pax_global_header00006660000000000000000000000064133677736050014533gustar00rootroot0000000000000052 comment=ed8c47124c1203bb5b69282816085f74977f40ed plugins-1.5/000077500000000000000000000000001336777360500130615ustar00rootroot00000000000000plugins-1.5/.gitignore000066400000000000000000000001261336777360500150500ustar00rootroot00000000000000*.pro.user* *.sw? # generated files .obj .qmake.* config.log Makefile .moc .rcc *.so plugins-1.5/README000066400000000000000000000002151336777360500137370ustar00rootroot00000000000000All available Psi+ plugins. generic - plugins for all platforms unix - plugins for unix-based systems dev - plugins in developemnt/unstable plugins-1.5/deprecated/000077500000000000000000000000001336777360500151615ustar00rootroot00000000000000plugins-1.5/deprecated/captchaformsplugin/000077500000000000000000000000001336777360500210525ustar00rootroot00000000000000plugins-1.5/deprecated/captchaformsplugin/CMakeLists.txt000066400000000000000000000034361336777360500236200ustar00rootroot00000000000000set( PLUGIN captchaformsplugin ) cmake_minimum_required(VERSION 3.1.0) set( CMAKE_AUTOMOC TRUE ) IF( NOT WIN32 ) set( LIB_SUFFIX "" CACHE STRING "Define suffix of directory name (32/64)" ) set( PLUGINS_PATH "lib${LIB_SUFFIX}/psi-plus/plugins" CACHE STRING "Install suffix for plugins" ) ELSE() set( PLUGINS_PATH "psi-plus/plugins" CACHE STRING "Install suffix for plugins" ) ENDIF() add_definitions( -DQT_PLUGIN ) set( _HDRS captchadialog.h loader.h ) set( _SRCS ${PLUGIN}.cpp captchadialog.cpp loader.cpp ) set( _UIS captchadialog.ui options.ui ) set( _RSCS resources.qrc ) include_directories( ${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ../../include . ) IF( USE_QT5 ) find_package( Qt5Widgets REQUIRED ) find_package( Qt5Xml REQUIRED ) find_package( Qt5Network REQUIRED ) set(QT_DEPLIBS Qt5::Widgets Qt5::Xml Qt5::Network ) qt5_wrap_ui(UIS ${_UIS}) qt5_add_resources(RSCS ${_RSCS}) ELSE() find_package( Qt4 REQUIRED ) include( ${QT_USE_FILE} ) include_directories( ${QT_QTCORE_INCLUDE_DIR} ${QT_QTGUI_INCLUDE_DIR} ${QT_QTXML_INCLUDE_DIR} ${QT_QTNETWORK_INCLUDE_DIR} ) set(QT_DEPLIBS ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY} ${QT_QTXML_LIBRARY} ${QT_QTNETWORK_LIBRARY} ) QT4_WRAP_UI(UIS ${_UIS}) QT4_ADD_RESOURCES(RSCS ${_RSCS}) ENDIF() add_library( ${PLUGIN} MODULE ${_SRCS} ${UIS} ${RSCS} ${TRS} ${MOCS} ) target_link_libraries( ${PLUGIN} ${QT_DEPLIBS} ) if( UNIX AND NOT( APPLE OR CYGWIN ) ) install( TARGETS ${PLUGIN} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} ) endif() if( WIN32 ) install( TARGETS ${PLUGIN} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} ) endif() plugins-1.5/deprecated/captchaformsplugin/captcha.png000066400000000000000000000013531336777360500231650ustar00rootroot00000000000000PNG  IHDRh6 pHYs.#.#x?vIDATx%[(arAl+ܸtX.%Z$7N%CZ͒ 攭5ٖc9,2em{y#bA(z{{h5Av}}mX^^^NOOI..^W|||ݑD[zp<77ۛ422rtt|uuEx<333VbiiGgggWTT0j~~~ccbwww`` 77711$??xx8##>==]Pd2F iiirl6󻷷WZZ ¼<&CX>??C7RASSij wvvV"S!l6trr2[ZZ't?e GnF(''guut$$$TIn͍`SSS"s[[[jj*c(..D"gggb_IRTqeed***Cb"Ą`_lj5,v: "o||JYT)~~~apq_Ђ@`!.yxnkkp\OvT=M)'Ve-___P$BAS/tIENDB`plugins-1.5/deprecated/captchaformsplugin/captchadialog.cpp000066400000000000000000000045601336777360500243460ustar00rootroot00000000000000/* * captchadialog.cpp - plugin * Copyright (C) 2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include #include "captchadialog.h" CaptchaDialog::CaptchaDialog(const QString& id, QWidget *p) : QDialog(p) , id_(id) { setAttribute(Qt::WA_DeleteOnClose); ui_.setupUi(this); toggleTEVisible(false); connect(ui_.buttonBox, SIGNAL(accepted()), SLOT(okPressed())); connect(ui_.buttonBox, SIGNAL(rejected()), SLOT(cancelPressed())); connect(ui_.cb_message, SIGNAL(toggled(bool)), SLOT(toggleTEVisible(bool))); ui_.le_answer->installEventFilter(this); } void CaptchaDialog::setQuestion(const QString &quest) { ui_.lb_question->setText(quest); adjustSize(); } void CaptchaDialog::toggleTEVisible(bool b) { ui_.textEdit->setVisible(b); adjustSize(); } void CaptchaDialog::setPixmap(const QPixmap &pix) { ui_.lb_image->setText(""); ui_.lb_image->setFixedSize(pix.size()); ui_.lb_image->setPixmap(pix); adjustSize(); } void CaptchaDialog::setText(const QString &text) { ui_.lb_image->setText(text); adjustSize(); } void CaptchaDialog::setBody(const QString &body) { ui_.textEdit->setPlainText(body); } void CaptchaDialog::okPressed() { QString text = ui_.le_answer->text(); if(text.isEmpty()) emit cancel(id_); else emit ok(id_, text); close(); } void CaptchaDialog::cancelPressed() { emit cancel(id_); close(); } bool CaptchaDialog::eventFilter(QObject *o, QEvent *e) { if(o == ui_.le_answer && e->type() == QEvent::KeyPress) { QKeyEvent *ke = static_cast(e); if(ke->key() == Qt::Key_Escape) { cancelPressed(); return true; } else if(ke->key() == Qt::Key_Enter) { okPressed(); return true; } } return QDialog::eventFilter(o,e); } plugins-1.5/deprecated/captchaformsplugin/captchadialog.h000066400000000000000000000026411336777360500240110ustar00rootroot00000000000000/* * captchadialog.h - plugin * Copyright (C) 2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef CAPTCHADIALOG_H #define CAPTCHADIALOG_H #include "ui_captchadialog.h" class CaptchaDialog : public QDialog { Q_OBJECT public: CaptchaDialog(const QString& id, QWidget *p = 0); void setPixmap(const QPixmap &pix); void setQuestion(const QString &quest); void setBody(const QString &body); void setText(const QString& text); private slots: void okPressed(); void cancelPressed(); void toggleTEVisible(bool); protected: bool eventFilter(QObject *o, QEvent *e); signals: void ok(const QString&, const QString&); void cancel(const QString&); private: Ui::CaptchaDialog ui_; QString id_; }; #endif // CAPTCHADIALOG_H plugins-1.5/deprecated/captchaformsplugin/captchadialog.ui000066400000000000000000000066271336777360500242070ustar00rootroot00000000000000 CaptchaDialog 0 0 274 361 CAPTCHA Qt::Horizontal 0 0 0 0 Loading data... Qt::Horizontal 0 0 Qt::Horizontal 40 20 Original message true Qt::Vertical 0 0 Qt::Horizontal 0 0 QDialogButtonBox::Cancel|QDialogButtonBox::Ok plugins-1.5/deprecated/captchaformsplugin/captchaformsplugin.cpp000066400000000000000000000322621336777360500254540ustar00rootroot00000000000000/* * captchaformsplugin.cpp - plugin * Copyright (C) 2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include #include "captchadialog.h" #include "loader.h" #include "ui_options.h" #include "psiplugin.h" #include "optionaccessor.h" #include "optionaccessinghost.h" #include "plugininfoprovider.h" #include "eventcreatinghost.h" #include "eventcreator.h" #include "stanzafilter.h" #include "stanzasender.h" #include "stanzasendinghost.h" #include "accountinfoaccessinghost.h" #include "accountinfoaccessor.h" #include "applicationinfoaccessinghost.h" #include "applicationinfoaccessor.h" #define constVersion "0.1.1" #define constProxyHost "host" #define constProxyPort "port" #define constProxyUser "user" #define constProxyPass "pass" #define constAutopopup "autopopup" #define constUseProxy "useproxy" static const QStringList methods = QStringList() << "qa" << "ocr" << "picture_q" << "picture_recog"; class CaptchaFormsPlugin : public QObject, public PsiPlugin, public OptionAccessor, public PluginInfoProvider, public EventCreator, public StanzaFilter, public StanzaSender, public AccountInfoAccessor, public ApplicationInfoAccessor { Q_OBJECT #ifdef HAVE_QT5 Q_PLUGIN_METADATA(IID "com.psi-plus.CaptchaFormsPlugin") #endif Q_INTERFACES(PsiPlugin OptionAccessor PluginInfoProvider EventCreator StanzaFilter StanzaSender AccountInfoAccessor ApplicationInfoAccessor) public: CaptchaFormsPlugin(); virtual QString name() const; virtual QString shortName() const; virtual QString version() const; virtual QWidget* options(); virtual bool enable(); virtual bool disable(); virtual void optionChanged(const QString&){}; virtual void applyOptions(); virtual void restoreOptions(); virtual void setOptionAccessingHost(OptionAccessingHost* host); virtual void setEventCreatingHost(EventCreatingHost* host); virtual bool incomingStanza(int account, const QDomElement& xml); virtual bool outgoingStanza(int account, QDomElement& xml); virtual void setStanzaSendingHost(StanzaSendingHost *host); virtual void setAccountInfoAccessingHost(AccountInfoAccessingHost* host); virtual void setApplicationInfoAccessingHost(ApplicationInfoAccessingHost* host); virtual QString pluginInfo(); virtual QPixmap icon() const; private: OptionAccessingHost *psiOptions; EventCreatingHost *psiEvent; StanzaSendingHost *stanzaSender; AccountInfoAccessingHost* accInfo; ApplicationInfoAccessingHost* appInfo; bool enabled; int id; bool autopopup, useProxy; QList< QHash > challenges_; QHash< QString, QPointer > dialogs_; Ui::Options ui_; bool isValidChallenge(const QDomElement& xml, QHash& dataFields) const; int findChalleng(const QString& field, const QString& value); private slots: void eventActivated(const QString&); void submitChallenge(const QString&, const QString&); void cancelChallenge(const QString&); void loaderData(const QString& id, const QByteArray& data); void loaderError(const QString& id); }; #ifndef HAVE_QT5 Q_EXPORT_PLUGIN(CaptchaFormsPlugin); #endif CaptchaFormsPlugin::CaptchaFormsPlugin() : psiOptions(0) , psiEvent(0) , stanzaSender(0) , accInfo(0) , appInfo(0) , enabled(false) , id(111) , autopopup(true) , useProxy(false) { } QString CaptchaFormsPlugin::name() const { return "Captcha Forms Plugin"; } QString CaptchaFormsPlugin::shortName() const { return "captcha"; } QString CaptchaFormsPlugin::version() const { return constVersion; } bool CaptchaFormsPlugin::enable() { if(psiOptions) { enabled = true; id = 111; useProxy = psiOptions->getPluginOption(constUseProxy, QVariant(useProxy)).toBool(); autopopup = psiOptions->getPluginOption(constAutopopup, QVariant(autopopup)).toBool(); if(!useProxy) appInfo->getProxyFor(name()); //register proxy } return enabled; } bool CaptchaFormsPlugin::disable() { enabled = false; return true; } QWidget* CaptchaFormsPlugin::options() { if (!enabled) { return 0; } QWidget *options = new QWidget(); ui_.setupUi(options); restoreOptions(); return options; } void CaptchaFormsPlugin::applyOptions() { useProxy = ui_.cb_use_proxy->isChecked(); psiOptions->setPluginOption(constUseProxy, QVariant(useProxy)); autopopup = ui_.cb_autopopup->isChecked(); psiOptions->setPluginOption(constAutopopup, QVariant(autopopup)); if(!useProxy) appInfo->getProxyFor(name()); //register proxy } void CaptchaFormsPlugin::restoreOptions() { ui_.cb_autopopup->setChecked(autopopup); ui_.cb_use_proxy->setChecked(useProxy); } void CaptchaFormsPlugin::setOptionAccessingHost(OptionAccessingHost *host) { psiOptions = host; } void CaptchaFormsPlugin::setEventCreatingHost(EventCreatingHost *host) { psiEvent = host; } void CaptchaFormsPlugin::setAccountInfoAccessingHost(AccountInfoAccessingHost *host) { accInfo = host; } void CaptchaFormsPlugin::setApplicationInfoAccessingHost(ApplicationInfoAccessingHost *host) { appInfo = host; } void CaptchaFormsPlugin::setStanzaSendingHost(StanzaSendingHost *host) { stanzaSender = host; } bool CaptchaFormsPlugin::incomingStanza(int account, const QDomElement &xml) { if(enabled) { QHash dataFields; if(!isValidChallenge(xml, dataFields) ) return false; else { dataFields["id"] = QString::number(id++); dataFields["account"] = QString::number(account); challenges_.push_back(dataFields); if(autopopup) eventActivated(dataFields.value("sender")); else psiEvent->createNewEvent(account, dataFields.value("sender"), tr("Captcha Plugin: CAPTCHA from %1") .arg(dataFields.value("sender")), this, SLOT(eventActivated(QString))); return true; } } return false; } bool CaptchaFormsPlugin::outgoingStanza(int /*account*/, QDomElement& /*xml*/) { return false; } void CaptchaFormsPlugin::eventActivated(const QString& from) { int index = findChalleng("sender", from); if(index == -1) return; QHash dataFields = challenges_.at(index); QString id = dataFields.value("id"); QPointer cd = new CaptchaDialog(id); cd->setBody(dataFields.value("body")); cd->setQuestion(dataFields.value("label")); connect(cd, SIGNAL(ok(QString, QString)), this, SLOT(submitChallenge(QString, QString))); connect(cd, SIGNAL(cancel(QString)), this, SLOT(cancelChallenge(QString))); dialogs_[id] = cd; if(dataFields.contains("data")) { QByteArray ba; ba.append(dataFields.value("data")); QPixmap pix = QPixmap::fromImage(QImage::fromData(QByteArray::fromBase64(ba))); cd->setPixmap(pix); } else { Loader *ld = new Loader(id, this); if(useProxy) { int acc = dataFields.value("account").toInt(); QString host_ = accInfo->proxyHost(acc); if(!host_.isEmpty()) { ld->setProxy(host_, accInfo->proxyPort(acc), accInfo->proxyUser(acc), accInfo->proxyPassword(acc)); } } else { Proxy p = appInfo->getProxyFor(name()); ld->setProxy(p.host, p.port, p.user, p.pass); } QString url = dataFields.value("uri"); if(url.isEmpty()) { QString str = dataFields.value("body"); QRegExp re(".*(http://[^\"]+).*"); if(re.indexIn(str) != -1) url = re.cap(1) + "/image"; } ld->start(url); connect(ld, SIGNAL(data(QString,QByteArray)), SLOT(loaderData(QString, QByteArray))); connect(ld, SIGNAL(error(QString)), SLOT(loaderError(QString))); } cd->show(); } void CaptchaFormsPlugin::loaderError(const QString& id) { if(!dialogs_.contains(id)) return; QPointer cd = dialogs_.value(id); if(cd) { cd->setText(tr("Error! Image can not be loaded.")); } else dialogs_.remove(id); } void CaptchaFormsPlugin::loaderData(const QString& id, const QByteArray& data) { if(!dialogs_.contains(id)) return; QPointer cd = dialogs_.value(id); if(cd) { cd->setPixmap(QPixmap::fromImage(QImage::fromData(data))); } else dialogs_.remove(id); } int CaptchaFormsPlugin::findChalleng(const QString& field, const QString& value) { int index = -1; for(int i = 0; i < challenges_.size(); i++) { QHash dataFields = challenges_.at(i); if(dataFields.contains(field) && dataFields.value(field) == value) { index = i; break; } } return index; } void CaptchaFormsPlugin::submitChallenge(const QString& id, const QString& text) { int index = findChalleng("id", id); if(index == -1) return; QHash dataFields = challenges_.at(index); QString mes = QString("" "" "urn:xmpp:captcha" "%4" "%5" "%7" "") .arg(stanzaSender->escape(dataFields.value("to")), stanzaSender->escape(dataFields.value("sender")), stanzaSender->escape(dataFields.value("id"))) .arg(stanzaSender->escape(dataFields.value("from")), stanzaSender->escape(dataFields.value("challenge"))) .arg(stanzaSender->escape(dataFields.value("method")), text); stanzaSender->sendStanza(dataFields.value("account").toInt(), mes); challenges_.removeAt(index); } void CaptchaFormsPlugin::cancelChallenge(const QString& id) { int index = findChalleng("id", id); if(index == -1) return; QHash dataFields = challenges_.at(index); QString mes = QString("" "" "") //.arg(dataFields.value("to")) .arg(stanzaSender->escape(dataFields.value("sender"))) .arg(stanzaSender->escape(dataFields.value("challenge"))); stanzaSender->sendStanza(dataFields.value("account").toInt(), mes); challenges_.removeAt(index); } bool CaptchaFormsPlugin::isValidChallenge(const QDomElement& stanza, QHash& dataFields) const { if(stanza.tagName() != "message") return false; QDomElement captcha = stanza.firstChildElement("captcha"); if(captcha.attribute("xmlns") != "urn:xmpp:captcha") return false; bool find = false; QDomElement formElem = captcha.firstChildElement("x"); while (!formElem.isNull() ) { if(formElem.attribute("xmlns") == "jabber:x:data") { find = true; break; } formElem = formElem.nextSiblingElement("x"); } if(!find) return false; dataFields["sender"] = stanza.attribute("from"); dataFields["body"] = stanza.firstChildElement("body").text(); dataFields["to"] = stanza.attribute("to"); find = false; QString id = stanza.attribute("id"); QDomNode field = formElem.firstChild(); while(!field.isNull()) { QDomElement tmp = field.toElement(); if(tmp.tagName() != "field") field = field.nextSibling(); QString var = tmp.attribute("var"); if(var == "FORM_TYPE") { if(tmp.firstChildElement("value").text() == "urn:xmpp:captcha") { find = true; } } else if(var == "challenge") { if(tmp.firstChildElement("value").text() == id) { dataFields["challenge"] = id; // id запроса } } else if(var == "from") { QString from = tmp.firstChildElement("value").text(); if(!from.isEmpty()) { dataFields["from"] = from; } } else if(tmp.attribute("type") != "hidden") { if(!var.isEmpty() && methods.contains(var)) { dataFields["label"] = tmp.attribute("label"); //вопрос dataFields["method"] = var; // метод QDomNodeList uriList = tmp.elementsByTagName("uri"); for(int i = 0; i < uriList.size(); i++) { QDomElement uriElem = uriList.at(i).toElement(); QString link = uriElem.text(); if(uriElem.attribute("type").left(5) == "image" && link.left(4) == "http") { dataFields["uri"] = link; // ссылка на контент в интернете dataFields["uri_type"] = uriElem.attribute("type"); // тип изображения break; } } } } field = field.nextSibling(); } QDomElement data = stanza.firstChildElement("data"); if(!data.isNull()) { dataFields["data"] = data.text(); } QStringList f = dataFields.keys(); if( !find || !f.contains("challenge") || !f.contains("from") ) return false; return true; } QString CaptchaFormsPlugin::pluginInfo() { return tr("Author: ") + "Dealer_WeARE\n" + tr("Email: ") + "wadealer@gmail.com\n\n" + trUtf8("This plugin is designed to pass of captcha directly from the Psi+."); } QPixmap CaptchaFormsPlugin::icon() const { return QPixmap(":/icons/captcha.png"); } #include "captchaformsplugin.moc" plugins-1.5/deprecated/captchaformsplugin/captchaformsplugin.pro000066400000000000000000000005051336777360500254650ustar00rootroot00000000000000CONFIG += release isEmpty(PSISDK) { include(../../psiplugin.pri) } else { include($$PSISDK/plugins/psiplugin.pri) } SOURCES += captchaformsplugin.cpp \ captchadialog.cpp \ loader.cpp FORMS += captchadialog.ui \ options.ui HEADERS += captchadialog.h \ loader.h RESOURCES += resources.qrc QT += network plugins-1.5/deprecated/captchaformsplugin/changelog.txt000066400000000000000000000037251336777360500235510ustar00rootroot000000000000002013-08-13 v0.1.1 - taurus + Иконка плагина 2011-11-01 v0.1.0 * настройки прокси перенесены в основные настройки приложения + теперь в поле ввода каптчи обрабатываются нажатия клавиш escape и enter 2010-12-17 v0.0.8 * небольшие исправления 2010-09-18 v0.0.7 * исправлена работа опции "настройки прокси из аккаунта" если прокси-сервер не используется 2010-09-11 v0.0.6 * обновлена ссылка на wiki ( http://psi-plus.com/wiki/plugins#captcha_forms_plugin ) 2010-08-02 v0.0.5 * обновлена информация о плагине 2010-07-23 v0.0.4 + добавлена возможность использовать настройки прокси-сервера из настроек аккаунта 2010-07-22 v0.0.3 + добавлена возможность включить автооткрытие диалога ввода капчи + добавлена экспериментальная возможность при необходимости грузить контент из интернета (нужны тесты) + добавлены настройки прокси-сервера + добавлена ссылка на вики 2010-07-21 v0.0.2 * немного переработан диалог ввода капчи 2010-07-21 v0.0.1 ! initial version Плагин предназначен для прохождения каптчи непосредственно из Psi+ В данный момент функционал очень ограничен. Работает только в случае, если картинка посылается непосредственно в теле сообщения (загрузка контента из интернета пока не работает) plugins-1.5/deprecated/captchaformsplugin/loader.cpp000066400000000000000000000032021336777360500230210ustar00rootroot00000000000000/* * loader.cpp - plugin * Copyright (C) 2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "loader.h" #include #include Loader::Loader(const QString& id, QObject *p) : QObject(p) , id_(id) { manager_ = new QNetworkAccessManager(this); } Loader::~Loader() { } void Loader::setProxy(const QString& host, int port, const QString& user, const QString& pass) { if(host.isEmpty()) return; QNetworkProxy proxy(QNetworkProxy::HttpCachingProxy,host,port,user,pass); manager_->setProxy(proxy); } void Loader::start(const QString& url) { manager_->get(QNetworkRequest(QUrl(url))); connect(manager_,SIGNAL(finished(QNetworkReply*)), SLOT(onRequestFinish(QNetworkReply*))); } void Loader::onRequestFinish(QNetworkReply *reply) { if(reply->error() == QNetworkReply::NoError) { QByteArray ba = reply->readAll(); emit data(id_, ba); } else emit error(id_); reply->deleteLater(); deleteLater(); } plugins-1.5/deprecated/captchaformsplugin/loader.h000066400000000000000000000025121336777360500224710ustar00rootroot00000000000000/* * loader.h - plugin * Copyright (C) 2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef LOADER_H #define LOADER_H #include class QNetworkAccessManager; class Loader : public QObject { Q_OBJECT public: Loader(const QString& id, QObject *p); ~Loader(); void start(const QString& url); void setProxy(const QString& host, int port, const QString& user = QString(), const QString& pass = QString()); private slots: void onRequestFinish(QNetworkReply*); signals: void error(const QString&); void data(const QString&, const QByteArray&); private: QNetworkAccessManager* manager_; QString id_; }; #endif // LOADER_H plugins-1.5/deprecated/captchaformsplugin/options.ui000066400000000000000000000035201336777360500231040ustar00rootroot00000000000000 Options 0 0 437 167 Options Auto-popup Captcha dialog Use proxy settings from account Qt::Vertical 0 0 Qt::Horizontal 0 0 <a href="http://psi-plus.com/wiki/plugins#captcha_forms_plugin">Wiki (Online)</a> true plugins-1.5/deprecated/captchaformsplugin/resources.qrc000066400000000000000000000001371336777360500235740ustar00rootroot00000000000000 captcha.png plugins-1.5/deprecated/gmailserviceplugin/000077500000000000000000000000001336777360500210525ustar00rootroot00000000000000plugins-1.5/deprecated/gmailserviceplugin/CMakeLists.txt000066400000000000000000000034011336777360500236100ustar00rootroot00000000000000set( PLUGIN gmailserviceplugin ) cmake_minimum_required(VERSION 3.1.0) set( CMAKE_AUTOMOC TRUE ) IF( NOT WIN32 ) set( LIB_SUFFIX "" CACHE STRING "Define suffix of directory name (32/64)" ) set( PLUGINS_PATH "lib${LIB_SUFFIX}/psi-plus/plugins" CACHE STRING "Install suffix for plugins" ) ELSE() set( PLUGINS_PATH "psi-plus/plugins" CACHE STRING "Install suffix for plugins" ) ENDIF() add_definitions( -DQT_PLUGIN ) include_directories( ${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ../../include . ) set( _HDRS ${PLUGIN}.h accountsettings.h common.h actionslist.h viewmaildlg.h ) set( _SRCS ${PLUGIN}.cpp accountsettings.cpp common.cpp actionslist.cpp viewmaildlg.cpp ) set( _UIS options.ui viewmaildlg.ui ) set( _RSCS ${PLUGIN}.qrc ) IF( USE_QT5 ) find_package( Qt5Widgets REQUIRED ) find_package( Qt5Xml REQUIRED ) set(QT_DEPLIBS Qt5::Widgets Qt5::Xml ) qt5_wrap_ui(UIS ${_UIS}) qt5_add_resources(RSCS ${_RSCS}) ELSE() find_package( Qt4 REQUIRED ) include( ${QT_USE_FILE} ) include_directories( ${QT_QTCORE_INCLUDE_DIR} ${QT_QTGUI_INCLUDE_DIR} ${QT_QTXML_INCLUDE_DIR} ) set(QT_DEPLIBS ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY} ${QT_QTXML_LIBRARY} ) QT4_WRAP_UI(UIS ${_UIS}) QT4_ADD_RESOURCES(RSCS ${_RSCS}) ENDIF() add_library( ${PLUGIN} MODULE ${_SRCS} ${UIS} ${RSCS} ${TRS} ${MOCS} ) target_link_libraries( ${PLUGIN} ${QT_DEPLIBS} ) if( UNIX AND NOT( APPLE OR CYGWIN ) ) install( TARGETS ${PLUGIN} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} ) endif() if( WIN32 ) install( TARGETS ${PLUGIN} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} ) endif() plugins-1.5/deprecated/gmailserviceplugin/accountsettings.cpp000066400000000000000000000044461336777360500250030ustar00rootroot00000000000000/* * accountsettings.cpp - plugin * Copyright (C) 2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "accountsettings.h" static const QString splitString = "&split&"; AccountSettings::AccountSettings(int acc, QString j) : account(acc) , jid(j) , fullJid(j) , isMailEnabled(false) , isMailSupported(false) , isArchivingEnabled(false) , isSuggestionsEnabled(false) , notifyAllUnread(false) , lastMailTime("") , lastMailTid("") , isSharedStatusEnabled(false) , isSharedStatusSupported(false) , isAttributesSupported(false) , isAttributesEnabled(true) , status("offline") , message("") , listMax(3) , listContentsMax(5) , statusMax(512) , isNoSaveSupported(false) , isNoSaveEnbaled(false) { } void AccountSettings::fromString(const QString& settings) { QStringList list = settings.split(splitString); if(!list.isEmpty()) jid = list.takeFirst(); if(!list.isEmpty()) lastMailTime = list.takeFirst(); if(!list.isEmpty()) lastMailTid = list.takeFirst(); if(!list.isEmpty()) notifyAllUnread = (list.takeFirst() == "true"); if(!list.isEmpty()) isSharedStatusEnabled = (list.takeFirst() == "true"); if(!list.isEmpty()) isNoSaveEnbaled = (list.takeFirst() == "true"); if(!list.isEmpty()) isAttributesEnabled = (list.takeFirst() == "true"); } QString AccountSettings::toString() const { QStringList list; list << jid << lastMailTime << lastMailTid << (notifyAllUnread ? "true" : "false") << (isSharedStatusEnabled ? "true" : "false") << (isNoSaveEnbaled ? "true" : "false") << (isAttributesEnabled ? "true" : "false"); return list.join(splitString); } plugins-1.5/deprecated/gmailserviceplugin/accountsettings.h000066400000000000000000000036731336777360500244510ustar00rootroot00000000000000/* * accountsettings.cpp - plugin * Copyright (C) 2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef ACCOUNTSETTINGS_H #define ACCOUNTSETTINGS_H #include #include #include struct Attributes { // int mc; // int emc; // int w; // bool rejected; QString t; // bool autosub; // QString alias_for; // QCString inv; }; class AccountSettings { public: AccountSettings(int acc = -1, QString j = QString()); ~AccountSettings() {}; void fromString(const QString& settings); QString toString() const; int account; QString jid; QString fullJid; bool isMailEnabled; bool isMailSupported; bool isArchivingEnabled; bool isSuggestionsEnabled; bool notifyAllUnread; QString lastMailTime; QString lastMailTid; bool isSharedStatusEnabled; bool isSharedStatusSupported; bool isAttributesSupported; bool isAttributesEnabled; QString status; QString message; QMap sharedStatuses; // < staus, list of status messages > int listMax; int listContentsMax; int statusMax; bool isNoSaveSupported; bool isNoSaveEnbaled; QMap noSaveList; // < jid, is no-save enabled > QMap attributes; //jid, Attributes }; Q_DECLARE_METATYPE(AccountSettings*) #endif // ACCOUNTSETTINGS_H plugins-1.5/deprecated/gmailserviceplugin/actionslist.cpp000066400000000000000000000043021336777360500241110ustar00rootroot00000000000000/* * actionslist.cpp - plugin * Copyright (C) 2010-2011 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "actionslist.h" ActionsList::ActionsList(QObject *p) : QObject(p) { } ActionsList::~ActionsList() { list_.clear(); } QAction* ActionsList::newAction(QObject *p, int account, const QString &contact, QIcon ico) { QAction* act = new QAction(ico, tr(" Enable Off the Record Chat.\n" "When checked, the server will not\n" "save the history for this contact."), p); AList l = list_.value(account); act->setProperty("account", account); act->setProperty("jid", contact); act->setVisible(false); act->setCheckable(true); l.push_back(QPointer(act)); list_.insert(account, l); connect(act, SIGNAL(triggered(bool)), SLOT(actionActivated(bool))); return act; } void ActionsList::updateActionsVisibility(int account, bool isVisible) { if(!list_.contains(account)) return; foreach(QPointer act, list_.value(account)) { if(act) { act->setVisible(isVisible); } } } void ActionsList::updateAction(int account, const QString &jid, bool isChecked) { foreach(QPointer act, list_.value(account)) { if(!act) continue; if(act->property("jid").toString() == jid) { act->setChecked(isChecked); break; } } } void ActionsList::actionActivated(bool val) { QAction* act = qobject_cast(sender()); if(act) { int account = act->property("account").toInt(); QString jid = act->property("jid").toString(); emit changeNoSaveState(account, jid, val); } } plugins-1.5/deprecated/gmailserviceplugin/actionslist.h000066400000000000000000000026171336777360500235650ustar00rootroot00000000000000/* * actionslist.h - plugin * Copyright (C) 2010-2011 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef ACTIONSLIST_H #define ACTIONSLIST_H #include #include class ActionsList : public QObject { Q_OBJECT public: ActionsList(QObject* p); ~ActionsList(); QAction* newAction(QObject* p, int account, const QString& contact, QIcon ico); void updateActionsVisibility(int account, bool isVisible); void updateAction(int account, const QString& jid, bool isChecked); signals: void changeNoSaveState(int account, QString jid, bool val); private slots: void actionActivated(bool val); private: typedef QList< QPointer > AList; QHash list_; }; #endif // ACTIONSLIST_H plugins-1.5/deprecated/gmailserviceplugin/changelog.txt000066400000000000000000000207571336777360500235550ustar00rootroot000000000000002013-08-13 v0.7.5 - taurus + Иконка плагина 2012-03-14 v0.7.4 + добавлена возможность задать приложение, которое будет запущено при получении почты 2012-02-20 v0.7.3 * исправления для нового попап-интерфейса 2011-12-16 v0.7.2 + добавлена возможность блокировки контактов с помощью Extended Contact Attributes (пункт в контекстном меню контакта) 2011-07-11 v0.7.1 * инвертировано колесико мыши + если последовательно пришло несколько уведомлений о почте, они все открываются одним кликом по событию + если окно просмотрщика неактивно, новое уведомление автоматически в него не добавляется * если есть пропущенные события, в заголовке просмотрщика добавляется символ "*" 2011-07-08 v0.7.0 + в заголовок просмотрщика писем добавлена информация о количестве писем и о номере текущего письма + в случае, если включен показ текста во всплывающих уведомлениях, будет показываться текст писем + если во время просмотра писем приходит новое уведомление, письма добавляются в просмотрщик автоматически + частично переработан интерфейс просмотрщика + добавлен переход между письмами с помощью колесика мыши * некоторые исправления 2011-04-26 v0.6.9 * попытка исправить падение приложения в случае, когда используются общие статусы 2011-03-13 v0.6.8 * испралено появление лишнего контакта в аккаунте по-умолчанию при получении уведомления о новой почте 2011-03-09 v0.6.7 + если пришло уведомление только об одном письме, то при клике на ссылку окно уведомления закрывается 2011-02-24 v0.6.6 + возвращена ссылка на сообщение 2011-02-22 v0.6.5 - из текста сообщения убрана ссылка на почту + добавлена кнопка "Открыть почтовый ящик" 2011-02-16 v0.6.4 + в окне просмотрщика добавлена информация об аккаунте, на который пришла почта * теперь при щелчке в трэе события открываются последовательно * исправлен показ почты для случая, когда выбрано показывать все непрочитанные сообщения * исправления для режима "Отключить запись чатов" * мелкие исправления 2011-02-09 v0.6.2 + теперь плагин показывает входящую почту в своем собственном стильном окошке ;) + при получении уведомления о новой почте показывается попап и играется звук 2011-02-03 v0.6.1 + плагин теперь использует настройки попапов из настроек приложения * исправлено неправильное определение аккаунта 2011-02-01 v0.6.0 * исправлено возможное падение приложения при изменении опции "Отключить запись чатов" * небольшие оптимизации кода 2011-01-22 v0.5.9 * исправлен поиск необходимого аккаунта при восстановлении и применении опций 2011-01-19 v0.5.8 * некоторые исправления 2010-12-20 v0.5.7 * плагин теперь более корректно определяет изменения статуса 2010-11-30 v0.5.6 * различные исправления для опций плагина и кнопок на панеле инструментов 2010-11-29 v0.5.5 - убран пункт меню из заголовка аккаунта + для включения\отключения Off the Record Chats теперь используется кнопка на панеле инструментов в окне чата * исправлена работа кнопки "Применить" 2010-11-26 v0.5.4 * плагин переименован в gmailserviceplugin 2010-11-25 v0.5.3 + добавлена поддержка Off the Record Chats (http://code.google.com/intl/ru/apis/talk/jep_extensions/otr.html) Для поддержки необходимо в настройках плагина включить опции "Message archiving" и "Enable Off the Record Chats" Выбор контактов, для которых сохранение истории на сервере выключено, осуществляется из контекстного меню аккаунта 2010-11-25 v0.5.2 * обновлена ссылка на wiki (http://psi-plus.com/wiki/plugins#gmail_service_plugin) 2010-11-24 v0.5.1 * несколько важных исправлений 2010-11-24 v0.5.0 * переписана большая часть кода плагина + добавлена поддержка Shared Status Messages (http://code.google.com/intl/ru/apis/talk/jep_extensions/shared_status.html) + добавлена поддержка User Settings (http://code.google.com/intl/ru/apis/talk/jep_extensions/usersettings.html) + добавлены уведомления об изменении Shared Status Messages и User Settings с помощью попапов 2010-09-11 v0.4.7 * обновлена ссылка на wiki (http://psi-plus.com/wiki/plugins#gmail_notification_plugin) 2010-08-25 v0.4.6 * совместимость с последней версией Psi+ 2010-05-17 zet v0.4.5 + поправлено полное название плагина (GMail Notification Plugin) 2010-05-17 Dealer_WeARE v0.4.4 + добавлена информация о плагине 2010-05-04 zet v0.4.3 * исправлена ссылка на wiki 2010-01-06 zet v0.4.2 + added changelog.txt 2010-01-05 v0.4.1 * fixed gmailnotify plugin Revision: 1566 Author: VampiRUS.666 Date: 7:49:42, 4 января 2010 г. Message: * updated gmailnotify plugin to v0.4.0 Revision: 1565 Author: VampiRUS.666 Date: 7:33:57, 4 января 2010 г. Message: * updated gmailnotify plugin to v0.3.9 Revision: 1034 Author: ivan.borzenkov Date: 0:45:09, 29 сентября 2009 г. Message: * patch gmailnotifyplugin for compatible whis const options Revision: 977 Author: VampiRUS.666 Date: 6:33:58, 7 сентября 2009 г. Message: + added option 'notification on/off' Revision: 851 Author: VampiRUS.666 Date: 8:27:45, 6 августа 2009 г. Message: * updated gmailnorifyplugin to v0.3.7 Revision: 648 Author: vladimir.shelukhin Date: 12:40:55, 6 июля 2009 г. Message: * updated gmailnotifyplugin to v0.3.6 Revision: 612 Author: vladimir.shelukhin Date: 16:52:47, 24 июня 2009 г. Message: * updated gmailnotifyplugin to v0.3.5 Revision: 592 Author: vladimir.shelukhin Date: 19:26:15, 20 июня 2009 г. Message: * updated gmailnotifyplugin Revision: 564 Author: ptitkov Date: 13:28:21, 14 июня 2009 г. Message: + added options for message Revision: 536 Author: givan101 Date: 16:35:38, 5 июня 2009 г. Message: * updated gmailnotify plugin to v0.3.1 by VampiRUS Revision: 532 Author: givan101 Date: 12:00:47, 5 июня 2009 г. Message: * updated gmailnotify plugin to v0.2.4 by VampiRUS Revision: 522 Author: ptitkov Date: 17:03:39, 2 июня 2009 г. Message: * fixed gmailnotify plugin by VampiRUS Revision: 518 Author: ptitkov Date: 10:48:07, 2 июня 2009 г. Message: + added gmailnotify plugin, thanks to VampiRUS plugins-1.5/deprecated/gmailserviceplugin/common.cpp000066400000000000000000000121451336777360500230510ustar00rootroot00000000000000/* * common.cpp - plugin * Copyright (C) 2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "common.h" void Utils::requestMail(AccountSettings *as, StanzaSendingHost *stanzaSender, AccountInfoAccessingHost *accInfo) { int acc = as->account; if(!checkAccount(acc, accInfo)) return; if(!as->isMailEnabled || !as->isMailSupported) return; QString time, tid; if (!as->notifyAllUnread) { time = as->lastMailTime; tid = as->lastMailTid; } if (!time.isEmpty()) { time = QString("newer-than-time='%1'").arg(time); } if (!tid.isEmpty()) { tid = QString("newer-than-tid='%1'").arg(tid); } QString id = stanzaSender->uniqueId(acc); QString reply = QString(""\ "") .arg(as->jid, time, tid, id); stanzaSender->sendStanza(acc, reply); } void Utils::requestSharedStatusesList(AccountSettings *as, StanzaSendingHost *stanzaSender, AccountInfoAccessingHost *accInfo) { int acc = as->account; if(!checkAccount(acc, accInfo)) return; if(!as->isSharedStatusEnabled || !as->isSharedStatusSupported) return; QString id = stanzaSender->uniqueId(acc); QString str = QString("" "") .arg(as->jid, id); stanzaSender->sendStanza(acc, str); } void Utils::requestExtendedContactAttributes(AccountSettings *as, StanzaSendingHost *stanzaSender, AccountInfoAccessingHost *accInfo) { int acc = as->account; if(!checkAccount(acc, accInfo)) return; if(!as->isAttributesEnabled || !as->isAttributesSupported) return; QString id = stanzaSender->uniqueId(acc); QString str = QString("" "") .arg(id); stanzaSender->sendStanza(acc, str); } void Utils::updateSharedStatus(AccountSettings *as, StanzaSendingHost *stanzaSender, AccountInfoAccessingHost *accInfo) { int acc = as->account; if(!checkAccount(acc, accInfo)) return; if(!as->isSharedStatusSupported || !as->isSharedStatusEnabled) return; QString id = stanzaSender->uniqueId(acc); QString str = QString("" "" "%3%4") .arg(as->jid, id) .arg(as->message, as->status.replace("online", "default")); foreach(QString status, as->sharedStatuses.keys()) { str += QString("").arg(QString(status).replace("online", "default")); foreach(QString message, as->sharedStatuses.value(status)) { str += QString("%1").arg(message); } str += ""; } str += ""; stanzaSender->sendStanza(acc, str); } void Utils::updateSettings(AccountSettings *as, StanzaSendingHost *stanzaSender, AccountInfoAccessingHost *accInfo) { int acc = as->account; if(!checkAccount(acc, accInfo)) return; QString reply = QString(""\ ""\ ""\ ""\ ""\ "") .arg(as->jid, stanzaSender->uniqueId(acc)) .arg(as->isMailEnabled ? "true" : "false") .arg(as->isArchivingEnabled ? "true" : "false") .arg(as->isSuggestionsEnabled ? "true" : "false"); stanzaSender->sendStanza(acc, reply); } void Utils::getUserSettings(AccountSettings *as, StanzaSendingHost *stanzaSender, AccountInfoAccessingHost *accInfo) { int acc = as->account; if(!checkAccount(acc, accInfo)) return; QString id = stanzaSender->uniqueId(acc); //id_.append(id); QString mes = QString("") .arg(as->jid).arg(id); stanzaSender->sendStanza(acc, mes); } void Utils::updateNoSaveState(AccountSettings *as, StanzaSendingHost *stanzaSender, AccountInfoAccessingHost *accInfo) { int acc = as->account; if(!checkAccount(acc, accInfo) || !as->isNoSaveSupported) return; QString id = stanzaSender->uniqueId(acc); QString mes = QString("" "") .arg(as->jid, id); stanzaSender->sendStanza(acc, mes); } bool Utils::checkAccount(int acc, AccountInfoAccessingHost *accInfo) { if(acc == -1) return false; if(accInfo->getStatus(acc) == "offline") return false; return true; } plugins-1.5/deprecated/gmailserviceplugin/common.h000066400000000000000000000037151336777360500225210ustar00rootroot00000000000000/* * common.h - plugin * Copyright (C) 2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef COMMON_H #define COMMON_H #include #if QT_VERSION > QT_VERSION_CHECK(5, 5, 0) #include #endif #include "accountsettings.h" #include "stanzasendinghost.h" #include "accountinfoaccessinghost.h" class Utils { public: static void requestMail(AccountSettings* as, StanzaSendingHost* stanzaSender, AccountInfoAccessingHost* accInfo); static void requestSharedStatusesList(AccountSettings* as, StanzaSendingHost* stanzaSender, AccountInfoAccessingHost* accInfo); static void updateSettings(AccountSettings* as, StanzaSendingHost* stanzaSender, AccountInfoAccessingHost* accInfo); static void updateSharedStatus(AccountSettings* as, StanzaSendingHost* stanzaSender, AccountInfoAccessingHost* accInfo); static void getUserSettings(AccountSettings* as, StanzaSendingHost* stanzaSender, AccountInfoAccessingHost* accInfo); static void updateNoSaveState(AccountSettings* as, StanzaSendingHost* stanzaSender, AccountInfoAccessingHost* accInfo); static void requestExtendedContactAttributes(AccountSettings* as, StanzaSendingHost* stanzaSender, AccountInfoAccessingHost* accInfo); static bool checkAccount(int account, AccountInfoAccessingHost* accInfo); }; #endif // COMMON_H plugins-1.5/deprecated/gmailserviceplugin/gmailnotify.png000066400000000000000000000030411336777360500241000ustar00rootroot00000000000000PNG  IHDRaiCCPICC ProfilexTkA6n"Zkx"IYhE6bk Ed3In6&*Ezd/JZE(ޫ(b-nL~7}ov r4 Ril|Bj A4%UN$As{z[V{wwҶ@G*q Y<ߡ)t9Nyx+=Y"|@5-MS%@H8qR>׋infObN~N>! ?F?aĆ=5`5_M'Tq. VJp8dasZHOLn}&wVQygE0  HPEaP@<14r?#{2u$jtbDA{6=Q<("qCA*Oy\V;噹sM^|vWGyz?W15s-_̗)UKuZ17ߟl;=..s7VgjHUO^gc)1&v!.K `m)m$``/]?[xF QT*d4o(/lșmSqens}nk~8X<R5 vz)Ӗ9R,bRPCRR%eKUbvؙn9BħJeRR~NցoEx pHYs  IDAT8SKhSA=wfk$&McE?PVA E-E(ݨ;n Υ UJ BP"Slhmji| MΛ3g̽t RB\1ځο9)t3ij[7W|ۥkVE˹Qo8d.hRZ4J_lt=kO4oOSf2> ojl}26uQ{B`24EvJŔlPfQJ_R!CjM+|FN" #include #include #include "gmailserviceplugin.h" #include "common.h" #ifndef HAVE_QT5 Q_EXPORT_PLUGIN(GmailNotifyPlugin); #endif GmailNotifyPlugin::GmailNotifyPlugin() : enabled(false) , optionsApplingInProgress_(false) , stanzaSender(0) , psiOptions(0) , accInfo(0) , popup(0) , accountController(0) , iconHost(0) , psiEvent(0) , sound_(0) , soundFile("sound/email.wav") , actions_(0) , popupId(0) { } QString GmailNotifyPlugin::name() const { return "GMail Service Plugin"; } QString GmailNotifyPlugin::shortName() const { return "gmailnotify"; } QString GmailNotifyPlugin::version() const { return PLUGIN_VERSION; } QWidget* GmailNotifyPlugin::options() { if (!enabled) return 0; options_ = new QWidget; ui_.setupUi(options_); restoreOptions(); ui_.tb_check->setIcon(iconHost->getIcon("psi/play")); ui_.tb_open->setIcon(iconHost->getIcon("psi/browse")); ui_.tb_open_prog->setIcon(iconHost->getIcon("psi/browse")); connect(ui_.tb_check, SIGNAL(clicked()), SLOT(checkSound())); connect(ui_.tb_open, SIGNAL(clicked()), SLOT(getSound())); connect(ui_.cb_accounts, SIGNAL(currentIndexChanged(int)), SLOT(updateOptions(int))); connect(ui_.tb_open_prog, SIGNAL(clicked()), SLOT(getProg())); return options_; } bool GmailNotifyPlugin::enable() { enabled = true; optionsApplingInProgress_ = false; id_.clear(); accounts.clear(); mailItems_.clear(); actions_ = new ActionsList(this); connect(actions_, SIGNAL(changeNoSaveState(int,QString,bool)), this, SLOT(changeNoSaveState(int,QString,bool))); QFile f(":/icons/gmailnotify.png"); if(f.open(QIODevice::ReadOnly)) iconHost->addIcon("gmailnotify/menu", f.readAll()); f.close(); f.setFileName(":/icons/nohistory.png"); if(f.open(QIODevice::ReadOnly)) iconHost->addIcon("gmailnotify/nohistory", f.readAll()); f.close(); soundFile = psiOptions->getPluginOption(OPTION_SOUND, soundFile).toString(); loadLists(); int interval = psiOptions->getPluginOption(OPTION_INTERVAL, QVariant(4000)).toInt()/1000; popupId = popup->registerOption(POPUP_OPTION, interval, "plugins.options."+shortName()+"."+OPTION_INTERVAL); program_ = psiOptions->getPluginOption(OPTION_PROG).toString(); //Update features bool end = false; int acc = 0; while(!end) { QString jid = accInfo->getJid(acc); if(jid == "-1") { end = true; continue; } QStringList l = jid.split("@"); QString domain = l.last().split("/").first(); QString id = stanzaSender->uniqueId(acc); id_.append(id); if(accInfo->getStatus(acc) != "offline") stanzaSender->sendStanza(acc, QString("") .arg(domain) .arg(id)); acc++; } return true; } bool GmailNotifyPlugin::disable() { qDeleteAll(accounts); accounts.clear(); delete actions_; actions_ = 0; delete mailViewer_; popup->unregisterOption(POPUP_OPTION); enabled = false; return true; } void GmailNotifyPlugin::applyOptions() { if (!options_) return; optionsApplingInProgress_ = true; soundFile = ui_.le_sound->text(); psiOptions->setPluginOption(OPTION_SOUND, soundFile); program_ = ui_.le_program->text(); psiOptions->setPluginOption(OPTION_PROG, program_); int index = ui_.cb_accounts->currentIndex(); if(accounts.size() <= index || index == -1) return; AccountSettings *as = findAccountSettings(ui_.cb_accounts->currentText()); if(!as) return; as->notifyAllUnread = !ui_.rb_new_messages->isChecked(); as->isMailEnabled = ui_.cb_mail->isChecked(); as->isArchivingEnabled = ui_.cb_archiving->isChecked(); as->isSuggestionsEnabled = ui_.cb_suggestions->isChecked(); as->isSharedStatusEnabled = ui_.cb_shared_statuses->isChecked(); as->isNoSaveEnbaled = ui_.cb_nosave->isChecked(); Utils::updateSettings(as, stanzaSender, accInfo); if(as->isMailEnabled) Utils::requestMail(as, stanzaSender, accInfo); if(as->isSharedStatusEnabled) Utils::requestSharedStatusesList(as, stanzaSender, accInfo); if(as->isNoSaveEnbaled && as->isArchivingEnabled) Utils::updateNoSaveState(as, stanzaSender, accInfo); updateActions(as); saveLists(); QTimer::singleShot(2000, this, SLOT(stopOptionsApply())); } void GmailNotifyPlugin::stopOptionsApply() { optionsApplingInProgress_ = false; } void GmailNotifyPlugin::saveLists() { QStringList l; foreach(AccountSettings *as, accounts) l.append(as->toString()); psiOptions->setPluginOption(OPTION_LISTS, QVariant(l)); } void GmailNotifyPlugin::loadLists() { QStringList l = psiOptions->getPluginOption(OPTION_LISTS, QVariant()).toStringList(); foreach(QString settings, l) { AccountSettings *as = new AccountSettings(); as->fromString(settings); accounts.append(as); } } void GmailNotifyPlugin::restoreOptions() { if (!options_ || optionsApplingInProgress_) return; ui_.lb_error->hide(); ui_.gb_settings->setEnabled(true); ui_.cb_mail->setVisible(true); ui_.cb_shared_statuses->setVisible(true); ui_.cb_nosave->setVisible(true); ui_.le_sound->setText(soundFile); ui_.le_program->setText(program_); ui_.cb_accounts->setEnabled(true); ui_.cb_accounts->clear(); if(!accounts.isEmpty()) { foreach(AccountSettings* as, accounts) { if(as->account != -1) ui_.cb_accounts->addItem(as->jid); } } if(!ui_.cb_accounts->count()) { ui_.cb_accounts->setEnabled(false); ui_.gb_mail_settings->setEnabled(false); ui_.gb_settings->setEnabled(false); ui_.lb_error->setVisible(true); } else { ui_.cb_accounts->setCurrentIndex(0); updateOptions(0); } } void GmailNotifyPlugin::updateOptions(int index) { if (!options_ || index >= accounts.size() || index < 0) return; AccountSettings *as = findAccountSettings(ui_.cb_accounts->currentText()); if(!as) return; ui_.cb_mail->setChecked(as->isMailEnabled); ui_.cb_mail->setVisible(as->isMailSupported); ui_.gb_mail_settings->setEnabled(ui_.cb_mail->isChecked()); ui_.rb_new_messages->setChecked(!as->notifyAllUnread); ui_.rb_all_messages->setChecked(as->notifyAllUnread); ui_.cb_archiving->setChecked(as->isArchivingEnabled); ui_.cb_suggestions->setChecked(as->isSuggestionsEnabled); ui_.cb_shared_statuses->setChecked(as->isSharedStatusEnabled); ui_.cb_shared_statuses->setVisible(as->isSharedStatusSupported); ui_.cb_nosave->setChecked(as->isNoSaveEnbaled); ui_.cb_nosave->setVisible(as->isNoSaveSupported); ui_.cb_nosave->setEnabled(ui_.cb_archiving->isChecked()); } bool GmailNotifyPlugin::incomingStanza(int account, const QDomElement& stanza) { if (enabled) { if (stanza.tagName() == "iq") { QDomElement query = stanza.firstChild().toElement(); if (!query.isNull()) { if(checkFeatures(account, stanza, query)) return true; if(checkEmail(account, stanza, query)) return true; if(checkSettings(account, stanza, query)) return true; if(checkSharedStatus(account, stanza, query)) return true; if(checkNoSave(account, stanza, query)) return true; if(checkAttributes(account, stanza, query)) return true; } } else if(stanza.tagName() == "message") { QDomElement x = stanza.firstChildElement("x"); if(!x.isNull() && x.attribute("xmlns") == "google:nosave") { QString jid = stanza.attribute("from").split("/").first(); bool val = (x.attribute("value") == "enabled"); AccountSettings *as = findAccountSettings(accInfo->getJid(account)); if(as && as->noSaveList.contains(jid) && as->noSaveList.value(jid) != val) { as->noSaveList.insert(jid, val); showPopup(tr("No-save state for contact %1 is changed").arg(jid)); return true; } } } } return false; } bool GmailNotifyPlugin::outgoingStanza(int account, QDomElement& stanza) { if(enabled && hasAccountSettings(account)) { if(stanza.tagName() == "presence") { AccountSettings* as = findAccountSettings(accInfo->getJid(account)); if(as && as->account == account && as->isSharedStatusEnabled && as->isSharedStatusSupported) { QString status = accInfo->getStatus(account); QString message = accInfo->getStatusMessage(account); if(message.length() > as->statusMax) message.chop(message.length() - as->statusMax); if(status == as->status && message == as->message) { return false; } as->message = message; as->status = status; qRegisterMetaType(); QMetaObject::invokeMethod(this, "updateSharedStatus", Qt::QueuedConnection, Q_ARG(AccountSettings*, as)); } } } return false; } bool GmailNotifyPlugin::checkFeatures(int account, const QDomElement &stanza, const QDomElement& query) { bool myReqyest = false; if (stanza.attribute("type") == "result" && query.tagName() == "query" && query.attribute("xmlns") == "http://jabber.org/protocol/disco#info") { if(id_.contains(stanza.attribute("id"))) { id_.removeAll(stanza.attribute("id")); myReqyest = true; } bool foundGoogleExt = false; const QString from = stanza.attribute("from").toLower(); if(from.contains("@")) { // нам нужен disco#info от сервера, а не от клиента. return false; } const QString jid = accInfo->getJid(account); QStringList tmpList = jid.split("@"); const QString domain = tmpList.last().split("/").first(); if(domain != from) { // нам нужен disco#info от нашего сервера return false; } QString fullJid = stanza.attribute("to"); for (QDomNode child = query.firstChild(); !child.isNull(); child = child.nextSibling()) { QDomElement feature = child.toElement(); if(feature.isNull() || feature.tagName() != "feature") continue; //If the server supports the Gmail extension if(feature.attribute("var") == "google:mail:notify" && feature.attribute("node").isEmpty()) { AccountSettings *as = create(account, jid); as->isMailSupported = true; //Utils::requestMail(as, stanzaSender, accInfo); foundGoogleExt = true; } else if(feature.attribute("var") == "google:setting" && feature.attribute("node").isEmpty()) { AccountSettings *as = create(account, jid); Utils::getUserSettings(as, stanzaSender, accInfo); foundGoogleExt = true; } else if(feature.attribute("var") == "google:shared-status" && feature.attribute("node").isEmpty()) { AccountSettings *as = create(account, jid); as->isSharedStatusSupported = true; as->status = accInfo->getStatus(account); as->message = accInfo->getStatusMessage(account); as->fullJid = fullJid; if(as->isSharedStatusEnabled) Utils::requestSharedStatusesList(as, stanzaSender, accInfo); foundGoogleExt = true; } else if(feature.attribute("var") == "google:nosave" && feature.attribute("node").isEmpty()) { AccountSettings *as = create(account, jid); as->isNoSaveSupported = true; updateActions(as); if(as->isNoSaveEnbaled) Utils::updateNoSaveState(as, stanzaSender, accInfo); foundGoogleExt = true; } else if(feature.attribute("var") == "google:roster" && feature.attribute("node").isEmpty()) { AccountSettings *as = create(account, jid); as->isAttributesSupported = true; if(as->isAttributesEnabled) Utils::requestExtendedContactAttributes(as, stanzaSender, accInfo); foundGoogleExt = true; } } if(foundGoogleExt) { optionsApplingInProgress_ = false; restoreOptions(); } } return myReqyest; } bool GmailNotifyPlugin::checkEmail(int account, const QDomElement &stanza, const QDomElement& query) { if (stanza.attribute("type") == "set" && query.tagName() == "new-mail" && query.attribute("xmlns") == "google:mail:notify") { //Server reports new mail //send success result QString from = stanza.attribute("to"); QString to = from.split("/").at(0); QString iqId = stanza.attribute("id"); QString reply = QString("").arg(from,to,iqId); stanzaSender->sendStanza(account, reply); AccountSettings *as = findAccountSettings(to.toLower()); if(!as || as->account != account) { return true; } //requests new mail Utils::requestMail(as, stanzaSender, accInfo); //block stanza processing return true; } else if(stanza.attribute("type") == "result" && query.tagName() == "mailbox" && query.attribute("xmlns") == "google:mail:notify") { //Email Query Response const QString jid = stanza.attribute("to").split("/").at(0); const QString server = stanza.attribute("from").toLower(); if(!server.isEmpty() && jid.toLower() != server) { return false; } const QString from = stanza.attribute("to"); AccountSettings *as = findAccountSettings(jid); if(!as || as->account != account) { return true; } as->lastMailTime = query.attribute("result-time"); QDomElement lastmail = query.firstChildElement("mail-thread-info"); if (!lastmail.isNull()) as->lastMailTid = lastmail.attribute("tid"); //save last check values saveLists(); incomingMail(account, query); return true; } return false; } bool GmailNotifyPlugin::checkSettings(int account, const QDomElement &stanza, const QDomElement& query) { bool foundSettings = false; if ( (stanza.attribute("type") == "result" || stanza.attribute("type") == "set") && query.tagName() == "usersetting" && query.attribute("xmlns") == "google:setting") { foundSettings = true; //id_.removeAll(stanza.attribute("id")); const QString jid = stanza.attribute("to").split("/").at(0); const QString server = stanza.attribute("from").toLower(); if(!server.isEmpty() && jid.toLower() != server) { return false; } AccountSettings *as = findAccountSettings(jid.toLower()); if(!as || as->account != account) { return true; } for (QDomNode child = query.firstChild(); !child.isNull(); child = child.nextSibling()) { QDomElement setting = child.toElement(); QString value = setting.attribute("value"); if(setting.isNull() || value.isEmpty()) continue; if(setting.tagName() == "autoacceptsuggestions") as->isSuggestionsEnabled = (value == "true"); else if(setting.tagName() == "mailnotifications") { as->isMailEnabled = (value == "true"); Utils::requestMail(as, stanzaSender, accInfo); } else if(setting.tagName() == "archivingenabled") { as->isArchivingEnabled = (value == "true"); updateActions(as); } } restoreOptions(); if(stanza.attribute("type") == "set") { showPopup(tr("Settings for an account %1 are changed").arg(jid)); const QString str = QString("").arg(accInfo->getJid(account), stanza.attribute("id")); stanzaSender->sendStanza(account, str); } } return foundSettings; } bool GmailNotifyPlugin::checkSharedStatus(int account, const QDomElement &stanza, const QDomElement &query) { bool found = false; if (query.tagName() == "query" && query.attribute("xmlns") == "google:shared-status") { found = true; const QString jid = stanza.attribute("to").split("/").at(0); const QString server = stanza.attribute("from").toLower(); if(!server.isEmpty() && jid.toLower() != server) { return false; } AccountSettings *as = findAccountSettings(jid); if(!as || as->account != account) { return true; } QString type = stanza.attribute("type"); if(type == "set") as->sharedStatuses.clear(); if(query.hasAttribute("status-max")) as->statusMax = query.attribute("status-max").toInt(); if(query.hasAttribute("status-list-contents-max")) as->listContentsMax = query.attribute("status-list-contents-max").toInt(); if(query.hasAttribute("status-list-max")) as->listMax = query.attribute("status-list-max").toInt(); if(type == "result" || type == "set") { for (QDomNode child = query.firstChild(); !child.isNull(); child = child.nextSibling()) { QDomElement settings = child.toElement(); if(settings.isNull()) continue; QString tagName = settings.tagName(); if(tagName == "status") as->message = settings.text(); else if(tagName == "show") as->status = settings.text().replace("default", "online"); else if(tagName == "status-list") { QStringList l; for (QDomNode child = settings.firstChild(); !child.isNull(); child = child.nextSibling()) { QDomElement st = child.toElement(); if(st.isNull() || st.tagName() != "status") continue; l.append(st.text()); } if(!l.isEmpty()) as->sharedStatuses.insert(settings.attribute("show").replace("default", "online"), l); } } } if(as->sharedStatuses.isEmpty()) as->sharedStatuses.insert(as->status, QStringList(as->message)); if(as->isSharedStatusEnabled) { //timer_->start(); accountController->setStatus(account, as->status, as->message); showPopup(tr("Shared Status for an account %1 is updated").arg(jid)); } if(type == "set") { const QString str = QString("").arg(accInfo->getJid(account), stanza.attribute("id")); stanzaSender->sendStanza(account, str); } } return found; } bool GmailNotifyPlugin::checkNoSave(int account, const QDomElement &stanza, const QDomElement &query) { bool found = false; if(query.tagName() == "query" && query.attribute("xmlns") == "google:nosave") { found = true; const QString jid = stanza.attribute("to").split("/").at(0); const QString server = stanza.attribute("from").toLower(); if(!server.isEmpty() && jid.toLower() != server) { return false; } AccountSettings *as = findAccountSettings(jid); if(!as || as->account != account) { return true; } const QString type = stanza.attribute("type"); for(QDomNode child = query.firstChild(); !child.isNull(); child = child.nextSibling()) { QDomElement noSave = child.toElement(); if(noSave.isNull() || noSave.tagName() != "item") continue; const QString item = noSave.attribute("jid"); bool state = (noSave.attribute("value") == "enabled"); bool changed; if(!as->noSaveList.contains(item)) { changed = true; } else { changed = as->noSaveList.value(item) != state; } if(changed) { as->noSaveList.insert(item, state); actions_->updateAction(account, item, state); if(type == "set") { showPopup(tr("No-save state for contact %1 is changed").arg(item)); } } if(type == "set") { const QString str = QString("").arg(accInfo->getJid(account), stanza.attribute("id")); stanzaSender->sendStanza(account, str); } } } return found; } bool GmailNotifyPlugin::checkAttributes(int account, const QDomElement &stanza, const QDomElement &query) { bool found = false; if(query.tagName() == "query" && query.attribute("xmlns") == "jabber:iq:roster" && query.attribute("ext") == "2") { const QString jid = stanza.attribute("to").split("/").at(0); const QString server = stanza.attribute("from").toLower(); if(!server.isEmpty() && jid.toLower() != server) { return false; } AccountSettings *as = findAccountSettings(jid); if(!as || as->account != account) { return true; } found = true; const QString type = stanza.attribute("type"); if(type == "set") { const QString str = QString("").arg(accInfo->getJid(account), stanza.attribute("id")); stanzaSender->sendStanza(account, str); } for(QDomNode child = query.firstChild(); !child.isNull(); child = child.nextSibling()) { QDomElement itemElem = child.toElement(); if(itemElem.isNull() || itemElem.tagName() != "item") continue; const QString jid = itemElem.attribute("jid"); const QString descr = itemElem.attribute("t"); Attributes atr; if(as->attributes.contains(jid)) { atr = as->attributes.value(jid); } if(atr.t != descr && type == "set") { showPopup(tr("Attributes for contact %1 are changed").arg(jid)); } atr.t = descr; as->attributes.insert(jid, atr); } } return found; } AccountSettings* GmailNotifyPlugin::findAccountSettings(const QString &jid) { if(!jid.isEmpty()) { foreach(AccountSettings* as, accounts) { if(as->jid == jid.toLower()) return as; } } return 0; } AccountSettings* GmailNotifyPlugin::create(int account, QString jid) { jid = jid.toLower(); if(jid.contains("/")) jid = jid.split("/").first(); AccountSettings *as = findAccountSettings(jid); if(!as) { as = new AccountSettings(account, jid); accounts.append(as); } else as->account = account; return as; } void GmailNotifyPlugin::changeNoSaveState(int account, QString jid, bool val) { if(!Utils::checkAccount(account, accInfo)) return; QString str = QString("" "" "" "") .arg(accInfo->getJid(account), stanzaSender->uniqueId(account)) .arg(jid, (val ? "enabled" : "disabled")); stanzaSender->sendStanza(account, str); // AccountSettings *as = findAccountSettings(accInfo->getJid(account)); // if(as) { // as->noSaveList.insert(jid, (val ? "enabled" : "disabled")); // } } bool GmailNotifyPlugin::hasAccountSettings(int account) { bool has = false; foreach(AccountSettings *as, accounts) { if(as->account == account) { has = true; break; } } return has; } void GmailNotifyPlugin::setStanzaSendingHost(StanzaSendingHost *host) { stanzaSender = host; } void GmailNotifyPlugin::setAccountInfoAccessingHost(AccountInfoAccessingHost* host) { accInfo = host; } void GmailNotifyPlugin::setOptionAccessingHost(OptionAccessingHost* host) { psiOptions = host; } void GmailNotifyPlugin::setPopupAccessingHost(PopupAccessingHost *host) { popup = host; } void GmailNotifyPlugin::setPsiAccountControllingHost(PsiAccountControllingHost *host) { accountController = host; } void GmailNotifyPlugin::setIconFactoryAccessingHost(IconFactoryAccessingHost *host) { iconHost = host; } void GmailNotifyPlugin::setEventCreatingHost(EventCreatingHost *host) { psiEvent = host; } void GmailNotifyPlugin::setSoundAccessingHost(SoundAccessingHost *host) { sound_ = host; } void GmailNotifyPlugin::showPopup(const QString& text) { int interval = popup->popupDuration(POPUP_OPTION); if(!interval) return; popup->initPopup(text, name(), "gmailnotify/menu", popupId); } void GmailNotifyPlugin::updateSharedStatus(AccountSettings* as) { if(as->sharedStatuses.contains(as->status)) { QStringList l = as->sharedStatuses.value(as->status); if(l.contains(as->message)) { l.removeAll(as->message); } l.push_front(as->message); while(l.size() > as->listContentsMax) { l.removeLast(); } as->sharedStatuses.insert(as->status, l); } else { as->sharedStatuses.insert(as->status, QStringList() << as->message); while(as->sharedStatuses.size() > as->listMax) { foreach(QString key, as->sharedStatuses.keys()) { if(key != as->status) { as->sharedStatuses.remove(key); break; } } } } Utils::updateSharedStatus(as, stanzaSender, accInfo); } QList < QVariantHash > GmailNotifyPlugin::getButtonParam() { return QList < QVariantHash >(); } QAction* GmailNotifyPlugin::getAction(QObject* parent, int account, const QString& contact) { const QString bareJid = contact.split("/").first(); QAction *act = actions_->newAction(parent, account, bareJid, iconHost->getIcon("gmailnotify/nohistory")); AccountSettings* as = findAccountSettings(accInfo->getJid(account)); if(as) { act->setVisible(as->isNoSaveEnbaled && as->isNoSaveSupported && as->isArchivingEnabled); if(as->noSaveList.contains(bareJid)) act->setChecked(as->noSaveList.value(bareJid)); } return act; } void GmailNotifyPlugin::updateActions(AccountSettings *as) { bool val = as->isNoSaveEnbaled && as->isNoSaveSupported && as->isArchivingEnabled; actions_->updateActionsVisibility(as->account, val); } void GmailNotifyPlugin::incomingMail(int account, const QDomElement &xml) { MailItemsList l; QDomElement mail = xml.firstChildElement("mail-thread-info"); while(!mail.isNull()) { MailItem mi; mi.url = mail.attribute("url"); mi.subject = mail.firstChildElement("subject").text(); mi.text = mail.firstChildElement("snippet").text(); mi.account = accInfo->getJid(account); QDomElement senders = mail.firstChildElement("senders"); QDomElement sender = senders.firstChildElement("sender"); QStringList fl; while(!sender.isNull()) { QString from = sender.attribute("name") + " <" + sender.attribute("address") + ">"; fl.append(from); sender = sender.nextSiblingElement("sender"); } fl.removeDuplicates(); mi.from = fl.join(", "); l.append(mi); mail = mail.nextSiblingElement("mail-thread-info"); } if(l.isEmpty()) { return; } mailItems_.append(l); bool soundEnabled = psiOptions->getGlobalOption("options.ui.notifications.sounds.enable").toBool(); if(soundEnabled) { psiOptions->setGlobalOption("options.ui.notifications.sounds.enable", false); playSound(soundFile); } QString popupMessage = tr("mail.google.com - incoming mail!"); if(psiOptions->getGlobalOption("options.ui.notifications.passive-popups.showMessage").toBool()) { popupMessage += "

"; foreach(const MailItem& i, l) popupMessage += ViewMailDlg::mailItemToText(i).replace("\n", "
") + "
"; } if(mailViewer_ && mailViewer_->isActiveWindow()) { showPopup(popupMessage); mailEventActivated(); } else { if(mailItems_.count() > 1) { showPopup(popupMessage); } else { psiEvent->createNewEvent(account, accInfo->getJid(account), popupMessage, this, SLOT(mailEventActivated())); } if(mailViewer_) { mailViewer_->setWindowTitle("*" + mailViewer_->caption()); } } psiOptions->setGlobalOption("options.ui.notifications.sounds.enable", soundEnabled); if(!program_.isEmpty()) { QStringList prog = program_.split(" "); QProcess *p = new QProcess(this); p->startDetached(prog.takeFirst(), prog); p->deleteLater(); } } void GmailNotifyPlugin::mailEventActivated() { if(mailItems_.isEmpty()) { return; } if(!mailViewer_) { mailViewer_ = new ViewMailDlg(mailItems_.takeFirst(), iconHost); } while(!mailItems_.isEmpty()) { mailViewer_->appendItems(mailItems_.takeFirst()); } mailViewer_->show(); mailViewer_->raise(); mailViewer_->activateWindow(); } void GmailNotifyPlugin::playSound(const QString &file) { sound_->playSound(file); } void GmailNotifyPlugin::checkSound() { playSound(ui_.le_sound->text()); } void GmailNotifyPlugin::getSound() { QString fileName = QFileDialog::getOpenFileName(0,tr("Choose a sound file"),"", tr("Sound (*.wav)")); if(fileName.isEmpty()) return; ui_.le_sound->setText(fileName); } void GmailNotifyPlugin::getProg() { QString fileName = QFileDialog::getOpenFileName(0,tr("Choose a program"),"",""); if(fileName.isEmpty()) return; ui_.le_program->setText(fileName); } QAction* GmailNotifyPlugin::getContactAction(QObject *parent, int account, const QString &contact) { QAction *act = 0; AccountSettings* as = findAccountSettings(accInfo->getJid(account)); if(as && as->isAttributesEnabled && as->isAttributesSupported) { act = new QAction(iconHost->getIcon("psi/stop"), tr("Block gmail contact"), parent); act->setCheckable(true); if(as->attributes.contains(contact) && as->attributes.value(contact).t == "B") act->setChecked(true); act->setProperty("jid", contact); act->setProperty("account", account); connect(act, SIGNAL(triggered(bool)), SLOT(blockActionTriggered(bool))); } return act; } void GmailNotifyPlugin::blockActionTriggered(bool block) { QAction* act = static_cast(sender()); const QString jid = act->property("jid").toString(); int acc = act->property("account").toInt(); QString str = QString("" "" "") .arg(stanzaSender->uniqueId(acc)) .arg(jid, block ? "B" : ""); stanzaSender->sendStanza(acc, str); } QString GmailNotifyPlugin::pluginInfo() { return tr("Authors: ") + "VampiRUS\nDealer_WeARE\n\n" + trUtf8("Shows notifications of new messages in your Gmailbox.\n" "Note: The plugin only checks the root of your Inbox folder in your" " Gmailbox for new messages. When using server side mail filtering, you may not be notified about all new messages."); } QPixmap GmailNotifyPlugin::icon() const { return QPixmap(":/icons/gmailnotify.png"); } plugins-1.5/deprecated/gmailserviceplugin/gmailserviceplugin.h000066400000000000000000000135251336777360500251220ustar00rootroot00000000000000/* * gmailserviceplugin.h - plugin * Copyright (C) 2009-2011 Kravtsov Nikolai, Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef GMAILSERVICEPLUGIN_H #define GMAILSERVICEPLUGIN_H class QDomElement; #include "actionslist.h" #include "psiplugin.h" #include "stanzafilter.h" #include "stanzasender.h" #include "stanzasendinghost.h" #include "optionaccessor.h" #include "optionaccessinghost.h" #include "plugininfoprovider.h" #include "accountinfoaccessinghost.h" #include "accountinfoaccessor.h" #include "popupaccessinghost.h" #include "popupaccessor.h" #include "psiaccountcontroller.h" #include "psiaccountcontrollinghost.h" #include "iconfactoryaccessinghost.h" #include "iconfactoryaccessor.h" #include "toolbariconaccessor.h" #include "eventcreatinghost.h" #include "eventcreator.h" #include "soundaccessinghost.h" #include "soundaccessor.h" #include "menuaccessor.h" #include "ui_options.h" #include "accountsettings.h" #include "viewmaildlg.h" #define OPTION_LISTS "lists" #define OPTION_INTERVAL "interval" #define OPTION_SOUND "sound" #define OPTION_PROG "program" #define POPUP_OPTION "Gmail Service Plugin" #define PLUGIN_VERSION "0.7.5" class GmailNotifyPlugin : public QObject, public PsiPlugin, public AccountInfoAccessor, public StanzaFilter, public StanzaSender, public OptionAccessor, public PluginInfoProvider, public PopupAccessor, public PsiAccountController, public IconFactoryAccessor, public ToolbarIconAccessor, public EventCreator, public SoundAccessor, public MenuAccessor { Q_OBJECT #ifdef HAVE_QT5 Q_PLUGIN_METADATA(IID "com.psi-plus.GmailNotifyPlugin") #endif Q_INTERFACES(PsiPlugin StanzaFilter StanzaSender /*EventFilter*/ OptionAccessor PluginInfoProvider AccountInfoAccessor PopupAccessor PsiAccountController IconFactoryAccessor ToolbarIconAccessor EventCreator SoundAccessor MenuAccessor) public: GmailNotifyPlugin(); virtual QString name() const; virtual QString shortName() const; virtual QString version() const; virtual QWidget* options(); virtual bool enable(); virtual bool disable(); virtual void setOptionAccessingHost(OptionAccessingHost* host); virtual void optionChanged(const QString& /*option*/){} virtual void applyOptions(); virtual void restoreOptions(); virtual bool incomingStanza(int account, const QDomElement& stanza); virtual bool outgoingStanza(int account, QDomElement& stanza); virtual void logout(int ) {} virtual void setStanzaSendingHost(StanzaSendingHost *host); virtual void setAccountInfoAccessingHost(AccountInfoAccessingHost* host); virtual void setPopupAccessingHost(PopupAccessingHost* host); virtual void setPsiAccountControllingHost(PsiAccountControllingHost* host); virtual void setIconFactoryAccessingHost(IconFactoryAccessingHost* host); virtual void setEventCreatingHost(EventCreatingHost* host); virtual void setSoundAccessingHost(SoundAccessingHost* host); virtual QList < QVariantHash > getButtonParam(); virtual QAction* getAction(QObject* parent, int account, const QString& contact); virtual QList < QVariantHash > getAccountMenuParam() { return QList < QVariantHash > (); } virtual QList < QVariantHash > getContactMenuParam() { return QList < QVariantHash > (); } virtual QAction* getContactAction(QObject* parent, int account, const QString& contact); virtual QAction* getAccountAction(QObject* /*parent*/, int /*account*/) { return 0; } virtual QString pluginInfo(); virtual QPixmap icon() const; private slots: void updateSharedStatus(AccountSettings* as); void changeNoSaveState(int account, QString jid, bool val); void updateOptions(int index); void stopOptionsApply(); void mailEventActivated(); void checkSound(); void getSound(); void blockActionTriggered(bool); void getProg(); private: AccountSettings* findAccountSettings(const QString& jid); AccountSettings* create(int account, QString jid); bool hasAccountSettings(int account); bool checkFeatures(int account, const QDomElement& stanza, const QDomElement& query); bool checkEmail(int account, const QDomElement& stanza, const QDomElement& query); bool checkSettings(int account, const QDomElement& stanza, const QDomElement& query); bool checkSharedStatus(int account, const QDomElement& stanza, const QDomElement& query); bool checkNoSave(int account, const QDomElement& stanza, const QDomElement& query); bool checkAttributes(int account, const QDomElement& stanza, const QDomElement& query); void saveLists(); void loadLists(); void showPopup(const QString& text); void updateActions(AccountSettings* as); void incomingMail(int account, const QDomElement& xml); void playSound(const QString& file); private: bool enabled; bool optionsApplingInProgress_; StanzaSendingHost* stanzaSender; OptionAccessingHost* psiOptions; AccountInfoAccessingHost* accInfo; PopupAccessingHost* popup; PsiAccountControllingHost* accountController; IconFactoryAccessingHost* iconHost; EventCreatingHost* psiEvent; SoundAccessingHost* sound_; QString soundFile; ActionsList* actions_; QPointer options_; QPointer mailViewer_; QList accounts; typedef QList MailItemsList; QList mailItems_; QStringList id_; int popupId; QString program_; Ui::Options ui_; }; #endif plugins-1.5/deprecated/gmailserviceplugin/gmailserviceplugin.pro000066400000000000000000000006611336777360500254700ustar00rootroot00000000000000CONFIG += release isEmpty(PSISDK) { include(../../psiplugin.pri) } else { include($$PSISDK/plugins/psiplugin.pri) } SOURCES += gmailserviceplugin.cpp \ accountsettings.cpp \ common.cpp \ actionslist.cpp \ viewmaildlg.cpp FORMS += options.ui \ viewmaildlg.ui HEADERS += gmailserviceplugin.h \ accountsettings.h \ common.h \ actionslist.h \ viewmaildlg.h RESOURCES += gmailserviceplugin.qrc plugins-1.5/deprecated/gmailserviceplugin/gmailserviceplugin.qrc000066400000000000000000000002061336777360500254500ustar00rootroot00000000000000 gmailnotify.png nohistory.png plugins-1.5/deprecated/gmailserviceplugin/nohistory.png000066400000000000000000000016301336777360500236160ustar00rootroot00000000000000PNG  IHDRasRGBbKGD pHYs^tIME   b>IDAT8MMhewf:6fے5KcT(R$ EmoěoUE(Ҟ*J 4Iiμ3~x?897)mD>LU5NU_fD30 L{di䚽X%8!SSEz1EiC(,ÏbRi tnk'zx; #`jZ&DBq'ksYYB[ljٱAv2r ug@* +Ty,C>F8pbA@(SzLz$&Q[k>Q.Z[n,mp%NW\$~"6G`Gv5VV)k~׿Fizٿ ڼq.Rqs7Y)t}P'("(ǘ?%} p]Nr/Kf+Z Z`76`g8'wWw8铽~=_d)FJW `[ =}az+~ևwsy6\1RXH?8ܼpco<኷&Q,f+BzK+ z5[h47m_|q~DgϽro<\դԚ@< ԢB %ҫR]7IENDB`plugins-1.5/deprecated/gmailserviceplugin/options.ui000066400000000000000000000170101336777360500231030ustar00rootroot00000000000000 Options 0 0 344 440 Form Supported accounts: 180 0 Qt::Horizontal 40 20 There is no supported accounts! Account Settings If set to "true", the server will send notifications of unread email. Mail notifications If set to "true", the server will save Google Talk chats on the server; if set to "false", no conversations will be logged. Message archiving If set to "true", the server will automatically add people emailed often to the user's roster. Auto-accept suggestions Enable multiple applications signed in as the same user to report the same status message. Enable Shared Statuses Google Talk server disables server-side logging of individual conversations and sends notifications. Enable "Message archiving" option for use! Enable Off the Record Chats Enable "Mail notifications" option! Mail Notifications Settings Show all unread messages Show new messages only 0 0 Start program: 0 0 Play sound: Qt::Vertical 20 40 <a href="http://psi-plus.com/wiki/plugins#gmail_service_plugin">Wiki (Online)</a> true cb_mail toggled(bool) gb_mail_settings setEnabled(bool) 191 79 187 206 cb_archiving toggled(bool) cb_nosave setEnabled(bool) 120 122 120 189 plugins-1.5/deprecated/gmailserviceplugin/viewmaildlg.cpp000066400000000000000000000077171336777360500240760ustar00rootroot00000000000000/* * viewmaildlg.cpp - plugin * Copyright (C) 2011 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "viewmaildlg.h" #include #include static const QString mailBoxUrl = "https://mail.google.com/mail/#inbox"; ViewMailDlg::ViewMailDlg(QList l, IconFactoryAccessingHost* host, QWidget *p) : QDialog(p, Qt::Window) , items_(l) , currentItem_(-1) { setAttribute(Qt::WA_DeleteOnClose); ui_.setupUi(this); ui_.tb_next->setIcon(host->getIcon("psi/arrowRight")); ui_.tb_prev->setIcon(host->getIcon("psi/arrowLeft")); ui_.pb_close->setIcon(style()->standardIcon(QStyle::SP_DialogCloseButton)); ui_.pb_browse->setIcon(style()->standardIcon(QStyle::SP_BrowserReload)); connect(ui_.tb_next, SIGNAL(clicked()), SLOT(showNext())); connect(ui_.tb_prev, SIGNAL(clicked()), SLOT(showPrev())); connect(ui_.pb_browse, SIGNAL(clicked()), SLOT(browse())); connect(ui_.te_text, SIGNAL(anchorClicked(QUrl)), SLOT(anchorClicked(QUrl))); if(!items_.isEmpty()) { currentItem_ = 0; showItem(currentItem_); } updateCaption(); } void ViewMailDlg::updateCaption() { setWindowTitle( caption() ); } QString ViewMailDlg::caption() const { return tr("[%1/%2] E-Mail") .arg(QString::number(currentItem_+1)) .arg(items_.size()); } void ViewMailDlg::appendItems(QList l) { items_.append(l); if(currentItem_ == -1) { currentItem_ = 0; showItem(currentItem_); } updateButtons(); updateCaption(); } void ViewMailDlg::updateButtons() { if(items_.isEmpty()) { ui_.tb_next->setEnabled(false); ui_.tb_prev->setEnabled(false); } else { ui_.tb_prev->setEnabled(currentItem_ != 0); ui_.tb_next->setEnabled(items_.size()-1 > currentItem_); } } void ViewMailDlg::showNext() { if(ui_.tb_next->isEnabled()) showItem(++currentItem_); } void ViewMailDlg::showPrev() { if(ui_.tb_prev->isEnabled()) showItem(--currentItem_); } void ViewMailDlg::showItem(int num) { ui_.le_account->clear(); ui_.le_from->clear(); ui_.le_subject->clear(); ui_.te_text->clear(); if(num != -1 && !items_.isEmpty() && num < items_.size() ) { MailItem me = items_.at(num); ui_.le_account->setText(me.account); ui_.le_account->setCursorPosition(0); ui_.le_from->setText(me.from); ui_.le_from->setCursorPosition(0); ui_.le_subject->setText(me.subject); ui_.le_subject->setCursorPosition(0); //FIXMI gmail отдает какой-то непонятный урл QRegExp re("th=([0-9]+)&"); QString text = me.text; if(me.url.contains(re)) { QString url = mailBoxUrl + "/"; QString tmp = re.cap(1); url += QString::number(tmp.toLongLong(), 16); text += QString("

%2").arg(url, tr("Open in browser")); } ui_.te_text->setHtml(text); } updateButtons(); updateCaption(); } void ViewMailDlg::browse() { QDesktopServices::openUrl(QUrl(mailBoxUrl)); } void ViewMailDlg::anchorClicked(const QUrl &url) { if(!url.isEmpty()) { QDesktopServices::openUrl(url); if(items_.count() < 2) { close(); } } } void ViewMailDlg::wheelEvent(QWheelEvent *e) { if(e->delta() < 0) { showNext(); } else { showPrev(); } e->accept(); } QString ViewMailDlg::mailItemToText(const MailItem &mi) { QStringList lst = QStringList() << mi.from << mi.subject << mi.text; QString text = lst.join("\n") + "\n"; return text; } plugins-1.5/deprecated/gmailserviceplugin/viewmaildlg.h000066400000000000000000000031261336777360500235310ustar00rootroot00000000000000/* * viewmaildlg.h - plugin * Copyright (C) 2011 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef VIEWMAILDLG_H #define VIEWMAILDLG_H #include "ui_viewmaildlg.h" #include "iconfactoryaccessinghost.h" struct MailItem { QString account; QString from; QString subject; QString text; QString url; }; class ViewMailDlg : public QDialog { Q_OBJECT public: ViewMailDlg(QList l, IconFactoryAccessingHost* host, QWidget *p = 0); ~ViewMailDlg() {}; void appendItems(QList l); QString caption() const; static QString mailItemToText(const MailItem& mi); private slots: void updateButtons(); void showNext(); void showPrev(); void browse(); void anchorClicked(const QUrl& url); private: void showItem(int num); void updateCaption(); protected: void wheelEvent(QWheelEvent *e); private: Ui::ViewMailDlg ui_; QList items_; int currentItem_; }; #endif // VIEWMAILDLG_H plugins-1.5/deprecated/gmailserviceplugin/viewmaildlg.ui000066400000000000000000000100011336777360500237050ustar00rootroot00000000000000 ViewMailDlg 0 0 513 351 0 0 E-Mail From: true Subject: true true Account: false false false Open mail in browser Open MailBox false Previous false Next Qt::Horizontal 40 20 Close &Close pb_close clicked() ViewMailDlg close() 460 324 256 175 plugins-1.5/deprecated/gnome3supportplugin/000077500000000000000000000000001336777360500212255ustar00rootroot00000000000000plugins-1.5/deprecated/gnome3supportplugin/CMakeLists.txt000066400000000000000000000032001336777360500237600ustar00rootroot00000000000000set( PLUGIN gnome3supportplugin ) cmake_minimum_required( VERSION 2.8.12) set( CMAKE_AUTOMOC TRUE ) IF( NOT WIN32 ) set( LIB_SUFFIX "" CACHE STRING "Define suffix of directory name (32/64)" ) set( PLUGINS_PATH "lib${LIB_SUFFIX}/psi-plus/plugins" CACHE STRING "Install suffix for plugins" ) ELSE( NOT WIN32 ) set( PLUGINS_PATH "psi-plus/plugins" CACHE STRING "Install suffix for plugins" ) ENDIF( NOT WIN32 ) add_definitions( -Wall -Ddbus -DQT_PLUGIN ) include_directories( ${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ../../include . ) set( _SRCS ${PLUGIN}.cpp ) set( _RSCS resources.qrc ) IF( ${USE_QT5} ) find_package( Qt5Widgets REQUIRED ) find_package( Qt5Xml REQUIRED ) find_package( Qt5DBus REQUIRED ) include_directories( ${Qt5Widgets_INCLUDES} ${Qt5Xml_INCLUDES} ${Qt5Dbus_INCLUDES} ) add_definitions( ${Qt5Widgets_DEFINITIONS} ${Qt5Xml_DEFINITIONS} ${Qt5Dbus_DEFINITIONS} ) set(QT_DEPLIBS Qt5::Widgets Qt5::Xml Qt5::DBus ) qt5_add_resources(RSCS ${_RSCS}) ELSE( ${USE_QT5} ) find_package( Qt4 REQUIRED ) include( ${QT_USE_FILE} ) include_directories( ${QT_QTCORE_INCLUDE_DIR} ${QT_QTGUI_INCLUDE_DIR} ${QT_QTXML_INCLUDE_DIR} ${QT_QTDBUS_INCLUDE_DIR} ) set(QT_DEPLIBS ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY} ${QT_QTXML_LIBRARY} ${QT_QTDBUS_LIBRARY} ) QT4_ADD_RESOURCES(RSCS ${_RSCS}) ENDIF( ${USE_QT5} ) add_library( ${PLUGIN} MODULE ${_SRCS} ${UIS} ${RSCS} ${TRS} ${MOCS} ) target_link_libraries( ${PLUGIN} ${QT_DEPLIBS} ) install( TARGETS ${PLUGIN} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} ) plugins-1.5/deprecated/gnome3supportplugin/changelog.txt000066400000000000000000000010421336777360500237120ustar00rootroot000000000000002013-08-13 v0.0.3 - taurus + Иконка плагина 2012-03-30 v0.0.2 + Исправления в кодестайле + Небольшая оптимизация в работе 2011-12-22 v0.0.1 + ! initial версия Плагин предназначен для добавления поддержки установки статуса присутствия в среде GNOME 3. Плагин предназначен только для работы в операционных системах семейства Linux plugins-1.5/deprecated/gnome3supportplugin/gnome3support.png000066400000000000000000000021221336777360500245550ustar00rootroot00000000000000PNG  IHDRazTXtRaw profile type exifxڥQ!=E DZ rؽfhMk#N:|_[V.E5lzJdy}{+A JEtꔝQr*O8RJ m]V专@BK-6tA-#UjڴR%UZ˭[11jfnͺWe{Vpi͚zǞ{MrȡG=} } uF<˔N>'HSNMg=}!VYteW[A~x ={P f B nA ,;p f1BNj;UT$EvTSnUr)'-j30&vUa4TO=.4\#qqQ}sBIT|d*IDAT8ӱ+asRN 2( :6P b7?e3aF`(eR\rgx~wO=~}鱎A/ȥpI|gt,ab \B3`(=Ac8lmX(b 3\I(:JN|+,lE0|V`H+Gw;z4# Б{j*j8BGFC䱂Q\$A>.7f.&6q| 'AMK zI!.MM؞TIENDB`plugins-1.5/deprecated/gnome3supportplugin/gnome3supportplugin.cpp000077500000000000000000000126601336777360500260050ustar00rootroot00000000000000/* * gnome3supportplugin.cpp - plugin * Copyright (C) 2011 KukuRuzo * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "psiplugin.h" #include "plugininfoprovider.h" #include "optionaccessinghost.h" #include "optionaccessor.h" #include "accountinfoaccessinghost.h" #include "accountinfoaccessor.h" #include "psiaccountcontroller.h" #include "psiaccountcontrollinghost.h" #include #include #include #define gnome3Service "org.gnome.SessionManager" #define gnome3Interface "org.gnome.SessionManager.Presence" #define gnome3Path "/org/gnome/SessionManager/Presence" static const QStringList statuses = QStringList() << "online" << "invisible" << "dnd" << "away"; #define constVersion "0.0.3" class Gnome3StatusWatcher : public QObject, public PsiPlugin, public PluginInfoProvider, public OptionAccessor, public PsiAccountController, public AccountInfoAccessor { Q_OBJECT #ifdef HAVE_QT5 Q_PLUGIN_METADATA(IID "com.psi-plus.Gnome3StatusWatcher") #endif Q_INTERFACES(PsiPlugin PluginInfoProvider OptionAccessor PsiAccountController AccountInfoAccessor) public: Gnome3StatusWatcher(); virtual QString name() const; virtual QString shortName() const; virtual QString version() const; virtual QWidget* options(); virtual bool enable(); virtual bool disable(); virtual void applyOptions() {}; virtual void restoreOptions() {}; virtual QPixmap icon() const; virtual void optionChanged(const QString&) {}; virtual void setOptionAccessingHost(OptionAccessingHost* host); virtual void setAccountInfoAccessingHost(AccountInfoAccessingHost* host); virtual void setPsiAccountControllingHost(PsiAccountControllingHost* host); virtual QString pluginInfo(); private: bool enabled; OptionAccessingHost* psiOptions; AccountInfoAccessingHost* accInfo; PsiAccountControllingHost* accControl; QString status, statusMessage; bool isDBUSConnected; void connectToBus(const QString &service_); void disconnectFromBus(const QString &service_); void setPsiGlobalStatus(const QString &status); private slots: void onGnome3StatusChange(const uint &status); }; #ifndef HAVE_QT5 Q_EXPORT_PLUGIN(Gnome3StatusWatcher); #endif Gnome3StatusWatcher::Gnome3StatusWatcher() { enabled = false; psiOptions = 0; accInfo = 0; accControl = 0; } QString Gnome3StatusWatcher::name() const { return "Gnome 3 Support Plugin"; } QString Gnome3StatusWatcher::shortName() const { return "gnome3support"; } QString Gnome3StatusWatcher::version() const { return constVersion; } void Gnome3StatusWatcher::setOptionAccessingHost(OptionAccessingHost* host) { psiOptions = host; } void Gnome3StatusWatcher::setAccountInfoAccessingHost(AccountInfoAccessingHost* host) { accInfo = host; } void Gnome3StatusWatcher::setPsiAccountControllingHost(PsiAccountControllingHost* host) { accControl = host; } bool Gnome3StatusWatcher::enable() { if (psiOptions) { enabled = true; isDBUSConnected = false; QStringList services = QDBusConnection::sessionBus().interface()->registeredServiceNames().value(); if (services.contains(gnome3Service, Qt::CaseInsensitive)) { connectToBus(gnome3Service); } } return enabled; } bool Gnome3StatusWatcher::disable(){ enabled = false; if (isDBUSConnected) { disconnectFromBus(gnome3Service); } return true; } QPixmap Gnome3StatusWatcher::icon() const { return QPixmap(":/icons/gnome3support.png"); } QWidget* Gnome3StatusWatcher::options() { return 0; } QString Gnome3StatusWatcher::pluginInfo() { return tr("Authors: ") + "KukuRuzo\n\n" + trUtf8("This plugin is designed to add support of GNOME 3 presence status changes"); } void Gnome3StatusWatcher::connectToBus(const QString &service_) { isDBUSConnected = QDBusConnection::sessionBus().connect(service_, QLatin1String(gnome3Path), QLatin1String(gnome3Interface), QLatin1String("StatusChanged"), this, SLOT(onGnome3StatusChange(uint))); } void Gnome3StatusWatcher::disconnectFromBus(const QString &service_) { QDBusConnection::sessionBus().disconnect(service_, QLatin1String(gnome3Path), QLatin1String(gnome3Interface), QLatin1String("StatusChanged"), this, SLOT(onGnome3StatusChange(uint))); } void Gnome3StatusWatcher::onGnome3StatusChange(const uint &status_) { int i = (int)status_; if (i != -1 && i < statuses.length()) { setPsiGlobalStatus(statuses[i]); } } void Gnome3StatusWatcher::setPsiGlobalStatus(const QString &status_) { if (!enabled) return; int account = 0; while (accInfo->getJid(account) != "-1") { QString accStatus = accInfo->getStatus(account); if (accStatus != "offline" && accStatus != "invisible" && accStatus != status_) { accControl->setStatus(account, status_, ""); } ++account; } } #include "gnome3supportplugin.moc" plugins-1.5/deprecated/gnome3supportplugin/gnome3supportplugin.pro000066400000000000000000000002011336777360500260040ustar00rootroot00000000000000!mac { CONFIG += release include(../../psiplugin.pri) SOURCES += gnome3supportplugin.cpp QT += dbus RESOURCES += resources.qrc } plugins-1.5/deprecated/gnome3supportplugin/resources.qrc000066400000000000000000000001451336777360500237460ustar00rootroot00000000000000 gnome3support.png plugins-1.5/deprecated/yandexnarodplugin/000077500000000000000000000000001336777360500207145ustar00rootroot00000000000000plugins-1.5/deprecated/yandexnarodplugin/authmanager.cpp000066400000000000000000000111331336777360500237130ustar00rootroot00000000000000/* authmanger.cpp Copyright (c) 2011 by Evgeny Khryukin *************************************************************************** * * * 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. * * * *************************************************************************** */ #include #include #include "authmanager.h" #include "options.h" #include "requestauthdialog.h" #include "common.h" AuthManager::AuthManager(QObject* p) : QObject(p) , authorized_(false) { manager_ = newManager(this); connect(manager_, SIGNAL(finished(QNetworkReply*)), SLOT(replyFinished(QNetworkReply*))); timer_ = new QTimer(this); timer_->setInterval(10000); timer_->setSingleShot(true); connect(timer_, SIGNAL(timeout()), SLOT(timeout())); loop_ = new QEventLoop(this); } AuthManager::~AuthManager() { if(timer_->isActive()) timer_->stop(); if(loop_->isRunning()) loop_->exit(); } bool AuthManager::go(const QString& login, const QString& pass, const QString& captcha) { narodLogin = login; narodPass = pass; QString narodCaptchaKey = captcha; Options *o = Options::instance(); QByteArray post = "login=" + narodLogin.toLatin1() + "&passwd=" + narodPass.toLatin1(); if (narodLogin.isEmpty() || narodPass.isEmpty() || !narodCaptchaKey.isEmpty()) { requestAuthDialog authdialog; authdialog.setLogin(narodLogin); authdialog.setPasswd(narodPass); if (!narodCaptchaKey.isEmpty()) { authdialog.setCaptcha(manager_->cookieJar()->cookiesForUrl(mainUrl), "http://passport.yandex.ru/digits?idkey=" + narodCaptchaKey); } if (authdialog.exec()) { narodLogin = authdialog.getLogin(); narodPass = authdialog.getPasswd(); if (authdialog.getRemember()) { o->setOption(CONST_LOGIN, narodLogin); o->setOption(CONST_PASS, Options::encodePassword(narodPass)); } post = "login=" + narodLogin.toLatin1() + "&passwd=" + narodPass.toLatin1(); } else { post.clear(); } if (!post.isEmpty() && !narodCaptchaKey.isEmpty()) { post += "&idkey="+narodCaptchaKey.toLatin1()+"&code="+authdialog.getCode(); } } if (!post.isEmpty()) { post += "&twoweeks=yes"; QNetworkRequest nr = newRequest(); nr.setUrl(authUrl); nr.setHeader(QNetworkRequest::ContentLengthHeader, post.length()); nr.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); manager_->post(nr, post); if(!loop_->isRunning()) { timer_->start(); loop_->exec(); } } else { return false; } return authorized_; } QList AuthManager::cookies() const { QList ret; if(authorized_) ret = manager_->cookieJar()->cookiesForUrl(mainUrl); return ret; } void AuthManager::timeout() { if(loop_->isRunning()) { authorized_ = false; loop_->exit(); } } void AuthManager::replyFinished(QNetworkReply* reply) { QVariant cooks = reply->header(QNetworkRequest::SetCookieHeader); if (!cooks.isNull()) { bool found = false; foreach (const QNetworkCookie& netcook, qVariantValue< QList >(cooks)) { if (netcook.name() == "yandex_login" && !netcook.value().isEmpty()) { found = true; break; } } if (!found) { QRegExp rx("]+name=\"no\""); QString page = reply->readAll(); if (rx.indexIn(page) > 0) { QRegExp rx1("]*>"); if (rx1.indexIn(page) > 0) { QByteArray post = "idkey=" + rx1.cap(1).toAscii() + "&filled=yes"; QNetworkRequest nr = newRequest(); nr.setUrl(authUrl); nr.setHeader(QNetworkRequest::ContentLengthHeader, post.length()); nr.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); manager_->post(nr, post); reply->deleteLater(); return; } } else { rx.setPattern(""); if (rx.indexIn(page) > 0) { timer_->stop(); go(narodLogin, narodPass, rx.cap(1)); reply->deleteLater(); return; } else { authorized_ = false; loop_->exit(); reply->deleteLater(); return; } } } else { authorized_ = true; loop_->exit(); reply->deleteLater(); return; } } authorized_ = false; loop_->exit(); reply->deleteLater(); return; } plugins-1.5/deprecated/yandexnarodplugin/authmanager.h000066400000000000000000000024151336777360500233630ustar00rootroot00000000000000/* authmanger.h Copyright (c) 2011 by Evgeny Khryukin *************************************************************************** * * * 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. * * * *************************************************************************** */ #ifndef AUTHMANAGER_H #define AUTHMANAGER_H #include class QNetworkReply; class QNetworkAccessManager; class QEventLoop; class QTimer; class AuthManager : public QObject { Q_OBJECT public: AuthManager(QObject* p = 0); ~AuthManager(); bool go(const QString& login, const QString& pass, const QString& captcha = ""); QList cookies() const; private slots: void timeout(); void replyFinished(QNetworkReply* r); private: bool authorized_; QString narodLogin, narodPass; QNetworkAccessManager *manager_; QEventLoop *loop_; QTimer *timer_; }; #endif // AUTHMANAGER_H plugins-1.5/deprecated/yandexnarodplugin/changelog.txt000066400000000000000000000130221336777360500234020ustar00rootroot000000000000002013-08-13 v0.1.4 - taurus + Иконка плагина 2012-02-23 v0.1.3 * при нажатии кнопки "В Броузер" теперь открывается ссылка http://narod.yandex.ru/disk/all/ * пароль теперь хранится в зашифрованном виде * некоторые справления уи * исправлены некоторые статусные сообщения в диалоге загрузки * исправлено отображения файлов со спецсимволами в имени 2012-02-22 v0.1.2 * исправления для новой системы попапов * исправления для Qt 4.8.0 2012-01-24 rion v0.1.1 * fixed regular expression in yandexnarod plugin to match outdated files too 2011-11-09 v0.1.0 * изменен механизм аплоада файлов на сервер, теперь можно загружать файлы большого объема * различные оптимизации + в диалог загрузки добавлена ссылка на файл + добавлена ссылка на вики 2011-10-28 v0.0.9 * удаленные файлы нельзя снова удалить + кнопка "Продлить" восстановлена, также добавлен соответствующий пункт меню Они активны только для файлов, срок жизни которых меньше 45 дней. + добавлена возможность послать файл перетаскиванием его в список 2011-10-27 v0.0.8 * убран пробел после ссылки при копировании + добавлен пункт меню "копировать ссылку" + добавлена кнопка "открыть броузер" + добавлено предупреждение при удалении файлов + улучшения для переводчиков 2011-10-21 v0.0.7 + во всплывающей подсказке добавлена информация о запороленности файла + добавлено контекстное меню на файлах + добавлена возможность установить и снять пароль 2011-10-20 v0.0.6 * улучшена работа с кукисами + добавлен показ всплывающего уведомления об успешной отправке файла контакту * много различных исправлений кода и оптимизаций 2011-10-19 v0.0.5 * исправлена работа через прокси-сервер - из зависимостей убран WebKit + добавлено сохранение кукисов с последующим их использованием + добавлена возможность удалить сохраненные кукисы * исправлен показ кол-ва файлов в списке + добавлена возможность получить ссылки для скачивания простым перетаскиванием файлов в поле ввода * изменен дизайн окна менеджера + исправлена работа для случая, когда в настройках паспорта стоит "Узнавать меня всегда" 2011-10-18 v0.0.4 * исправлен показ срока жизни файлов в подсказке * множество различных исправлений и улучшений, многое переписано, многое оптимизировано 2011-10-14 v0.0.3 + окно менеджера сделано сворачиваемым и максимизируемым + в информацию о плагине добавлена ссылка на страницу http://passport.yandex.ru/passport?mode=tune * спрятана кнопка Prolongate т.к. похоже, что она пока не работает * исправлена работа каптчи * некоторые исправления связанные с увеличением стабильности 2011-10-13 v0.0.2 + в настройки добавлена кнопка запуска менеджера + в менеджере добавлены всплывающие подсказки над файлами + добавлена возможность продлить время хранения файла (не протестировано) * теперь прокси используется и для закгрузки каптчи (не протестировано) * различные исправления 2011-10-12 v0.0.1 ! initial version Плагин является портом соответсвующего плагина для QutIM (http://qutim.org/forum/viewtopic.php?f=62&t=711) Позволяет передавать файлы с помощью сервиса Яндекс.Диск http://narod.yandex.ru/ (пункт меню контакта) Также позволяет управлять файлами, загруженными на данных хост (пункт меню аккаунта) По сравнению с оригиналом добавлена поддержка прокси-сервера, исправлено удаление файлов; некоторые другие исправления plugins-1.5/deprecated/yandexnarodplugin/common.cpp000066400000000000000000000022761336777360500227170ustar00rootroot00000000000000/* common.cpp Copyright (c) 2011 by Evgeny Khryukin *************************************************************************** * * * 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. * * * *************************************************************************** */ #include "common.h" #include #include "options.h" QNetworkRequest newRequest() { QNetworkRequest nr; nr.setRawHeader("Cache-Control", "no-cache"); nr.setRawHeader("Accept", "*/*"); nr.setRawHeader("User-Agent", "PsiPlus/0.15 (U; YB/4.2.0; MRA/5.5; en)"); return nr; } QNetworkAccessManager* newManager(QObject* parent) { QNetworkAccessManager* netman = new QNetworkAccessManager(parent); if(Options::instance()->useProxy()) { netman->setProxy(Options::instance()->getProxy()); } return netman; } plugins-1.5/deprecated/yandexnarodplugin/common.h000066400000000000000000000017511336777360500223610ustar00rootroot00000000000000/* common.h Copyright (c) 2011 by Evgeny Khryukin *************************************************************************** * * * 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. * * * *************************************************************************** */ #ifndef COMMON_H #define COMMON_H #include class QNetworkAccessManager; const QUrl mainUrl = QUrl("http://narod.yandex.ru"); const QUrl authUrl = QUrl("http://passport.yandex.ru/passport?mode=auth"); QNetworkRequest newRequest(); QNetworkAccessManager* newManager(QObject* parent); #endif // COMMON_H plugins-1.5/deprecated/yandexnarodplugin/icons/000077500000000000000000000000001336777360500220275ustar00rootroot00000000000000plugins-1.5/deprecated/yandexnarodplugin/icons/clipboard.png000066400000000000000000000013571336777360500245020ustar00rootroot00000000000000PNG  IHDRaIDATx}oHSQƟnnN#K7"UDDL+%%K} DҗL_JIAIi"43欭qL0ڽn^!ZsFsnK$6^Fbn\.<~A;.Ry& ,qUoa4(w]G8#Ip_B"VQQV\evϭlRЄϋKHHhJ@#{"-'zfIpANbʂ BAc`cǯ 3 ^')YXV8J_B$ A 9`z? б:4V+Wxl ?6T'Q I 6mG/Df!nzTޡi6 ~U0t3%a--eTD 8 MJ-˿%RffXƅrtX 8wwwh$e! eY%8}9$*B2 5hQ2#)Z+'`0(Xa4;ڃKϺpĹZ' |>z%Leٰ*Ws?Հ)\ٓ[g\>@)M# 4Ԁ,JGas0mN>X=t^] ~? Ks_hw\~ < 6NtIENDB`plugins-1.5/deprecated/yandexnarodplugin/icons/close.png000066400000000000000000000012471336777360500236460ustar00rootroot00000000000000PNG  IHDRanIDATxڥ]HQ>ml5(I *E9FEiLR(an/Z,JִXnDÒeIwmw:.<;ys(Qłn*'Q`RΕ4@woy547?F2Zmc9 б`K=KV*'I80/`o> xg4ojiqxߟudyļZfSb8)^afŢƥH>_:X W8tldi$ ɤ(7omD>*.4w84"H {B]Q~%6q&=eyDb.`{x}]Vf!%:9 >'JEnET1>p1\o+NS&^R`MxSRH@ybɮ @r G`$0&J $RI6EQ:y%3PHUXo.6lS>~r  )YcY: R4ɬ]/ƥ0=@`L;Zo s0b`X8IENDB`plugins-1.5/deprecated/yandexnarodplugin/icons/prolongate.png000066400000000000000000000007551336777360500247160ustar00rootroot00000000000000PNG  IHDRaIDATxcd0Ԁ  8UY[+l.hFo>eӑh~}2u;3Ę8TtHXmk{?V+__ g`ǩ*sYB.=9BBgQ xʳY'Ɗ߷ ^P_ H>#tɎfh1Bc/ r^80 #?Nd`dgA(vS@]u?_1cef`ï |6U)r3kKv^rt1b a91S*Nݻ_$e L6?bA!qD)e ]߿L\8^"A<<7J ecIENDB`plugins-1.5/deprecated/yandexnarodplugin/icons/reload.png000066400000000000000000000016071336777360500240070ustar00rootroot00000000000000PNG  IHDRaNIDATxekhWwfdMUj%CKSj4ho?0m!"J_Z|ɦƖmQ7&ĝG̺3wz3\9w.n.ї10ϏŤLzgn3Y^ʵ)ByZ `4l%athKFbOkc)c$xR@o F&+dx}E7HklbJᡳK%Zz3ݟ.d̒I@+`U'pfayQ2axZ6 M:_WRr@-xkZ B8`7c'XHq wwDOaĎ 5%۰tIGpE݂pastc8jǀ#D}hȉ4yn+|?湷\~bVb"`!Z"K ;a)ցp>tO<hьELPJ{dE wRS>QXx; ʟMcoJS䮾)Lfqu7N3w59&֣/w^) -4]]r񄀁`m3n:luTL8S9+pja ӲCwm$xg+ $9j |\j .GHd UR_+L{l ")HQ/騟_Ց}B11P晕 L8[^?4+hdtYPη~Q+~ܨQM/j̾hSFBΗroxjIENDB`plugins-1.5/deprecated/yandexnarodplugin/icons/upload.png000066400000000000000000000014431336777360500240230ustar00rootroot00000000000000PNG  IHDRasRGBbKGD pHYs  tIME  $nIDAT8uKhY@{~"&MΨ(!\L k .u+qBE\QIИQR"p߽aŀ@kIWYkِkө!Z7uP tzVױ²ե$5!@ C8umT @-gږ|U=6B 䮋m%CGd,ɩ3lkk2o]skvr3+k~pUKd,ɛo*gWQLWi t-lg#-9I.loўr If7 b]`I z =^y,!w4I*K"́ŗ>q2 0Gi|Tб"&I4crIwLdkZUu]&e\UoǩOȪwW-wQ 05a9vu[33+iA ôBJdP8UP/ |MI-Vt*TJuLs9eR.aWj,ax;SF@w6sǬt k{IENDB`plugins-1.5/deprecated/yandexnarodplugin/icons/yandexnarod-icons-files.png000066400000000000000000000057041336777360500272700ustar00rootroot00000000000000PNG  IHDR Q{tEXtSoftwareAdobe ImageReadyqe<PLTE--ZPY ||E55K1,5eee666SSS&%%ڭҡ\\\BBBӊ*̺rOJJJɼcjͤiiiM"צQդxƗTxWʓGe)zcDu+aHzeqhv/0z1sgUJ/--덬zlڨTӫVŦP$_9o vGֽٳѫoodJoȅ:b('ƘVsSJSSTԥ7㷥L!uP6SNȓ2q͑h֖'44~0gipǘvಊfsUvw#ר8,ŲrזɄW~A!߭7dw }shʩ򤤑lWpN6|w Ԣµۅ=ֵy aG[zxx|M\3ITU.\FbPI۩ \쭶_4v">a(1°L+˚ȥ)ZsH$zm3!aN΂TU2rw_N_8P~ҏ  %$ʼnl!@6a$%^i<^ryZUqy'_7DE pX < pQkzV.~Wa bLz1ꁺEJL8pc^ @v 4}b}nUMMW.QXJ- T*p-wu=?i諟X$bNEkX`{hIID@D&"GA؉9&ꐀ;Ȗd{苷>ol-mjZ R0m_cԬS(ڃu:Oh`!ާ% ^>z8/vqwn *X`݉c(cva3Hx6cxU%'dKZչľD[7P)-ZƩ^,@ :e$FM H/ /beWRRWEWuArwNq_#e83_%,(nV1ƘxfY&-0 0ْ; [ָ9*>{@pXW @*` ^}ii&~P`ž>?\ZgݕjmJƮ>Gh\^ /8P#G`C0/d+]Ϊ+P,hJmhG+r̀@@^ O*%vtX_ At++K B~tS#'kjIRd k0`63jpe|kӕ% ,Y[9wUV`[ Xp`P %{۞Aˠ2Xuεn/9jԶIHq$@Á2Tpd2?  gVZ).6WVA!(X F$F`KZiU@1 ^C96BFloZ*a 'k6$ᆈ99b0fϳ_˲Vog;:T_]nG[9^&Vx8 n^ I 4y*;.RK Ehu N;@@j+g @7CacePF)@zZq4q5-q;;~b?([ iIENDB`plugins-1.5/deprecated/yandexnarodplugin/icons/yandexnarodlogo.png000066400000000000000000000026511336777360500257360ustar00rootroot00000000000000PNG  IHDR%(NgAMA7tEXtSoftwareAdobe ImageReadyqe<PLTEWWWrrr]]]ccc ZBKKK000 ۠'''NNNޢ999ϗ~~~xϴ{{{b<,B0v333K7ɓ̱xxx666---rS̕EEE퍍0#PC#HHH՛`FlllOI:***fffy$F>(```\N)nmiii???^\X2&60!$<0v^+%đ v4uuukrq1JIGwL}r\! H5ZVHnS tBBBƐy,`xUkfY׏q rDphR؞@7v@ZZZ<<<{ooo} ^TTTa[IL9{Z3-ID4$$$LdOtRNS {IDATxtw0m4iiҦ2l]V^y+yӷIc%obYߓdp8OɐփTH^ >~VZ (OU\hT*x;-,IT9)jH9 #include #include "options.h" #include "applicationinfoaccessinghost.h" #include "optionaccessinghost.h" static const QString passwordKey = "yandexnarodpluginkey"; Options * Options ::instance_ = 0; Options ::Options () : QObject(QApplication::instance()) , appInfo(0) , options(0) { } Options ::~Options() { } void Options ::setApplicationInfoAccessingHost(ApplicationInfoAccessingHost *host) { appInfo = host; getProxy(); } void Options ::setOptionAccessingHost(OptionAccessingHost *host) { options = host; } Options * Options ::instance() { if(!instance_) instance_ = new Options(); return instance_; } void Options ::reset() { delete instance_; instance_ = 0; } bool Options ::useProxy() const { bool use = false; if(appInfo) { Proxy p = appInfo->getProxyFor("Yandex Narod Plugin"); use = !p.host.isEmpty(); } return use; } QNetworkProxy Options ::getProxy() const { QNetworkProxy np; if(appInfo) { Proxy p = appInfo->getProxyFor("Yandex Narod Plugin"); np = QNetworkProxy(QNetworkProxy::HttpCachingProxy, p.host, p.port, p.user, p.pass); if(p.type != "http") np.setType(QNetworkProxy::Socks5Proxy); } return np; } void Options::setOption(const QString &name, const QVariant &value) { if(options) { options->setPluginOption(name, value); } } QVariant Options::getOption(const QString &name, const QVariant &def) { QVariant ret(def); if(options) { ret = options->getPluginOption(name, def); } return ret; } void Options::saveCookies(const QList &cooks) { if(options) { QByteArray ba; QDataStream ds(&ba, QIODevice::WriteOnly); foreach(const QNetworkCookie& cookie, cooks) { ds << cookie.toRawForm(QNetworkCookie::NameAndValueOnly); } options->setPluginOption(CONST_COOKIES, ba); } } QList Options::loadCookies() { QList ret; if(options) { QByteArray ba = options->getPluginOption(CONST_COOKIES, QByteArray()).toByteArray(); if(!ba.isEmpty()) { QDataStream ds(&ba, QIODevice::ReadOnly); QByteArray byte; while(!ds.atEnd()) { ds >> byte; QList list = QNetworkCookie::parseCookies(byte); ret += list; } } } return ret; } QString Options::message(MessageType type) { switch(type) { case MAuthStart: return tr("Authorizing..."); case MAuthOk: return tr("Authorizing OK"); case MAuthError: return tr("Authorization failed"); case MCancel: return tr("Canceled"); case MChooseFile: return tr("Choose file"); case MUploading: return tr("Uploading"); case MError: return tr("Error! %1"); case MRemoveCookie: return tr("Cookies are removed"); } return QString(); } QString Options::encodePassword(const QString &pass) { QString result; int n1, n2; if (passwordKey.length() == 0) { return pass; } for (n1 = 0, n2 = 0; n1 < pass.length(); ++n1) { ushort x = pass.at(n1).unicode() ^ passwordKey.at(n2++).unicode(); QString hex; hex.sprintf("%04x", x); result += hex; if(n2 >= passwordKey.length()) { n2 = 0; } } return result; } QString Options::decodePassword(const QString &pass) { QString result; int n1, n2; if (passwordKey.length() == 0) { return pass; } for(n1 = 0, n2 = 0; n1 < pass.length(); n1 += 4) { ushort x = 0; if(n1 + 4 > pass.length()) { break; } x += QString(pass.at(n1)).toInt(NULL,16)*4096; x += QString(pass.at(n1+1)).toInt(NULL,16)*256; x += QString(pass.at(n1+2)).toInt(NULL,16)*16; x += QString(pass.at(n1+3)).toInt(NULL,16); QChar c(x ^ passwordKey.at(n2++).unicode()); result += c; if(n2 >= passwordKey.length()) { n2 = 0; } } return result; } plugins-1.5/deprecated/yandexnarodplugin/options.h000066400000000000000000000041641336777360500225650ustar00rootroot00000000000000/* proxy.h Copyright (c) 2011 by Evgeny Khryukin *************************************************************************** * * * 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. * * * *************************************************************************** */ #ifndef PROXY_H #define PROXY_H #include #include #include "QVariant" class ApplicationInfoAccessingHost; class OptionAccessingHost; #define CONST_COOKIES "cookies" #define CONST_LOGIN "login" #define CONST_PASS_OLD "pass" #define CONST_PASS "pass-encoded" #define CONST_TEMPLATE "template" #define CONST_LAST_FOLDER "lastfolder" #define CONST_WIDTH "width" #define CONST_HEIGHT "height" #define POPUP_OPTION_NAME ".popupinterval" #define VERSION "0.1.4" #define O_M(x) Options::message(x) enum MessageType { MAuthStart, MAuthOk, MAuthError, MCancel, MChooseFile, MUploading, MError, MRemoveCookie }; class Options : public QObject { Q_OBJECT public: static Options * instance(); static void reset(); static QString message(MessageType type); static QString encodePassword(const QString &pass); static QString decodePassword(const QString &pass); void setApplicationInfoAccessingHost(ApplicationInfoAccessingHost* host); void setOptionAccessingHost(OptionAccessingHost* host); void setOption(const QString& name, const QVariant& value); QVariant getOption(const QString& name, const QVariant& def = QVariant::Invalid); QNetworkProxy getProxy() const; bool useProxy() const; void saveCookies(const QList& cooks); QList loadCookies(); private: static Options * instance_; Options (); virtual ~Options(); ApplicationInfoAccessingHost* appInfo; OptionAccessingHost* options; }; #endif // PROXY_H plugins-1.5/deprecated/yandexnarodplugin/requestauthdialog.cpp000066400000000000000000000035521336777360500251570ustar00rootroot00000000000000/* requestAuthDialog Copyright (c) 2008-2009 by Alexander Kazarin 2011 by Evgeny Khryukin *************************************************************************** * * * 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. * * * *************************************************************************** */ #include #include #include #include #include "requestauthdialog.h" #include "options.h" requestAuthDialog::requestAuthDialog(QWidget *parent) : QDialog(parent) , manager_(0) { ui.setupUi(this); setFixedHeight(210); ui.frameCaptcha->hide(); setFixedSize(size()); } requestAuthDialog::~requestAuthDialog() { } void requestAuthDialog::setCaptcha(const QList &cooks, const QString &url) { if(!manager_) { manager_ = new QNetworkAccessManager(this); if(Options::instance()->useProxy()) manager_->setProxy(Options::instance()->getProxy()); connect(manager_, SIGNAL(finished(QNetworkReply*)), SLOT(reply(QNetworkReply*))); } manager_->cookieJar()->setCookiesFromUrl(cooks, url); manager_->get(QNetworkRequest(QUrl(url))); } void requestAuthDialog::reply(QNetworkReply *r) { if(r->error() == QNetworkReply::NoError) { ui.frameCaptcha->show(); ui.labelCaptcha->show(); QPixmap pix = QPixmap::fromImage(QImage::fromData(r->readAll())); ui.webCaptcha->setPixmap(pix); setFixedHeight(350); setFixedSize(size()); } r->deleteLater(); } plugins-1.5/deprecated/yandexnarodplugin/requestauthdialog.h000066400000000000000000000031701336777360500246200ustar00rootroot00000000000000/* requestAuthDialog Copyright (c) 2008 by Alexander Kazarin *************************************************************************** * * * 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. * * * *************************************************************************** */ #ifndef REQUESTAUTHDIALOG_H #define REQUESTAUTHDIALOG_H #include "ui_requestauthdialog.h" #include class QNetworkAccessManager; class QNetworkReply; class requestAuthDialog : public QDialog { Q_OBJECT; public: requestAuthDialog(QWidget *parent = 0); ~requestAuthDialog(); void setLogin(const QString& login) { ui.editLogin->setText(login); ui.editPasswd->setFocus(); } void setPasswd(const QString& passwd) { ui.editPasswd->setText(passwd); ui.editPasswd->setFocus(); } QString getLogin() const { return ui.editLogin->text(); } QString getPasswd() const { return ui.editPasswd->text(); } bool getRemember() const { return ui.cbRemember->isChecked(); } QString getCode() const { return ui.editCaptcha->text(); } void setCaptcha(const QList& cooks, const QString& url); private slots: void reply(QNetworkReply* r); private: Ui::requestAuthDialogClass ui; QNetworkAccessManager *manager_; }; #endif plugins-1.5/deprecated/yandexnarodplugin/requestauthdialog.ui000066400000000000000000000124401336777360500250060ustar00rootroot00000000000000 requestAuthDialogClass 0 0 234 332 128 0 320 15400 Authorization :/icons/yandexnarodplugin.png:/icons/yandexnarodplugin.png Login: 0 0 Password: 0 0 QLineEdit::Password Remember Qt::Vertical 20 40 QFrame::NoFrame QFrame::Raised 0 Captcha: 0 60 0 0 Qt::Horizontal 40 20 QDialogButtonBox::Cancel|QDialogButtonBox::Ok Qt::Horizontal 40 20 buttonBox accepted() requestAuthDialogClass accept() 118 281 118 152 buttonBox rejected() requestAuthDialogClass reject() 118 281 118 152 plugins-1.5/deprecated/yandexnarodplugin/uploaddialog.cpp000066400000000000000000000061571336777360500240750ustar00rootroot00000000000000/* uploadDialog Copyright (c) 2008-2009 by Alexander Kazarin 2011 Evgeny Khryukin *************************************************************************** * * * 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. * * * *************************************************************************** */ #include #include "uploaddialog.h" #include "uploadmanager.h" #include "options.h" uploadDialog::uploadDialog(QWidget *p) : QDialog(p, Qt::MSWindowsFixedSizeDialogHint) { ui.setupUi(this); ui.progressBar->setValue(0); connect(ui.btnUploadCancel, SIGNAL(clicked()), this, SIGNAL(canceled())); connect(ui.btnUploadCancel, SIGNAL(clicked()), this, SLOT(close())); setAttribute(Qt::WA_DeleteOnClose, true); netman = new UploadManager(this); connect(netman, SIGNAL(statusText(QString)), this, SLOT(setStatus(QString))); connect(netman, SIGNAL(transferProgress(qint64,qint64)),this, SLOT(progress(qint64,qint64))); connect(netman, SIGNAL(uploadFileURL(QString)), this, SIGNAL(fileUrl(QString))); connect(netman, SIGNAL(uploaded()), this, SLOT(setDone())); connect(netman, SIGNAL(uploadFileURL(QString)), this, SLOT(setLink(QString))); } uploadDialog::~uploadDialog() { } void uploadDialog::setFilename(const QString& str) { ui.labelFile->setText(tr("File: ") + str); setWindowTitle(O_M(MUploading) + " - " + str); } void uploadDialog::start(const QString& fileName) { QFileInfo fi(fileName); setFilename(fi.fileName()); ui.progressBar->setValue(0); ui.labelLink->setVisible(false); utime.start(); netman->go(fileName); } void uploadDialog::progress(qint64 cBytes, qint64 totalBytes) { ui.labelStatus->setText(O_M(MUploading)+"..."); ui.labelProgress->setText(tr("Progress: ") + QString::number(cBytes) + " / " + QString::number(totalBytes)); ui.progressBar->setMaximum(totalBytes); ui.progressBar->setValue(cBytes); setWindowTitle("[" + ui.progressBar->text() + "] - " + O_M(MUploading)+"..."); QTime etime(0,0,0); int elapsed = utime.elapsed(); etime = etime.addMSecs(elapsed); ui.labelETime->setText(tr("Elapsed time: ") + etime.toString("hh:mm:ss") ); float speed_kbsec = (elapsed == 0) ? 0 : (cBytes / (((float)elapsed)/1000))/1024; if (speed_kbsec > 0) ui.labelSpeed->setText(tr("Speed: ")+QString::number(speed_kbsec)+tr(" kb/sec")); if (cBytes == totalBytes) ui.labelStatus->setText(tr("Upload completed. Waiting for verification.")); } void uploadDialog::setDone() { if(netman->success()) ui.btnUploadCancel->setText(tr("Done")); else ui.btnUploadCancel->setText(tr("Close")); emit finished(); } void uploadDialog::setLink(const QString &link) { ui.labelLink->setVisible(true); ui.labelLink->setText(tr("Link: %2").arg(link, link.left(30)+"...")); } plugins-1.5/deprecated/yandexnarodplugin/uploaddialog.h000066400000000000000000000025441336777360500235360ustar00rootroot00000000000000/* uploadDialog Copyright (c) 2008 by Alexander Kazarin 2011 Evgeny Khryukin *************************************************************************** * * * 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. * * * *************************************************************************** */ #ifndef UPLOADDIALOG_H #define UPLOADDIALOG_H #include #include #include "ui_uploaddialog.h" class UploadManager; class uploadDialog : public QDialog { Q_OBJECT public: uploadDialog(QWidget* p = 0); ~uploadDialog(); void start(const QString& fileName); private: void setFilename(const QString& str); Ui::uploadDialogClass ui; QTime utime; UploadManager* netman; signals: void canceled(); void finished(); void fileUrl(const QString&); private slots: void progress(qint64, qint64); void setStatus(const QString& str) { ui.labelStatus->setText(str); } void setDone(); void setLink(const QString& link); }; #endif plugins-1.5/deprecated/yandexnarodplugin/uploaddialog.ui000066400000000000000000000103231336777360500237160ustar00rootroot00000000000000 uploadDialogClass 0 0 300 218 0 0 300 218 300 218 Uploading... :/icons/yandexnarodplugin.png:/icons/yandexnarodplugin.png Upload started. Qt::AlignCenter File: Qt::PlainText Progress: Elapsed time: Speed: 0 0 Link: true Qt::Vertical 0 0 0 0 0 Qt::Horizontal 40 20 0 0 Cancel Qt::Horizontal 40 20 plugins-1.5/deprecated/yandexnarodplugin/uploadmanager.cpp000066400000000000000000000174731336777360500242530ustar00rootroot00000000000000/* uploadmanger.cpp Copyright (c) 2011 by Evgeny Khryukin *************************************************************************** * * * 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. * * * *************************************************************************** */ #include #include #include #include #include #include #include "uploadmanager.h" #include "common.h" #include "options.h" #include "authmanager.h" static const QString boundary = "AaB03x"; //--------------------------------- //-------HttpDevice---------------- //--------------------------------- class HttpDevice : public QIODevice { public: HttpDevice(const QString& fileName, QObject *p = 0) : QIODevice(p) , totalSize(0) , ioIndex(0) , lastIndex(0) , fileName_(fileName) { QFileInfo fi(fileName_); QByteArray mpData; mpData.append("--" + boundary + "\r\n"); mpData.append("Content-Disposition: form-data; name=\"file\"; filename=\"" + fi.fileName().toUtf8() + "\"\r\n"); mpData.append("Content-Transfer-Encoding: binary\r\n"); mpData.append("\r\n"); appendData(mpData); QFile *device = new QFile(fileName_, this); Range r; r.start = totalSize; r.end = totalSize + device->size() - 1; ioDevices.append(QPair(r, device)); totalSize += device->size(); appendData("\r\n--" + boundary.toLatin1() + "--\r\n"); } ~HttpDevice() { } virtual qint64 size() const { return totalSize; } virtual bool seek(qint64 pos) { if(pos >= totalSize) return false; ioIndex = pos; lastIndex = 0; return QIODevice::seek(pos); } virtual bool open(QIODevice::OpenMode mode) { if(mode != QIODevice::ReadOnly) return false; for(int i = 0; i < ioDevices.size(); i++) { if(!ioDevices.at(i).second->open(mode)) return false; } return QIODevice::open(mode); } protected: virtual qint64 readData(char *data, qint64 len) { if ((len = qMin(len, qint64(totalSize) - ioIndex)) <= 0) return qint64(0); qint64 totalRead = 0; while(len > 0) { if( ioIndex >= ioDevices[lastIndex].first.start && ioIndex <= ioDevices[lastIndex].first.end ) { } else { for(int i = 0 ; i < ioDevices.count() ; ++i) { if( ioIndex >= ioDevices[i].first.start && ioIndex <= ioDevices[i].first.end ) { lastIndex = i; } } } QIODevice * chunk = ioDevices[lastIndex].second; if(!ioDevices[lastIndex].second->seek(ioIndex - ioDevices[lastIndex].first.start)) { qDebug("HttpDevice: Failed to seek inner device"); break; } qint64 bytesLeftInThisChunk = chunk->size() - chunk->pos(); qint64 bytesToReadInThisRequest = qMin(bytesLeftInThisChunk, len); qint64 readLen = chunk->read(data, bytesToReadInThisRequest); if( readLen != bytesToReadInThisRequest ) { qDebug("HttpDevice: Failed to read requested amount of data"); break; } data += bytesToReadInThisRequest; len -= bytesToReadInThisRequest; totalRead += bytesToReadInThisRequest; ioIndex += bytesToReadInThisRequest; } return totalRead; } virtual qint64 writeData(const char */*data*/, qint64 /*len*/) { return -1; } private: struct Range { int start; int end; }; void appendData(const QByteArray& data) { QBuffer * buffer = new QBuffer(this); buffer->setData(data); Range r; r.start = totalSize; r.end = totalSize + data.size() - 1; ioDevices.append(QPair(r, buffer)); totalSize += data.size(); } private: QVector< QPair > ioDevices; int totalSize; qint64 ioIndex; int lastIndex; QString fileName_; }; //----------------------------------------- //-------UploadManager--------------------- //----------------------------------------- UploadManager::UploadManager(QObject* p) : QObject(p) , success_(false) , hd_(0) { manager_ = newManager(this); } UploadManager::~UploadManager() { } void UploadManager::go(const QString& file) { if (file.isEmpty()) { emit statusText(O_M(MCancel)); emit uploaded(); return; } //manager_->cookieJar()->setCookiesFromUrl(Options::instance()->loadCookies(), mainUrl); if(manager_->cookieJar()->cookiesForUrl(mainUrl).isEmpty()) { AuthManager am; emit statusText(O_M(MAuthStart)); bool auth = am.go(Options::instance()->getOption(CONST_LOGIN, "").toString(), Options::decodePassword(Options::instance()->getOption(CONST_PASS, "").toString()) ); if(auth) { setCookies(am.cookies()); Options::instance()->saveCookies(am.cookies()); emit statusText(O_M(MAuthOk)); } else { emit statusText(O_M(MAuthError)); emit uploaded(); return; } } fileName_ = file; QNetworkRequest nr = newRequest(); nr.setUrl(QUrl("http://narod.yandex.ru/disk/getstorage/")); emit statusText(tr("Getting storage...")); QNetworkReply* reply = manager_->get(nr); connect(reply, SIGNAL(finished()), SLOT(getStorageFinished())); } void UploadManager::setCookies(const QList& cookies) { manager_->cookieJar()->setCookiesFromUrl(cookies, mainUrl); } void UploadManager::getStorageFinished() { QNetworkReply *reply = static_cast(sender()); if(reply->error() == QNetworkReply::NoError) { QString page = reply->readAll(); QRegExp rx("\"url\":\"(\\S+)\".+\"hash\":\"(\\S+)\".+\"purl\":\"(\\S+)\""); if (rx.indexIn(page) > -1) { doUpload(QUrl(rx.cap(1) + "?tid=" + rx.cap(2))); } else { emit statusText(tr("Can't get storage")); emit uploaded(); } } else { emit statusText(O_M(MError).arg(reply->errorString())); emit uploaded(); } reply->deleteLater(); } void UploadManager::doUpload(const QUrl &url) { emit statusText(tr("Starting upload...")); hd_ = new HttpDevice(fileName_, this); if(!hd_->open(QIODevice::ReadOnly)) { emit statusText(tr("Error opening file!")); emit uploaded(); return; } QNetworkRequest nr = newRequest(); nr.setUrl(url); nr.setHeader(QNetworkRequest::ContentTypeHeader, "multipart/form-data, boundary=" + boundary.toLatin1()); nr.setHeader(QNetworkRequest::ContentLengthHeader, hd_->size()); QNetworkReply* netrp = manager_->post(nr, hd_); connect(netrp, SIGNAL(uploadProgress(qint64,qint64)), this, SIGNAL(transferProgress(qint64,qint64))); connect(netrp, SIGNAL(finished()), this, SLOT(uploadFinished())); } void UploadManager::uploadFinished() { QNetworkReply *reply = static_cast(sender()); if(reply->error() == QNetworkReply::NoError) { emit statusText(tr("Verifying...")); QNetworkRequest nr = newRequest(); nr.setUrl(QUrl("http://narod.yandex.ru/disk/last/")); QNetworkReply* netrp = manager_->get(nr); connect(netrp, SIGNAL(finished()), SLOT(verifyingFinished())); } else { emit statusText(O_M(MError).arg(reply->errorString())); emit uploaded(); } hd_->deleteLater(); hd_ = 0; reply->deleteLater(); } void UploadManager::verifyingFinished() { QNetworkReply *reply = static_cast(sender()); if(reply->error() == QNetworkReply::NoError) { QString page = reply->readAll(); QRegExp rx("[^<]+
"); if (rx.indexIn(page) != -1) { success_ = true; emit statusText(tr("Uploaded successfully")); QString url = rx.cap(1); emit uploadFileURL(url); } else { emit statusText(tr("Verifying failed")); } } else { emit statusText(O_M(MError).arg(reply->errorString())); } emit uploaded(); reply->deleteLater(); } //#include "uploadmanager.moc" plugins-1.5/deprecated/yandexnarodplugin/uploadmanager.h000066400000000000000000000026711336777360500237120ustar00rootroot00000000000000/* uploadmanger.h Copyright (c) 2011 by Evgeny Khryukin *************************************************************************** * * * 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. * * * *************************************************************************** */ #ifndef UPLOADMANAGER_H #define UPLOADMANAGER_H #include class QNetworkAccessManager; class QFile; class HttpDevice; class UploadManager : public QObject { Q_OBJECT public: UploadManager(QObject* p = 0); ~UploadManager(); void go(const QString& file); void setCookies(const QList& cookies); bool success() const { return success_; }; signals: void transferProgress(qint64, qint64); void uploaded(); void statusText(const QString&); void uploadFileURL(const QString&); private slots: void getStorageFinished(); void uploadFinished(); void verifyingFinished(); private: void doUpload(const QUrl& url); private: QNetworkAccessManager* manager_; QString fileName_; bool success_; HttpDevice *hd_; }; #endif // UPLOADMANAGER_H plugins-1.5/deprecated/yandexnarodplugin/yandexnarod.cpp000066400000000000000000000143171336777360500237420ustar00rootroot00000000000000/* yandexnarodPlugin Copyright (c) 2008-2009 by Alexander Kazarin 2011 Evgeny Khryukin *************************************************************************** * * * 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. * * * *************************************************************************** */ #include #include "yandexnarod.h" #include "yandexnarodmanage.h" #include "authmanager.h" #include "yandexnarodsettings.h" #include "uploaddialog.h" #include "options.h" yandexnarodPlugin::yandexnarodPlugin() : psiOptions(0) , psiIcons(0) , stanzaSender(0) , appInfo(0) , popup(0) , enabled(false) , currentAccount(-1) , popupId(0) { } QString yandexnarodPlugin::name() const { return "Yandex Narod Plugin"; } QString yandexnarodPlugin::shortName() const { return "yandexnarod"; } QString yandexnarodPlugin::version() const { return VERSION; } QWidget* yandexnarodPlugin::options() { if(!enabled) { return 0; } settingswidget = new yandexnarodSettings(); connect(settingswidget, SIGNAL(testclick()), this, SLOT(on_btnTest_clicked())); connect(settingswidget, SIGNAL(startManager()), this, SLOT(manage_clicked())); return settingswidget; } bool yandexnarodPlugin::enable() { enabled = true; QFile file(":/icons/yandexnarodplugin.png"); file.open(QIODevice::ReadOnly); QByteArray image = file.readAll(); psiIcons->addIcon("yandexnarod/logo",image); file.close(); Options::instance()->setApplicationInfoAccessingHost(appInfo); Options::instance()->setOptionAccessingHost(psiOptions); //remove old password option QString oldPass = Options::instance()->getOption(CONST_PASS_OLD).toString(); if(!oldPass.isEmpty()) { Options::instance()->setOption(CONST_PASS_OLD, QVariant("")); Options::instance()->setOption(CONST_PASS, Options::encodePassword(oldPass)); } popupId = popup->registerOption(name(), 3, "plugins.options." + shortName() + POPUP_OPTION_NAME); return enabled; } bool yandexnarodPlugin::disable() { enabled = false; if(manageDialog) delete manageDialog; if(uploadwidget) { uploadwidget->disconnect(); delete uploadwidget; } popup->unregisterOption(name()); Options::reset(); return true; } void yandexnarodPlugin::setOptionAccessingHost(OptionAccessingHost* host) { psiOptions = host; } void yandexnarodPlugin::setIconFactoryAccessingHost(IconFactoryAccessingHost *host) { psiIcons = host; } void yandexnarodPlugin::setStanzaSendingHost(StanzaSendingHost *host) { stanzaSender = host; } void yandexnarodPlugin::setApplicationInfoAccessingHost(ApplicationInfoAccessingHost *host) { appInfo = host; } void yandexnarodPlugin::setPopupAccessingHost(PopupAccessingHost *host) { popup = host; } void yandexnarodPlugin::applyOptions() { if(settingswidget) settingswidget->saveSettings(); } void yandexnarodPlugin::restoreOptions() { if(settingswidget) settingswidget->restoreSettings(); } QList < QVariantHash > yandexnarodPlugin::getAccountMenuParam() { QList < QVariantHash > list; QVariantHash hash; hash["icon"] = QVariant(QString("yandexnarod/logo")); hash["name"] = QVariant(tr("Open Yandex Narod Manager")); hash["reciver"] = qVariantFromValue(qobject_cast(this)); hash["slot"] = QVariant(SLOT(manage_clicked())); list.append(hash); return list; } QList < QVariantHash > yandexnarodPlugin::getContactMenuParam() { QList < QVariantHash > list; QVariantHash hash; hash["icon"] = QVariant(QString("yandexnarod/logo")); hash["name"] = QVariant(tr("Send file via Yandex Narod")); hash["reciver"] = qVariantFromValue(qobject_cast(this)); hash["slot"] = QVariant(SLOT(actionStart())); list.append(hash); return list; } void yandexnarodPlugin::manage_clicked() { if(!manageDialog) { manageDialog = new yandexnarodManage(); manageDialog->show(); } else { manageDialog->raise(); manageDialog->activateWindow(); } } void yandexnarodPlugin::on_btnTest_clicked() { if(!settingswidget) return; AuthManager am; settingswidget->setStatus(O_M(MAuthStart)); bool auth = am.go(settingswidget->getLogin(), settingswidget->getPasswd()); QString rez = auth ? O_M(MAuthOk) : O_M(MAuthError); settingswidget->setStatus(rez); if(auth) { Options::instance()->saveCookies(am.cookies()); } } void yandexnarodPlugin::actionStart() { currentJid = sender()->property("jid").toString(); currentAccount = sender()->property("account").toInt(); QString filepath = QFileDialog::getOpenFileName(uploadwidget, O_M(MChooseFile), psiOptions->getPluginOption(CONST_LAST_FOLDER).toString()); if (!filepath.isEmpty()) { fi = QFileInfo(filepath); psiOptions->setPluginOption(CONST_LAST_FOLDER, fi.dir().path()); uploadwidget = new uploadDialog(); connect(uploadwidget, SIGNAL(fileUrl(QString)), this, SLOT(onFileURL(QString))); uploadwidget->show(); uploadwidget->start(filepath); } } void yandexnarodPlugin::onFileURL(const QString& url) { QString sendmsg = psiOptions->getPluginOption(CONST_TEMPLATE).toString(); sendmsg.replace("%N", fi.fileName()); sendmsg.replace("%U", url); sendmsg.replace("%S", QString::number(fi.size())); uploadwidget->close(); if(currentAccount != -1 && !currentJid.isEmpty()) { stanzaSender->sendMessage(currentAccount, currentJid, stanzaSender->escape(sendmsg), "", "chat"); showPopup(currentAccount, currentJid, tr("File sent to %1").arg(currentJid)); } currentJid.clear(); currentAccount = -1; } void yandexnarodPlugin::showPopup(int/* account*/, const QString&/* jid*/, const QString& text) { if(popup->popupDuration(name())) { popup->initPopup(text, tr("Yandex Narod Plugin"), "yandexnarod/logo", popupId); } } QString yandexnarodPlugin::pluginInfo() { return trUtf8("Ported from QutIM Yandex.Narod plugin\nhttp://qutim.org/forum/viewtopic.php?f=62&t=711\n\n"); } QPixmap yandexnarodPlugin::icon() const { return QPixmap(":/icons/yandexnarodplugin.png"); } Q_EXPORT_PLUGIN(yandexnarodPlugin); plugins-1.5/deprecated/yandexnarodplugin/yandexnarod.h000066400000000000000000000064451336777360500234120ustar00rootroot00000000000000/* yandexnarodPlugin Copyright (c) 2008-2009 by Alexander Kazarin 2011 Evgeny Khryukin *************************************************************************** * * * 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. * * * *************************************************************************** */ #ifndef YANDEXNARODPLUGIN_H #define YANDEXNARODPLUGIN_H class QAction; #include "psiplugin.h" #include "optionaccessinghost.h" #include "optionaccessor.h" #include "menuaccessor.h" #include "iconfactoryaccessinghost.h" #include "iconfactoryaccessor.h" #include "stanzasender.h" #include "stanzasendinghost.h" #include "plugininfoprovider.h" #include "applicationinfoaccessinghost.h" #include "applicationinfoaccessor.h" #include "popupaccessinghost.h" #include "popupaccessor.h" class yandexnarodSettings; class uploadDialog; class yandexnarodManage; class yandexnarodPlugin : public QObject, public PsiPlugin, public OptionAccessor, public MenuAccessor , public IconFactoryAccessor , public StanzaSender, public PluginInfoProvider , public ApplicationInfoAccessor, public PopupAccessor { Q_OBJECT Q_INTERFACES(PsiPlugin OptionAccessor MenuAccessor IconFactoryAccessor StanzaSender PluginInfoProvider ApplicationInfoAccessor PopupAccessor) public: yandexnarodPlugin(); virtual QString name() const; virtual QString shortName() const; virtual QString version() const; virtual QWidget* options(); virtual bool enable(); virtual bool disable(); virtual void setOptionAccessingHost(OptionAccessingHost* host); virtual void setIconFactoryAccessingHost(IconFactoryAccessingHost* host); virtual void setStanzaSendingHost(StanzaSendingHost* host); virtual void setApplicationInfoAccessingHost(ApplicationInfoAccessingHost* host); virtual void setPopupAccessingHost(PopupAccessingHost* host); virtual void optionChanged(const QString& /*option*/) {}; virtual void applyOptions(); virtual void restoreOptions(); virtual QList < QVariantHash > getAccountMenuParam(); virtual QList < QVariantHash > getContactMenuParam(); virtual QAction* getContactAction(QObject* /*parent*/, int /*account*/, const QString& /*contact*/) { return 0; }; virtual QAction* getAccountAction(QObject* /*parent*/, int /*account*/) { return 0; }; virtual QString pluginInfo(); virtual QPixmap icon() const; private slots: void manage_clicked(); void on_btnTest_clicked(); void actionStart(); void onFileURL(const QString& url); private: void showPopup(int account, const QString& jid, const QString& text); private: OptionAccessingHost* psiOptions; IconFactoryAccessingHost* psiIcons; StanzaSendingHost* stanzaSender; ApplicationInfoAccessingHost* appInfo; PopupAccessingHost* popup; bool enabled; QString currentJid; int currentAccount; int popupId; QPointer uploadwidget; QPointer settingswidget; QPointer manageDialog; QFileInfo fi; }; #endif plugins-1.5/deprecated/yandexnarodplugin/yandexnarod.qrc000066400000000000000000000006721336777360500237440ustar00rootroot00000000000000 icons/yandexnarodlogo.png icons/yandexnarodplugin.png icons/yandexnarod-icons-files.png icons/upload.png icons/clipboard.png icons/close.png icons/delete.png icons/reload.png icons/prolongate.png plugins-1.5/deprecated/yandexnarodplugin/yandexnarodmanage.cpp000066400000000000000000000240361336777360500251120ustar00rootroot00000000000000/* yandexnarodManage Copyright (c) 2009 by Alexander Kazarin 2011 by Evgeny Khryukin *************************************************************************** * * * 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. * * * *************************************************************************** */ #include #include #include #include #include #include #include #include #include "yandexnarodmanage.h" #include "uploaddialog.h" #include "optionaccessinghost.h" #include "yandexnarodsettings.h" #include "options.h" #include "ui_yandexnarodmanage.h" //------------------------------------------ //-------ListWidgetItem--------------------- //------------------------------------------ class ListWidgetItem : public QListWidgetItem { public: ListWidgetItem(const QIcon& ico, const yandexnarodNetMan::FileItem& fileitem) : QListWidgetItem(ico, fileitem.filename) , item_(fileitem) { QString toolTip = QObject::tr("Name: %1\nSize: %2\nDate prolongate: %3\nURL: %4\nPassword: %5") .arg(fileitem.filename) .arg( QString(fileitem.size).replace(" ", " ") ) .arg(fileitem.date) .arg(fileitem.fileurl) .arg(fileitem.passset ? QObject::tr("Yes") : QObject::tr("No")); setToolTip(toolTip); } const yandexnarodNetMan::FileItem& fileItem() const { return item_; } private: yandexnarodNetMan::FileItem item_; }; //------------------------------------------ //-------ListWidget------------------------- //------------------------------------------ ListWidget::ListWidget(QWidget* p) : QListWidget(p) { } QStringList ListWidget::mimeTypes() const { return QStringList() << "text/plain"; } QMimeData* ListWidget::mimeData(const QList items) const { if(items.isEmpty()) return 0; QMimeData* d = new QMimeData(); QString text; foreach(QListWidgetItem *i, items) { text += static_cast(i)->fileItem().fileurl + "\n"; } d->setText(text); return d; } void ListWidget::mousePressEvent(QMouseEvent *event) { QListWidget::mousePressEvent(event); if(event->button() == Qt::RightButton) { QListWidgetItem *lwi = itemAt(event->pos()); if(lwi) { ListWidgetItem *it = static_cast(lwi); emit menu(it->fileItem()); event->accept(); } } } static QStringList files(const QMimeData *md) { QString str = QFile::decodeName(QByteArray::fromPercentEncoding(md->data("text/uri-list"))); QRegExp re("file://(.+)"); QStringList files; int index = re.indexIn(str); while(index != -1) { files.append(re.cap(1).trimmed()); index = re.indexIn(str, index+1); } return files; } void ListWidget::dragEnterEvent(QDragEnterEvent *event) { const QMimeData *md = event->mimeData(); QStringList list = files(md); bool ok = false; if(list.size() == 1) { QFile file(list.takeFirst()); if(file.exists()) { ok = true; } } if(ok) { event->acceptProposedAction(); } } void ListWidget::dropEvent(QDropEvent *event) { QStringList list = files(event->mimeData()); if(list.size() == 1) { const QString path = list.takeFirst(); QFile file(path); if(file.exists()) emit uploadFile(path); } event->setDropAction(Qt::IgnoreAction); event->accept(); } //------------------------------------------ //-------yandexnarodManage------------------ //------------------------------------------ yandexnarodManage::yandexnarodManage(QWidget* p) : QDialog(p, Qt::Window) , ui_(new Ui::yandexnarodManageClass) { ui_->setupUi(this); setWindowTitle(tr("Yandex.Narod file manager")); setWindowIcon(QIcon(":/icons/yandexnarodplugin.png")); ui_->frameProgress->hide(); ui_->frameFileActions->hide(); ui_->listWidget->clear(); ui_->btnOpenBrowser->setIcon(qApp->style()->standardIcon(QStyle::SP_BrowserReload)); newNetMan(); QPixmap iconimage(":/icons/yandexnarod-icons-files.png"); for (int i=0; i<(iconimage.width()/16); i++) { QIcon icon(iconimage.copy((i*16),0,16,16)); fileicons.append(icon); } fileiconstyles["b-icon-music"] = 0; fileiconstyles["b-icon-video"] = 1; fileiconstyles["b-icon-arc"] = 2; fileiconstyles["b-icon-doc"] = 3; fileiconstyles["b-icon-soft"] = 4; fileiconstyles["b-icon-unknown"] = 5; fileiconstyles["b-icon-picture"] = 14; Options* o = Options::instance(); int h = o->getOption(CONST_HEIGHT, 200).toInt(); int w = o->getOption(CONST_WIDTH, 300).toInt(); resize(w, h); setAttribute(Qt::WA_QuitOnClose, false); setAttribute(Qt::WA_DeleteOnClose, true); connect(ui_->listWidget, SIGNAL(menu(yandexnarodNetMan::FileItem)), SLOT(doMenu(yandexnarodNetMan::FileItem))); connect(ui_->listWidget, SIGNAL(uploadFile(QString)), this, SLOT(uploadFile(QString)), Qt::QueuedConnection); } yandexnarodManage::~yandexnarodManage() { Options* o = Options::instance(); o->setOption(CONST_HEIGHT, height()); o->setOption(CONST_WIDTH, width()); delete ui_; } void yandexnarodManage::newNetMan() { netman = new yandexnarodNetMan(this); connect(netman, SIGNAL(statusText(QString)), ui_->labelStatus, SLOT(setText(QString))); connect(netman, SIGNAL(newFileItem(yandexnarodNetMan::FileItem)), this, SLOT(newFileItem(yandexnarodNetMan::FileItem))); connect(netman, SIGNAL(finished()), this, SLOT(netmanFinished())); } void yandexnarodManage::newFileItem(yandexnarodNetMan::FileItem fileitem) { int iconnum = 5; QString fileiconname = fileitem.fileicon.replace("-old", ""); if (fileiconstyles.contains(fileiconname)) iconnum = fileiconstyles[fileiconname]; QListWidgetItem *listitem = new ListWidgetItem(fileicons[iconnum], fileitem); ui_->listWidget->addItem(listitem); } void yandexnarodManage::netmanPrepare() { ui_->frameProgress->show(); ui_->labelStatus->clear(); ui_->frameFileActions->hide(); ui_->btnReload->setEnabled(false); } void yandexnarodManage::netmanFinished() { ui_->btnReload->setEnabled(true); } void yandexnarodManage::on_btnReload_clicked() { ui_->listWidget->clear(); netmanPrepare(); netman->startGetFilelist(); } void yandexnarodManage::on_btnDelete_clicked() { QList out; foreach(QListWidgetItem* i, ui_->listWidget->selectedItems()) { ListWidgetItem* lwi = static_cast(i); yandexnarodNetMan::FileItem &f = const_cast(lwi->fileItem()); if(!f.deleted) { out.append(f); f.deleted = true; } } if(out.isEmpty()) return; int rez = QMessageBox::question(this, tr("Delete file(s)"), tr("Are you sure?"), QMessageBox::Ok | QMessageBox::Cancel); if(rez == QMessageBox::Cancel) return; foreach(QListWidgetItem* i, ui_->listWidget->selectedItems()) { i->setIcon(fileicons[15]); } netmanPrepare(); netman->startDelFiles(out); } void yandexnarodManage::on_btnProlong_clicked() { netmanPrepare(); QList out; foreach(QListWidgetItem* i, ui_->listWidget->selectedItems()) { ListWidgetItem* lwi = static_cast(i); yandexnarodNetMan::FileItem f = lwi->fileItem(); if(f.prolong() < 45) { out.append(f); } } netman->startProlongFiles(out); } void yandexnarodManage::on_btnClearCookies_clicked() { netman->disconnect(); netman->deleteLater(); Options::instance()->saveCookies(QList()); newNetMan(); ui_->frameProgress->show(); ui_->labelStatus->setText(O_M(MRemoveCookie)); } void yandexnarodManage::on_btnOpenBrowser_clicked() { QDesktopServices::openUrl(QUrl("http://narod.yandex.ru/disk/all/")); } void yandexnarodManage::on_listWidget_pressed(QModelIndex) { if (ui_->frameFileActions->isHidden()) ui_->frameFileActions->show(); bool prolong = false; foreach(QListWidgetItem* i, ui_->listWidget->selectedItems()) { ListWidgetItem* lwi = static_cast(i); if(lwi->fileItem().prolong() < 45) { prolong = true; break; } } ui_->btnProlong->setEnabled(prolong); } void yandexnarodManage::on_btnClipboard_clicked() { QStringList text; foreach(QListWidgetItem* i, ui_->listWidget->selectedItems()) { text << static_cast(i)->fileItem().fileurl; } copyToClipboard(text.join("\n")); } void yandexnarodManage::copyToClipboard(const QString &text) { QClipboard *clipboard = QApplication::clipboard(); clipboard->setText(text); } void yandexnarodManage::on_btnUpload_clicked() { QString filePath = QFileDialog::getOpenFileName(this, O_M(MChooseFile), Options::instance()->getOption(CONST_LAST_FOLDER).toString()); if (!filePath.isEmpty()) { QFileInfo fi(filePath); Options::instance()->setOption(CONST_LAST_FOLDER, fi.dir().path()); uploadFile(filePath); } } void yandexnarodManage::uploadFile(const QString &path) { uploadDialog* uploadwidget = new uploadDialog(this); connect(uploadwidget, SIGNAL(canceled()), this, SLOT(netmanFinished())); connect(uploadwidget, SIGNAL(finished()), this, SLOT(netmanFinished())); uploadwidget->show(); uploadwidget->start(path); } void yandexnarodManage::doMenu(const yandexnarodNetMan::FileItem &it) { QMenu m; QList actions; QAction *act = new QAction(tr("Set password"), &m); act->setVisible(!it.passset); act->setData(1); actions << act; act = new QAction(tr("Remove password"), &m); act->setVisible(it.passset); act->setData(2); actions << act; act = new QAction(tr("Copy URL"), &m); act->setData(3); actions << act; act = new QAction(tr("Prolongate"), &m); act->setData(4); act->setEnabled(it.prolong() < 45); actions << act; m.addActions(actions); QAction* ret = m.exec(QCursor::pos()); if(ret) { switch(ret->data().toInt()) { case 1: netman->startSetPass(it); break; case 2: netman->startRemovePass(it); break; case 3: copyToClipboard(it.fileurl); break; case 4: netman->startProlongFiles(QList() << it); default: break; } } } plugins-1.5/deprecated/yandexnarodplugin/yandexnarodmanage.h000066400000000000000000000042151336777360500245540ustar00rootroot00000000000000/* yandexnarodManage Copyright (c) 2009 by Alexander Kazarin 2011 by Evgeny Khryukin *************************************************************************** * * * 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. * * * *************************************************************************** */ #ifndef YANDEXNARODMANAGE_H #define YANDEXNARODMANAGE_H #include #include #include "yandexnarodnetman.h" namespace Ui { class yandexnarodManageClass; } class ListWidget : public QListWidget { Q_OBJECT public: ListWidget(QWidget* p = 0); protected: virtual QStringList mimeTypes() const; virtual QMimeData *mimeData(const QList items) const; virtual void mousePressEvent(QMouseEvent *event); virtual void dragEnterEvent(QDragEnterEvent *event); virtual void dropEvent(QDropEvent *event); signals: void menu(const yandexnarodNetMan::FileItem&); void uploadFile(const QString&); }; class yandexnarodManage : public QDialog { Q_OBJECT public: yandexnarodManage(QWidget* p = 0); ~yandexnarodManage(); private: void newNetMan(); void netmanPrepare(); void copyToClipboard(const QString& text); private slots: void newFileItem(yandexnarodNetMan::FileItem); void on_btnDelete_clicked(); void on_btnClipboard_clicked(); void on_listWidget_pressed(QModelIndex index); void on_btnReload_clicked(); void on_btnUpload_clicked(); void on_btnProlong_clicked(); void on_btnClearCookies_clicked(); void on_btnOpenBrowser_clicked(); void netmanFinished(); void doMenu(const yandexnarodNetMan::FileItem& item); void uploadFile(const QString& path); private: Ui::yandexnarodManageClass* ui_; yandexnarodNetMan *netman; QList fileicons; QHash fileiconstyles; }; #endif plugins-1.5/deprecated/yandexnarodplugin/yandexnarodmanage.ui000066400000000000000000000274451336777360500247540ustar00rootroot00000000000000 yandexnarodManageClass 0 0 555 452 502 284 Form QLayout::SetDefaultConstraint 0 0 170 0 170 16777215 Get Filelist :/icons/reload.png:/icons/reload.png 0 0 170 0 170 16777215 Upload File :/icons/upload.png:/icons/upload.png 0 0 170 98 170 16777215 QFrame::NoFrame QFrame::Plain 0 QLayout::SetDefaultConstraint 0 Actions: 0 0 16777215 16777215 Copy URL :/icons/clipboard.png:/icons/clipboard.png false 0 0 Prolongate :/icons/prolongate.png:/icons/prolongate.png 0 0 0 0 16777215 16777215 Delete File(s) :/icons/delete.png:/icons/delete.png Qt::Vertical 20 40 Qt::Vertical 20 40 0 0 170 80 170 50 QFrame::NoFrame QFrame::Plain 0 line1 line2 true QLayout::SetDefaultConstraint 0 0 Files list: 0 0 QFrame::Box true QAbstractItemView::DragDrop QAbstractItemView::ExtendedSelection New Item Clear Cookies :/icons/delete.png:/icons/delete.png Open Browser Qt::Horizontal 40 20 0 0 Close :/icons/close.png:/icons/close.png ListWidget QListWidget
yandexnarodmanage.h
btnExit clicked() yandexnarodManageClass close() 79 458 321 241
plugins-1.5/deprecated/yandexnarodplugin/yandexnarodnetman.cpp000066400000000000000000000226021336777360500251410ustar00rootroot00000000000000/* yandexnarodNetMan Copyright (c) 2008-2009 by Alexander Kazarin 2011 by Evgeny Khryukin *************************************************************************** * * * 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. * * * *************************************************************************** */ #include #include #include #include "yandexnarodnetman.h" #include "authmanager.h" #include "options.h" #include "common.h" // function needed for tests only //static void saveData(const QString& text) //{ // //qDebug() << text; // QFile file(QDir::homePath() + "/page.html"); // if(file.open(QIODevice::WriteOnly | QIODevice::Truncate) ) { // QTextStream str(&file); // str << text; // } //} //------------------------------------------- //------GetPassDlg--------------------------- //------------------------------------------- class GetPassDlg : public QDialog { Q_OBJECT public: GetPassDlg(QWidget *p = 0) : QDialog(p) , lePass(new QLineEdit) , leConfirmPass(new QLineEdit) { setWindowTitle(tr("Set Password")); lePass->setEchoMode(QLineEdit::Password); leConfirmPass->setEchoMode(QLineEdit::Password); QDialogButtonBox *bb = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); QVBoxLayout* l = new QVBoxLayout(this); l->addWidget(new QLabel(tr("Password:"))); l->addWidget(lePass); l->addWidget(new QLabel(tr("Confirm password:"))); l->addWidget(leConfirmPass); l->addWidget(bb); connect(bb, SIGNAL(rejected()), SLOT(reject())); connect(bb, SIGNAL(accepted()), SLOT(okPressed())); adjustSize(); setFixedSize(size()); show(); } QString password() const { return lePass->text(); } private slots: void okPressed() { if(isPassOk()) { accept(); } else { QToolTip::showText(pos() + leConfirmPass->pos(), tr("Password does not match"), leConfirmPass); } } private: bool isPassOk() const { return lePass->text() == leConfirmPass->text(); } private: QLineEdit *lePass, *leConfirmPass; }; //----------------------------------------- //-------yandexnarodNetMan----------------- //----------------------------------------- yandexnarodNetMan::yandexnarodNetMan(QObject *parent) : QObject(parent) { netman = newManager(this); netman->cookieJar()->setCookiesFromUrl(Options::instance()->loadCookies(), mainUrl); connect(netman, SIGNAL(finished(QNetworkReply*)), this, SLOT(netrpFinished(QNetworkReply*))); } yandexnarodNetMan::~yandexnarodNetMan() { } bool yandexnarodNetMan::startAuth(const QString& login, const QString& passwd) { AuthManager am; emit statusText(O_M(MAuthStart)); bool auth = am.go(login, passwd); if(auth) { netman->cookieJar()->setCookiesFromUrl(am.cookies(), mainUrl); Options::instance()->saveCookies(am.cookies()); emit statusText(O_M(MAuthOk)); } else { emit statusText(O_M(MAuthError)); } return auth; } void yandexnarodNetMan::startGetFilelist() { action = GetFiles; netmanDo(); } void yandexnarodNetMan::startDelFiles(const QList& fileItems_) { if(fileItems_.isEmpty()) { emit finished(); return; } action = DeleteFiles; netmanDo(fileItems_); } void yandexnarodNetMan::startProlongFiles(const QList& fileItems_) { if(fileItems_.isEmpty()) { emit finished(); return; } action = ProlongateFiles; netmanDo(fileItems_); } void yandexnarodNetMan::startSetPass(const FileItem &item) { if(item.passset) { emit finished(); return; } action = SetPass; netmanDo(QList() << item); } void yandexnarodNetMan::startRemovePass(const FileItem &item) { if(!item.passset) { emit finished(); return; } action = RemovePass; netmanDo(QList() << item); } void yandexnarodNetMan::netmanDo(QList fileItems) { QNetworkCookieJar *netcookjar = netman->cookieJar(); QList cookList = netcookjar->cookiesForUrl(mainUrl); if (cookList.isEmpty()) { bool auth = startAuth(Options::instance()->getOption(CONST_LOGIN, "").toString(), Options::decodePassword(Options::instance()->getOption(CONST_PASS, "").toString()) ); if(!auth) return; } switch(action) { case GetFiles: { emit statusText(tr("Downloading filelist...")); QNetworkRequest nr = newRequest(); nr.setUrl(QUrl("http://narod.yandex.ru/disk/all/page1/?sort=cdate%20desc")); netman->get(nr); break; } case DeleteFiles: case ProlongateFiles: { emit statusText((action == DeleteFiles) ? tr("Deleting files...") : tr("Prolongate files...")); QByteArray postData; postData.append((action == DeleteFiles) ? "action=delete" : "action=prolongate"); foreach (const FileItem& item, fileItems) { postData.append(QString("&fid=%1&token-%1=%2").arg(item.fileid, item.token)); } QNetworkRequest nr = newRequest(); nr.setUrl(QUrl("http://narod.yandex.ru/disk/all")); nr.setHeader(QNetworkRequest::ContentLengthHeader, postData.length()); nr.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); netman->post(nr, postData); break; } case SetPass: { GetPassDlg gpd; if(gpd.exec() == QDialog::Accepted) { QNetworkRequest nr = newRequest(); nr.setUrl(QUrl("http://narod.yandex.ru/disk/setpasswd/" + fileItems.first().fileid)); const QString pass = gpd.password(); QByteArray post; post.append("passwd=" + pass); post.append("&token=" + fileItems.first().passtoken); nr.setHeader(QNetworkRequest::ContentLengthHeader, post.length()); nr.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); netman->post(nr, post); } else { emit statusText(O_M(MCancel)); emit finished(); } break; } case RemovePass: { QNetworkRequest nr = newRequest(); nr.setUrl(QUrl("http://narod.yandex.ru/disk/setpasswd/" + fileItems.first().fileid)); QByteArray post; post.append("passwd=&token=" + fileItems.first().passtoken); nr.setHeader(QNetworkRequest::ContentLengthHeader, post.length()); nr.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); netman->post(nr, post); break; } default: break; } } void yandexnarodNetMan::netrpFinished(QNetworkReply* reply) { if(reply->error() == QNetworkReply::NoError) { QString page = reply->readAll(); switch(action) { case GetFiles: { static bool firstTry = true; if(page.isEmpty()) { if(firstTry) { firstTry = false; emit statusText(tr("Cookies are obsolete!\nReathorization...")); QNetworkCookieJar *jar = netman->cookieJar(); delete jar; jar = new QNetworkCookieJar(netman); netman->setCookieJar(jar); netmanDo(); } else { emit statusText(tr("Can't get files!\nTry remove cookies.")); } emit finished(); reply->deleteLater(); return; } else { firstTry = true; page.replace("", ""); int cpos = 0; static int count = 0; QRegExp rx("class=\"\\S+icon\\s(\\S+)\"[^<]+([^<]+).*" "(\\S+).*data-token=\"(\\S+)\".*([^>]+)"); rx.setMinimal(true); cpos = rx.indexIn(page); while (cpos != -1) { FileItem fileitem; QTextDocument doc; doc.setHtml(QString::fromUtf8(rx.cap(5).toLatin1())); fileitem.filename = doc.toPlainText(); fileitem.fileid = rx.cap(2); fileitem.token = rx.cap(3); fileitem.fileurl = rx.cap(4); fileitem.fileicon = rx.cap(1); fileitem.size = QString::fromUtf8(rx.cap(6).toLatin1()); fileitem.passtoken = rx.cap(7); fileitem.passset = (rx.cap(8) == "b-old-icon b-old-icon-pwd-on"); fileitem.date = QString::fromUtf8(rx.cap(9).toLatin1()); emit newFileItem(fileitem); cpos = rx.indexIn(page, cpos+1); ++count; } QRegExp rxnp(" 0 && rxnp.capturedTexts()[1].length()) { QNetworkRequest nr = newRequest(); nr.setUrl(QUrl("http://narod.yandex.ru"+rxnp.cap(1))); netman->get(nr); } else { emit statusText(QString(tr("Filelist downloaded\n(%1 files)")).arg(QString::number(count))); emit finished(); count = 0; } } break; } case DeleteFiles: { emit statusText(tr("File(s) deleted")); emit finished(); break; } case ProlongateFiles: { emit statusText(tr("File(s) prolongated")); emit finished(); break; } case SetPass: { emit statusText(tr("Password is set")); emit finished(); break; } case RemovePass: { emit statusText(tr("Password is deleted")); emit finished(); break; } default: emit finished(); break; } } else { emit statusText(O_M(MError).arg(reply->errorString())); emit finished(); } reply->deleteLater(); } #include "yandexnarodnetman.moc" plugins-1.5/deprecated/yandexnarodplugin/yandexnarodnetman.h000066400000000000000000000040521336777360500246050ustar00rootroot00000000000000/* yandexnarodNetMan Copyright (c) 2009 by Alexander Kazarin 2011 by Evgeny Khryukin *************************************************************************** * * * 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. * * * *************************************************************************** */ #ifndef YANDEXNARODNETMAN_H #define YANDEXNARODNETMAN_H #include class QNetworkAccessManager; class QNetworkReply; class yandexnarodNetMan : public QObject { Q_OBJECT public: yandexnarodNetMan(QObject *parent); ~yandexnarodNetMan(); struct FileItem { FileItem() { deleted = false; } int prolong() const { int d = 1; QRegExp re("(\\d+) \\S+"); if(re.indexIn(date) != -1) { d = re.cap(1).toInt(); } return d; } QString fileicon; QString fileid; QString filename; QString fileurl; QString token; QString size; QString date; QString passtoken; bool passset; bool deleted; }; bool startAuth(const QString& login, const QString& pass); void startGetFilelist(); void startDelFiles(const QList& fileItems); void startProlongFiles(const QList& fileItems); void startSetPass(const FileItem& item); void startRemovePass(const FileItem& item); private: enum Actions { NoAction = 0, GetFiles, DeleteFiles, ProlongateFiles, SetPass, RemovePass }; void netmanDo(QList fileItems = QList()); private slots: void netrpFinished(QNetworkReply*); signals: void statusText(const QString&); void newFileItem(yandexnarodNetMan::FileItem); void finished(); private: Actions action; QNetworkAccessManager *netman; }; #endif // YANDEXNARODNETMAN_H plugins-1.5/deprecated/yandexnarodplugin/yandexnarodplugin.pro000066400000000000000000000013121336777360500251660ustar00rootroot00000000000000include(../../psiplugin.pri) CONFIG += release QT += network INCLUDEPATH += $$PWD DEPENDPATH += $$PWD HEADERS += yandexnarod.h \ requestauthdialog.h \ uploaddialog.h \ yandexnarodsettings.h \ yandexnarodmanage.h \ yandexnarodnetman.h \ options.h \ uploadmanager.h \ authmanager.h \ common.h SOURCES += yandexnarod.cpp \ requestauthdialog.cpp \ uploaddialog.cpp \ yandexnarodsettings.cpp \ yandexnarodmanage.cpp \ yandexnarodnetman.cpp \ options.cpp \ uploadmanager.cpp \ authmanager.cpp \ common.cpp RESOURCES += yandexnarod.qrc FORMS += requestauthdialog.ui \ uploaddialog.ui \ yandexnarodsettings.ui \ yandexnarodmanage.ui plugins-1.5/deprecated/yandexnarodplugin/yandexnarodsettings.cpp000066400000000000000000000040451336777360500255200ustar00rootroot00000000000000/* yandexnarodPluginSettings Copyright (c) 2009 by Alexander Kazarin 2011 by Evgeny Khryukin *************************************************************************** * * * 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. * * * *************************************************************************** */ #include "yandexnarodsettings.h" #include "optionaccessinghost.h" #include "options.h" yandexnarodSettings::yandexnarodSettings(QWidget *p) : QWidget(p) { ui.setupUi(this); ui.labelStatus->setText(NULL); restoreSettings(); connect(ui.btnTest, SIGNAL(clicked()), this, SLOT(saveSettings())); connect(ui.btnTest, SIGNAL(clicked()), this, SIGNAL(testclick())); connect(ui.pb_startManager, SIGNAL(clicked()), this, SIGNAL(startManager())); } yandexnarodSettings::~yandexnarodSettings() { } void yandexnarodSettings::saveSettings() { Options* o = Options::instance(); o->setOption(CONST_LOGIN, ui.editLogin->text()); o->setOption(CONST_PASS, Options::encodePassword(ui.editPasswd->text())); o->setOption(CONST_TEMPLATE, ui.textTpl->toPlainText()); } void yandexnarodSettings::setStatus(const QString& str) { ui.labelStatus->setText(str); } void yandexnarodSettings::restoreSettings() { Options* o = Options::instance(); ui.editLogin->setText(o->getOption(CONST_LOGIN).toString()); ui.editPasswd->setText(Options::decodePassword(o->getOption(CONST_PASS).toString())); ui.textTpl->setText(o->getOption(CONST_TEMPLATE, QVariant("File sent: %N (%S bytes)\n%U")).toString()); } void yandexnarodSettings::on_btnClearCookies_clicked() { Options::instance()->saveCookies(QList()); setStatus(O_M(MRemoveCookie)); } plugins-1.5/deprecated/yandexnarodplugin/yandexnarodsettings.h000066400000000000000000000025671336777360500251740ustar00rootroot00000000000000/* yandexnarodSettings Copyright (c) 2009 by Alexander Kazarin 2011 by Evgeny Khryukin *************************************************************************** * * * 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. * * * *************************************************************************** */ #ifndef YANDEXNARODSETTINGS_H #define YANDEXNARODSETTINGS_H #include "ui_yandexnarodsettings.h" class yandexnarodSettings : public QWidget { Q_OBJECT; public: yandexnarodSettings(QWidget *p = 0); ~yandexnarodSettings(); QString getLogin() const { return ui.editLogin->text(); } QString getPasswd() const { return ui.editPasswd->text(); } void btnTest_enabled(bool b) { ui.btnTest->setEnabled(b); } void restoreSettings(); public slots: void setStatus(const QString& str); void saveSettings(); private slots: void on_btnClearCookies_clicked(); private: Ui::yandexnarodSettingsClass ui; signals: void testclick(); void startManager(); }; #endif plugins-1.5/deprecated/yandexnarodplugin/yandexnarodsettings.ui000066400000000000000000000100361336777360500253500ustar00rootroot00000000000000 yandexnarodSettingsClass 0 0 556 386 Settings Login 0 0 Password 0 0 QLineEdit::Password status Qt::LinksAccessibleByMouse Test Authorization Start Manager Send file template <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Sans'; font-size:10pt; font-weight:400; font-style:normal;"> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Verdana'; font-size:8pt;"></p></body></html> 16777215 17 %N - file name; %U - file URL; %S - file size Clear Cookies <a href="http://psi-plus.com/wiki/plugins#yandex_narod_plugin">wiki (online)</a> true testclick() plugins-1.5/dev/000077500000000000000000000000001336777360500136375ustar00rootroot00000000000000plugins-1.5/dev/CMakeLists.txt000066400000000000000000000010511336777360500163740ustar00rootroot00000000000000cmake_minimum_required( VERSION 3.1.0 ) set( plugins_list battleshipgameplugin ripperccplugin ) if( "${BUILD_PLUGINS}" STREQUAL "ALL" ) set( plugins ${plugins_list} ) else( "${BUILD_PLUGINS}" STREQUAL "ALL" ) set( plugins "${BUILD_PLUGINS}" ) endif( "${BUILD_PLUGINS}" STREQUAL "ALL" ) foreach( plugin ${plugins_list} ) foreach( subdir ${plugins} ) if( ${plugin} STREQUAL ${subdir} ) message("Parse subdirectory: ./${plugin}") add_subdirectory("./${plugin}") endif( ${plugin} STREQUAL ${subdir} ) endforeach(subdir) endforeach(plugin) plugins-1.5/dev/battleshipgameplugin/000077500000000000000000000000001336777360500200475ustar00rootroot00000000000000plugins-1.5/dev/battleshipgameplugin/CMakeLists.txt000066400000000000000000000035431336777360500226140ustar00rootroot00000000000000unset(_HDRS) unset(_UIS) unset(_SRCS) unset(_RSCS) unset(PLUGIN) set( PLUGIN battleshipgameplugin ) project(${PLUGIN}) cmake_minimum_required( VERSION 3.1.0 ) set( CMAKE_AUTOMOC TRUE ) IF( NOT WIN32 ) set( LIB_SUFFIX "" CACHE STRING "Define suffix of directory name (32/64)" ) set( PLUGINS_PATH "lib${LIB_SUFFIX}/psi-plus/plugins" CACHE STRING "Install suffix for plugins" ) ELSE( NOT WIN32 ) set( PLUGINS_PATH "psi-plus/plugins" CACHE STRING "Install suffix for plugins" ) ENDIF( NOT WIN32 ) add_definitions( -DQT_PLUGIN ) include_directories( ${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ../../include . ) set( _HDRS ${PLUGIN}.h boarddelegate.h boardmodel.h boardview.h gamemodel.h gamesessions.h invitedialog.h options.h pluginwindow.h ) set( _SRCS ${PLUGIN}.cpp boarddelegate.cpp boardmodel.cpp boardview.cpp gamemodel.cpp gamesessions.cpp invitedialog.cpp options.cpp pluginwindow.cpp ) set( _UIS invitationdialog.ui invitedialog.ui options.ui pluginwindow.ui ) set( _RSCS ${PLUGIN}.qrc ) find_package( Qt5 COMPONENTS Widgets Xml REQUIRED ) add_definitions( ${Qt5Widgets_DEFINITIONS} ${Qt5Xml_DEFINITIONS} ) set(QT_DEPLIBS Qt5::Widgets Qt5::Xml ) set(CMAKE_CXX_FLAGS "-std=c++0x ${CMAKE_CXX_FLAGS} ${Qt5Widgets_EXECUTABLE_COMPILE_FLAGS}") qt5_wrap_ui(UIS ${_UIS}) qt5_add_resources(RSCS ${_RSCS}) add_library( ${PLUGIN} MODULE ${_SRCS} ${UIS} ${RSCS} ) target_link_libraries( ${PLUGIN} ${QT_DEPLIBS} ) if( UNIX AND NOT( APPLE OR CYGWIN ) ) install( TARGETS ${PLUGIN} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} ) endif( UNIX AND NOT( APPLE OR CYGWIN ) ) if( WIN32 ) install( TARGETS ${PLUGIN} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} ) endif( WIN32 ) plugins-1.5/dev/battleshipgameplugin/battleshipgameplugin.cpp000066400000000000000000000334741336777360500247760ustar00rootroot00000000000000/* * battleshipgameplugin.cpp - Battleship Game plugin * Copyright (C) 2014 Aleksey Andreev * * 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. * * You can also redistribute and/or modify this program under the * terms of the Psi License, specified in the accompanied COPYING * file, as published by the Psi Project; either dated January 1st, * 2005, 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include "battleshipgameplugin.h" #include "gamesessions.h" #include "options.h" #include #define constVersion "0.0.1" #define constShortPluginName "battleshipgameplugin" #define constPluginName "Battleship Game Plugin" #ifndef HAVE_QT5 Q_EXPORT_PLUGIN2(battleshipgameplugin, BattleshipGamePlugin) #endif BattleshipGamePlugin::BattleshipGamePlugin(QObject *parent) : QObject(parent), enabled_(false), psiTab(NULL), psiIcon(NULL), psiAccInfo(NULL), psiContactInfo(NULL), psiSender(NULL), psiEvent(NULL), psiSound(NULL), psiPopup(NULL) { Options::psiOptions = NULL; } QString BattleshipGamePlugin::name() const { return constPluginName; } QString BattleshipGamePlugin::shortName() const { return constShortPluginName; } QString BattleshipGamePlugin::version() const { return constVersion; } QWidget *BattleshipGamePlugin::options() { QWidget *options = new QWidget; ui_.setupUi(options); ui_.play_error->setIcon(psiIcon->getIcon("psi/play")); ui_.play_finish->setIcon(psiIcon->getIcon("psi/play")); ui_.play_move->setIcon(psiIcon->getIcon("psi/play"));; ui_.play_start->setIcon(psiIcon->getIcon("psi/play")); ui_.select_error->setIcon(psiIcon->getIcon("psi/browse")); ui_.select_finish->setIcon(psiIcon->getIcon("psi/browse")); ui_.select_move->setIcon(psiIcon->getIcon("psi/browse")); ui_.select_start->setIcon(psiIcon->getIcon("psi/browse")); restoreOptions(); connect(ui_.play_error, SIGNAL(clicked()), this, SLOT(testSound())); connect(ui_.play_finish, SIGNAL(clicked()), this, SLOT(testSound())); connect(ui_.play_move, SIGNAL(clicked()), this, SLOT(testSound())); connect(ui_.play_start, SIGNAL(clicked()), this, SLOT(testSound())); connect(ui_.select_error, SIGNAL(clicked()), this, SLOT(getSound())); connect(ui_.select_finish, SIGNAL(clicked()), this, SLOT(getSound())); connect(ui_.select_start, SIGNAL(clicked()), this, SLOT(getSound())); connect(ui_.select_move, SIGNAL(clicked()), this, SLOT(getSound())); return options; } bool BattleshipGamePlugin::enable() { if (enabled_) return true; // Грузим иконку плагина QFile file(":/battleshipgameplugin/battleship"); if(file.open(QIODevice::ReadOnly)) { QByteArray ico = file.readAll(); psiIcon->addIcon("battleshipgameplugin/battleship", ico); file.close(); } // Создаем соединения с менеджером игровых сессий GameSessionList *gsl = GameSessionList::instance(); connect(gsl, SIGNAL(sendStanza(int, QString)), this, SLOT(sendGameStanza(int, QString)), Qt::QueuedConnection); connect(gsl, SIGNAL(doPopup(QString)), this, SLOT(doPopup(QString)), Qt::QueuedConnection); connect(gsl, SIGNAL(playSound(QString)), this, SLOT(playSound(QString)), Qt::QueuedConnection); connect(gsl, SIGNAL(doInviteEvent(int,QString,QString,QObject*,const char*)), this, SLOT(doPsiEvent(int,QString,QString,QObject*,const char*)), Qt::QueuedConnection); // Выставляем флаг и уходим enabled_ = true; return true; } bool BattleshipGamePlugin::disable() { enabled_ = false; GameSessionList::reset(); Options::reset(); return true; } void BattleshipGamePlugin::applyOptions() { Options *options = Options::instance(); options->setOption(constDefSoundSettings, ui_.cb_sound_override->isChecked()); options->setOption(constSoundStart, ui_.le_start->text()); options->setOption(constSoundFinish, ui_.le_finish->text()); options->setOption(constSoundMove, ui_.le_move->text()); options->setOption(constSoundError, ui_.le_error->text()); options->setOption(constDndDisable, ui_.cb_disable_dnd->isChecked()); options->setOption(constConfDisable, ui_.cb_disable_conf->isChecked()); options->setOption(constSaveWndPosition, ui_.cb_save_pos->isChecked()); options->setOption(constSaveWndWidthHeight, ui_.cb_save_w_h->isChecked()); } void BattleshipGamePlugin::restoreOptions() { Options *options = Options::instance(); ui_.cb_sound_override->setChecked(options->getOption(constDefSoundSettings).toBool()); ui_.le_start->setText(options->getOption(constSoundStart).toString()); ui_.le_finish->setText(options->getOption(constSoundFinish).toString()); ui_.le_move->setText(options->getOption(constSoundMove).toString()); ui_.le_error->setText(options->getOption(constSoundError).toString()); ui_.cb_disable_dnd->setChecked(options->getOption(constDndDisable).toBool()); ui_.cb_disable_conf->setChecked(options->getOption(constConfDisable).toBool()); ui_.cb_save_pos->setChecked(options->getOption(constSaveWndPosition).toBool()); ui_.cb_save_w_h->setChecked(options->getOption(constSaveWndWidthHeight).toBool()); } QPixmap BattleshipGamePlugin::icon() const { return QPixmap(":/battleshipgameplugin/battleship"); } /** * Получение списка ресурсов и вызов формы для отправки приглашения */ void BattleshipGamePlugin::inviteDlg(int account, QString full_jid) { QString bareJid = full_jid.section('/', 0, 0); //QStringList jid_parse = full_jid.split("/"); //QString jid = jid_parse.takeFirst(); if (bareJid.isEmpty()) return; QStringList resList; if (psiContactInfo->isPrivate(account, full_jid)) { // This is conference QString res = full_jid.section('/', 1); if (res.isEmpty()) return; resList.append(res); } else { // Получаем список ресурсов оппонента resList = psiContactInfo->resources(account, bareJid); } // Отображение окна отправки приглашения GameSessionList::instance()->invite(account, bareJid, resList); } // ------------------------------------------ Slots ------------------------------------------ /** * Кто-то кликнул по кнопке тулбара в окне чата */ void BattleshipGamePlugin::toolButtonPressed() { if (!enabled_) return; // Получаем наш account id QString jid = psiTab->getYourJid(); int account = -1; for (int i = 0; ; i++) { QString str1 = psiAccInfo->getJid(i); if (str1 == jid) { account = i; break; } if (str1 == "-1") return; } // Проверяем статус аккаунта if (account == -1 || psiAccInfo->getStatus(account) == "offline") return; // -- inviteDlg(account, psiTab->getJid()); } /** * Кто-то выбрал плагин в меню ростера */ void BattleshipGamePlugin::menuActivated() { if(!enabled_) return; int account = sender()->property("account").toInt(); if (psiAccInfo->getStatus(account) == "offline") return; QString jid = sender()->property("jid").toString(); inviteDlg(account, jid); } /** * Создания события для приглашения */ void BattleshipGamePlugin::doPsiEvent(int account, QString from, QString text, QObject *receiver, const char *method) { psiEvent->createNewEvent(account, from, text, receiver, method); } /** * Отсылка станзы по запросу игры */ void BattleshipGamePlugin::sendGameStanza(int account, QString stanza) { if (enabled_ && psiAccInfo->getStatus(account) != "offline") psiSender->sendStanza(account, stanza); } void BattleshipGamePlugin::testSound() { QObject *sender_ = sender(); if (sender_ == (ui_.play_error)) { psiSound->playSound(ui_.le_error->text()); } else if (sender_ == ui_.play_finish) { psiSound->playSound(ui_.le_finish->text()); } else if (sender_ == ui_.play_move) { psiSound->playSound(ui_.le_move->text()); } else if (sender_ == ui_.play_start) { psiSound->playSound(ui_.le_start->text()); } } void BattleshipGamePlugin::getSound() { QObject *sender_ = sender(); QLineEdit *le = 0; if (sender_ == ui_.select_error) { le = ui_.le_error; } else if (sender_ == ui_.select_finish) { le = ui_.le_finish; } else if (sender_ == ui_.select_move) { le = ui_.le_move; } else if (sender_ == ui_.select_start) { le = ui_.le_start; } if (!le) return; QString file_name = QFileDialog::getOpenFileName(0, tr("Choose a sound file"), "", tr("Sound (*.wav)")); if (file_name.isEmpty()) return; le->setText(file_name); } void BattleshipGamePlugin::doPopup(QString text) { psiPopup->initPopup(text, tr(constPluginName), "battleshipgameplugin/battleship"); } void BattleshipGamePlugin::playSound(QString sound_id) { Options *options = Options::instance(); if (options->getOption(constDefSoundSettings).toBool() || Options::psiOptions->getGlobalOption("options.ui.notifications.sounds.enable").toBool()) { if (sound_id == constSoundMove) psiSound->playSound(options->getOption(constSoundMove).toString()); else if (sound_id == constSoundStart) psiSound->playSound(options->getOption(constSoundStart).toString()); else if (sound_id == constSoundFinish) psiSound->playSound(options->getOption(constSoundFinish).toString()); else if (sound_id == constSoundError) psiSound->playSound(options->getOption(constSoundError).toString()); } } // --------------------- Plugin info provider --------------------------- QString BattleshipGamePlugin::pluginInfo() { return tr("Author: ") + "Liuch\n" + tr("Email: ") + "liuch@mail.ru\n\n" + trUtf8("This plugin allows you to play battleship with your friends.\n" "For sending commands, normal messages are used, so this plugin will always work wherever you are able to log in." "To invite a friend for a game, you can use contact menu item or the button on the toolbar in a chat window."); } // --------------------- Option accessor --------------------------- void BattleshipGamePlugin::setOptionAccessingHost(OptionAccessingHost *host) { Options::psiOptions = host; } void BattleshipGamePlugin::optionChanged(const QString &/*option*/) { } // --------------------- Iconfactory accessor --------------------------- void BattleshipGamePlugin::setIconFactoryAccessingHost(IconFactoryAccessingHost *host) { psiIcon = host; } // --------------------- Toolbar icon accessor --------------------------- QList BattleshipGamePlugin::getButtonParam() { QList list; QVariantHash hash; hash["tooltip"] = QVariant(tr("Battleship game")); hash["icon"] = QVariant(QString("battleshipgameplugin/battleship")); hash["reciver"] = qVariantFromValue(qobject_cast(this)); hash["slot"] = QVariant(SLOT(toolButtonPressed())); list.push_back(hash); return list; } QAction* BattleshipGamePlugin::getAction(QObject* /*parent*/, int /*account*/, const QString& /*contact*/) { return NULL; } // --------------------- Activetab accessor --------------------------- void BattleshipGamePlugin::setActiveTabAccessingHost(ActiveTabAccessingHost *host) { psiTab = host; } // --------------------- Account info accessor --------------------------- void BattleshipGamePlugin::setAccountInfoAccessingHost(AccountInfoAccessingHost * host) { psiAccInfo = host; } // --------------------- Contact info accessor --------------------------- void BattleshipGamePlugin::setContactInfoAccessingHost(ContactInfoAccessingHost * host) { psiContactInfo = host; } // --------------------- Stanza sender --------------------------- void BattleshipGamePlugin::setStanzaSendingHost(StanzaSendingHost *host) { psiSender = host; } // --------------------- Stanza filter --------------------------- bool BattleshipGamePlugin::incomingStanza(int account, const QDomElement& xml) { if(xml.tagName() == "iq") { QString acc_status = ""; bool confPriv = false; if (xml.attribute("type") == "set") { acc_status = psiAccInfo->getStatus(account); confPriv = psiContactInfo->isPrivate(account, xml.attribute("from")); } return GameSessionList::instance()->processIncomingIqStanza(account, xml, acc_status, confPriv); } return false; } bool BattleshipGamePlugin::outgoingStanza(int /*account*/, QDomElement& /*xml*/) { return false; } // --------------------- Event creator --------------------------- void BattleshipGamePlugin::setEventCreatingHost(EventCreatingHost *host) { psiEvent = host; } // --------------------- Sound accessor --------------------------- void BattleshipGamePlugin::setSoundAccessingHost(SoundAccessingHost *host) { psiSound = host; } // --------------------- Menu accessor --------------------------- QList BattleshipGamePlugin::getAccountMenuParam() { return QList(); } QList BattleshipGamePlugin::getContactMenuParam() { QList menu_list; QVariantHash hash; hash["name"] = QVariant(tr("Battleship game!")); hash["icon"] = QVariant(QString("battleshipgameplugin/battleship")); hash["reciver"] = qVariantFromValue(qobject_cast(this)); hash["slot"] = QVariant(SLOT(menuActivated())); menu_list.push_back(hash); return menu_list; } QAction* BattleshipGamePlugin::getContactAction(QObject*, int, const QString&) { return NULL; } QAction* BattleshipGamePlugin::getAccountAction(QObject*, int) { return NULL; } // --------------------- Popup accessor --------------------------- void BattleshipGamePlugin::setPopupAccessingHost(PopupAccessingHost *host) { psiPopup = host; } plugins-1.5/dev/battleshipgameplugin/battleshipgameplugin.h000066400000000000000000000117561336777360500244420ustar00rootroot00000000000000/* * battleshipgameplugin.h - Battleship Game plugin * Copyright (C) 2014 Aleksey Andreev * * 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. * * You can also redistribute and/or modify this program under the * terms of the Psi License, specified in the accompanied COPYING * file, as published by the Psi Project; either dated January 1st, * 2005, 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef BATTLESHIPGAMEPLUGIN_H #define BATTLESHIPGAMEPLUGIN_H #include #include #include #include #include "psiplugin.h" #include "plugininfoprovider.h" #include "optionaccessor.h" #include "optionaccessinghost.h" #include "iconfactoryaccessor.h" #include "iconfactoryaccessinghost.h" #include "toolbariconaccessor.h" #include "activetabaccessor.h" #include "activetabaccessinghost.h" #include "accountinfoaccessor.h" #include "accountinfoaccessinghost.h" #include "contactinfoaccessor.h" #include "contactinfoaccessinghost.h" #include "stanzasender.h" #include "stanzasendinghost.h" #include "stanzafilter.h" #include "eventcreator.h" #include "eventcreatinghost.h" #include "soundaccessor.h" #include "soundaccessinghost.h" #include "menuaccessor.h" #include "popupaccessor.h" #include "popupaccessinghost.h" #include "ui_options.h" class BattleshipGamePlugin : public QObject, public PsiPlugin, public PluginInfoProvider, public OptionAccessor, public IconFactoryAccessor, public ToolbarIconAccessor, public ActiveTabAccessor, public AccountInfoAccessor, public ContactInfoAccessor, public StanzaSender, public StanzaFilter, public EventCreator, public SoundAccessor, public MenuAccessor, public PopupAccessor { Q_OBJECT #ifdef HAVE_QT5 Q_PLUGIN_METADATA(IID "com.psi-plus.BattleshipGame") #endif Q_INTERFACES(PsiPlugin PluginInfoProvider OptionAccessor IconFactoryAccessor ToolbarIconAccessor ActiveTabAccessor AccountInfoAccessor ContactInfoAccessor StanzaSender StanzaFilter EventCreator SoundAccessor MenuAccessor PopupAccessor) public: explicit BattleshipGamePlugin(QObject *parent = 0); // Psiplugin virtual QString name() const; virtual QString shortName() const; virtual QString version() const; virtual QWidget* options(); virtual bool enable(); virtual bool disable(); virtual void applyOptions(); virtual void restoreOptions(); virtual QPixmap icon() const; // Plugin info provider virtual QString pluginInfo(); // Option accessor virtual void setOptionAccessingHost(OptionAccessingHost*); virtual void optionChanged(const QString&); // Iconfactory accessor virtual void setIconFactoryAccessingHost(IconFactoryAccessingHost*); // Toolbar icon accessor virtual QList getButtonParam(); virtual QAction* getAction(QObject* , int , const QString& ); // Activetab accessor virtual void setActiveTabAccessingHost(ActiveTabAccessingHost*); // Account info accessor virtual void setAccountInfoAccessingHost(AccountInfoAccessingHost*); // Contact info accessor virtual void setContactInfoAccessingHost(ContactInfoAccessingHost*); // Stanza sender virtual void setStanzaSendingHost(StanzaSendingHost*); // Stanza filter virtual bool incomingStanza(int account, const QDomElement& xml); virtual bool outgoingStanza(int account, QDomElement& xml); // Event creator virtual void setEventCreatingHost(EventCreatingHost*); // Sound accessor virtual void setSoundAccessingHost(SoundAccessingHost*); // Menu accessor virtual QList getAccountMenuParam(); virtual QList getContactMenuParam(); virtual QAction* getContactAction(QObject*, int, const QString&); virtual QAction* getAccountAction(QObject*, int); // Popup accessor virtual void setPopupAccessingHost(PopupAccessingHost*); private: bool enabled_; ActiveTabAccessingHost *psiTab; IconFactoryAccessingHost *psiIcon; AccountInfoAccessingHost *psiAccInfo; ContactInfoAccessingHost *psiContactInfo; StanzaSendingHost *psiSender; EventCreatingHost *psiEvent; SoundAccessingHost *psiSound; PopupAccessingHost *psiPopup; // -- Ui::options ui_; private: void inviteDlg(int account, QString full_jid); private slots: void toolButtonPressed(); void menuActivated(); void doPsiEvent(int, QString, QString, QObject *, const char *); void sendGameStanza(int account, const QString stanza); void testSound(); void getSound(); void doPopup(QString text); void playSound(QString); }; #endif // BATTLESHIPGAMEPLUGIN_H plugins-1.5/dev/battleshipgameplugin/battleshipgameplugin.pro000066400000000000000000000010401336777360500247740ustar00rootroot00000000000000CONFIG += release include(../../psiplugin.pri) HEADERS += battleshipgameplugin.h \ options.h \ gamesessions.h \ invitedialog.h \ pluginwindow.h \ boardview.h \ boardmodel.h \ gamemodel.h \ boarddelegate.h SOURCES += battleshipgameplugin.cpp \ options.cpp \ gamesessions.cpp \ invitedialog.cpp \ pluginwindow.cpp \ boardview.cpp \ boardmodel.cpp \ gamemodel.cpp \ boarddelegate.cpp FORMS += options.ui \ invitedialog.ui \ invitationdialog.ui \ pluginwindow.ui RESOURCES += \ battleshipgameplugin.qrc plugins-1.5/dev/battleshipgameplugin/battleshipgameplugin.qrc000066400000000000000000000002131336777360500247620ustar00rootroot00000000000000 img/battleship256.png plugins-1.5/dev/battleshipgameplugin/boarddelegate.cpp000066400000000000000000000074631336777360500233470ustar00rootroot00000000000000/* * boarddelegate.cpp - Battleship game plugin * Copyright (C) 2014 Aleksey Andreev * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "boarddelegate.h" BoardDelegate::BoardDelegate(BoardModel *model, QObject *parent) : QItemDelegate(parent) , model_(model) { } void BoardDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { if (!index.isValid()) return; QPoint point(index.column(), index.row()); painter->save(); painter->setRenderHint(QPainter::Antialiasing, true); painter->setRenderHint(QPainter::TextAntialiasing, true); painter->setRenderHint(QPainter::SmoothPixmapTransform, true); QRectF r(option.rect); int opos = model_->model2oppboard(point); int mpos = -1; if (opos == -1) mpos = model_->model2myboard(point); if (opos != -1 || mpos != -1) { GameBoard::CellStatus st; if (opos != -1) st = model_->gameModel()->oppBoard().cell(opos).status; else st = model_->gameModel()->myBoard().cell(mpos).status; if (st == GameBoard::CellOccupied || st == GameBoard::CellHit) { QRectF r2 = r.adjusted(1.0, 1.0, -1.0, -1.0); QPen pen(Qt::black); pen.setWidthF(2.0); pen.setJoinStyle(Qt::MiterJoin); painter->setPen(pen); painter->drawRect(r2); if (st == GameBoard::CellHit) { r2.adjust(1.0, 1.0, -1.0, -1.0); pen.setCapStyle(Qt::RoundCap); painter->drawLine(r2.topLeft(), r2.bottomRight()); painter->drawLine(r2.topRight(), r2.bottomLeft()); } } else { QRectF r2 = r.adjusted(0.5, 0.5, -0.5, -0.5); setGridPen(painter); painter->drawRect(r2); if (st == GameBoard::CellMiss || st == GameBoard::CellMargin) { qreal w = r.width() * 0.2; QPen pen(Qt::black); pen.setWidthF(w); pen.setCapStyle(Qt::RoundCap); painter->setPen(pen); painter->drawPoint(r.center()); } } } else { // displaying coordinates if ((point.x() == 1 || point.x() == model_->columnCount() - 2) && point.y() >= 2 && point.y() < model_->rowCount() - 2) { // Numbers QString text = QString::number(point.y() - 1); painter->drawText(r, Qt::AlignCenter, text, 0); QRectF r2 = r.adjusted(0.5, 0.5, -0.5, -0.5); setGridPen(painter); if (point.x() == 1) painter->drawLine(r2.topRight(), r2.bottomRight()); else painter->drawLine(r2.topLeft(), r2.bottomLeft()); } else if ((point.y() == 1 || point.y() == model_->rowCount() - 2) && point.x() >= 2 && point.x() < model_->columnCount() - 2 && (point.x() <= 11 || point.x() >= 15)) { // letters static const QString letters("ABCDEFGHJK"); QString text; if (point.x() <= 11) text = letters.mid(point.x() - 2, 1); else text = letters.mid(point.x() - 15, 1); painter->drawText(r, Qt::AlignCenter, text, 0); QRectF r2 = r.adjusted(0.5, 0.5, -0.5, -0.5); setGridPen(painter); if (point.y() == 1) painter->drawLine(r2.bottomLeft(), r2.bottomRight()); else painter->drawLine(r2.topLeft(), r2.topRight()); } } painter->restore(); } void BoardDelegate::setGridPen(QPainter *painter) { QPen pen(Qt::blue); pen.setWidthF(0.5); pen.setJoinStyle(Qt::MiterJoin); pen.setCapStyle(Qt::SquareCap); painter->setPen(pen); } plugins-1.5/dev/battleshipgameplugin/boarddelegate.h000066400000000000000000000023771336777360500230130ustar00rootroot00000000000000/* * boarddelegate.h - Battleship game plugin * Copyright (C) 2014 Aleksey Andreev * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef BOARDDELEGATE_H #define BOARDDELEGATE_H #include #include #include "boardmodel.h" class BoardDelegate : public QItemDelegate { Q_OBJECT public: BoardDelegate(BoardModel *model, QObject *parent = 0); virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; private: static void setGridPen(QPainter *painter); private: BoardModel *model_; }; #endif // BOARDDELEGATE_H plugins-1.5/dev/battleshipgameplugin/boardmodel.cpp000066400000000000000000000064261336777360500226730ustar00rootroot00000000000000/* * boardmodel.cpp - Battleship game plugin * Copyright (C) 2014 Aleksey Andreev * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "boardmodel.h" #define MODEL_ROW_COUNT 2 + 10 + 2 #define MODEL_COL_COUNT 2 + 10 + 3 + 10 + 2 BoardModel::BoardModel(QObject *parent) : QAbstractTableModel(parent) , gameModel_(NULL) { } BoardModel::~BoardModel() { } void BoardModel::init(GameModel *gm) { gameModel_ = gm; // #ifdef HAVE_QT5 QAbstractTableModel::beginResetModel(); QAbstractTableModel::endResetModel(); #else QAbstractTableModel::reset(); #endif connect(gameModel_, SIGNAL(myBoardUpdated(int,int,int,int)), this, SLOT(updateMyBoard(int,int,int,int))); connect(gameModel_, SIGNAL(oppBoardUpdated(int,int,int,int)), this, SLOT(updateOppBoard(int,int,int,int))); } Qt::ItemFlags BoardModel::flags(const QModelIndex & index) const { Qt::ItemFlags fl = Qt::NoItemFlags | Qt::ItemIsEnabled; int row = index.row(); if (row < 2 || row >= MODEL_ROW_COUNT - 2) return fl; int col = index.column(); if (col < 2 || col >= MODEL_COL_COUNT - 2 || (col > 11 && col < 15)) return fl; return (fl | Qt::ItemIsSelectable); } QVariant BoardModel::headerData(int /*section*/, Qt::Orientation /*orientation*/, int /*role*/) const { return QVariant(); } QVariant BoardModel::data(const QModelIndex &/*index*/, int /*role*/) const { return QVariant(); } int BoardModel::rowCount(const QModelIndex &/*parent*/) const { return MODEL_ROW_COUNT; } int BoardModel::columnCount(const QModelIndex &/*parent*/) const { return MODEL_COL_COUNT; } void BoardModel::updateMyBoard(int x, int y, int width, int height) { QRect r(x, y, width, height); QPoint p1 = myboard2model(r.topLeft()); QPoint p2 = myboard2model(r.bottomRight()); emit dataChanged(index(p1.y(), p1.x()), index(p2.y(), p2.x())); } void BoardModel::updateOppBoard(int x, int y, int width, int height) { QRect r(x, y, width, height); QPoint p1 = oppboard2model(r.topLeft()); QPoint p2 = oppboard2model(r.bottomRight()); emit dataChanged(index(p1.y(), p1.x()), index(p2.y(), p2.x())); } int BoardModel::model2oppboard(const QPoint &p) { int col = p.x() - 15; if (col >= 0 && col < 10) { int row = p.y() - 2; if (row >= 0 && row < 10) return row * 10 + col; } return -1; } int BoardModel::model2myboard(const QPoint &p) { int col = p.x() - 2; if (col >= 0 && col < 10) { int row = p.y() - 2; if (row >= 0 && row < 10) return row * 10 + col; } return -1; } QPoint BoardModel::myboard2model(const QPoint &p) const { return QPoint(p.x() + 2, p.y() + 2); } QPoint BoardModel::oppboard2model(const QPoint &p) const { return QPoint(p.x() + 2 + 10 + 3, p.y() + 2); } plugins-1.5/dev/battleshipgameplugin/boardmodel.h000066400000000000000000000035311336777360500223320ustar00rootroot00000000000000/* * boardmodel.h - Battleship game plugin * Copyright (C) 2014 Aleksey Andreev * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef BOARDMODEL_H #define BOARDMODEL_H #include #include "gamemodel.h" class BoardModel : public QAbstractTableModel { Q_OBJECT public: BoardModel(QObject *parent = 0); ~BoardModel(); void init(GameModel *gm); GameModel *gameModel() const { return gameModel_; } int model2oppboard(const QPoint &p); int model2myboard(const QPoint &p); virtual Qt::ItemFlags flags(const QModelIndex & index) const; virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; virtual int rowCount(const QModelIndex &parent = QModelIndex()) const; virtual int columnCount(const QModelIndex &parent = QModelIndex()) const; private: QPoint myboard2model(const QPoint &p) const; QPoint oppboard2model(const QPoint &p) const; private: GameModel *gameModel_; private slots: void updateMyBoard(int x, int y, int width, int height); void updateOppBoard(int x, int y, int width, int height); }; #endif // BOARDMODEL_H plugins-1.5/dev/battleshipgameplugin/boardview.cpp000066400000000000000000000047231336777360500225430ustar00rootroot00000000000000/* * boardview.cpp - Battleship game plugin * Copyright (C) 2014 Aleksey Andreev * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include #include "boardview.h" BoardView::BoardView(QWidget *parent) : QTableView(parent) , bmodel_(NULL) { } void BoardView::setModel(BoardModel *model) { QTableView::setModel(model); bmodel_ = model; } void BoardView::resizeEvent(QResizeEvent */*event*/) { setCellsSize(); } void BoardView::mouseReleaseEvent(QMouseEvent */*event*/) { QModelIndex index = currentIndex(); if (index.isValid()) { int pos = bmodel_->model2oppboard(QPoint(index.column(), index.row())); if (pos != -1) bmodel_->gameModel()->localTurn(pos); } } void BoardView::setCellsSize() { if (!bmodel_) return; int rowCnt = model()->rowCount() - 2; int colCnt = model()->columnCount() - 3; int boardWidth = width() - verticalHeader()->width() - (lineWidth() + midLineWidth()) * 2; int boardHeight = height() - horizontalHeader()->height() - (lineWidth() + midLineWidth()) * 2; boardWidth -= 4; boardHeight -= 4; // Запас для гарантии отсутствия прокрутки int cellWidth = boardWidth / colCnt - 1; int cellHeight = boardHeight / rowCnt - 1; int cellSize = qMin(cellWidth, cellHeight); int hMargin = boardHeight - cellSize * rowCnt; if (hMargin < 0) hMargin = 0; hMargin /= 2; int vMargin = boardWidth - cellSize * colCnt; if (vMargin < 0) vMargin = 0; vMargin /= 3; horizontalHeader()->setDefaultSectionSize(cellSize); verticalHeader()->setDefaultSectionSize(cellSize); horizontalHeader()->resizeSection(0, vMargin); horizontalHeader()->resizeSection(colCnt / 2 + 1, vMargin); horizontalHeader()->resizeSection(colCnt + 2, vMargin); verticalHeader()->resizeSection(0, hMargin); verticalHeader()->resizeSection(rowCnt + 1, hMargin); } plugins-1.5/dev/battleshipgameplugin/boardview.h000066400000000000000000000023011336777360500221760ustar00rootroot00000000000000/* * boardview.h - Battleship game plugin * Copyright (C) 2014 Aleksey Andreev * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef BOARDVIEW_H #define BOARDVIEW_H #include #include "boardmodel.h" class BoardView : public QTableView { Q_OBJECT public: BoardView(QWidget *parent = 0); void setModel(BoardModel *model); private: virtual void resizeEvent(QResizeEvent *event); virtual void mouseReleaseEvent(QMouseEvent *event); void setCellsSize(); private: BoardModel *bmodel_; }; #endif // BOARDVIEW_H plugins-1.5/dev/battleshipgameplugin/changelog.txt000066400000000000000000000010571336777360500225420ustar00rootroot000000000000002014-12-15 v0.0.1 ! initial version Данный плагин позволяет вам играть с вашими знакомыми в игру Морской бой. Реализована разновидность с семь короблями для совместимости с клиентом Tkabber. Для передачи команд используются обычные сообщения, поэтому плагин будет работать везде, где у вас есть возможность выйти в онлайн. plugins-1.5/dev/battleshipgameplugin/gamemodel.cpp000066400000000000000000000412321336777360500225070ustar00rootroot00000000000000/* * gamemodel.cpp - Battleship game plugin * Copyright (C) 2014 Aleksey Andreev * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include #include "gamemodel.h" GameModel::GameModel(QObject *parent) : QObject(parent) , status_(StatusNone) , lastShot_(-1) , draw_(false) , oppDraw_(false) , myAccept_(false) , oppResign_(false) , myResign_(false) , destroyed_(false) { connect(&myBoard_, SIGNAL(shipDestroyed(int)), this, SLOT(myShipDestroyed()), Qt::DirectConnection); } void GameModel::init() { setStatus(StatusBoardInit); opBoard_.init(GameBoard::CellUnknown, false); myBoard_.init(GameBoard::CellFree, true); myBoard_.makeShipRandomPosition(); } void GameModel::setError() { setStatus(StatusError); } bool GameModel::initOpponentBoard(const QStringList &data) { bool err = false; int cnt = data.count(); for (int i = 0; i < cnt; ++i) { const QString str = data.at(i); const QString t = str.section(';', 0, 0); int n = str.section(';', 1, 1).toInt(); const QString s = str.section(';', 2); if (t == "cell") { if (!opBoard_.updateCellDigest(n, s)) { err = true; break; } } else if (t == "ship") { if (!opBoard_.updateShipDigest(n, s)) { err = true; break; } } } return !err; } bool GameModel::uncoverOpponentBoard(const QStringList &data) { bool err = false; int cnt = data.count(); for (int i = 0; i < cnt; ++i) { const QString str = data.at(i); int pos = str.section(';', 0, 0).toInt(); GameBoard::CellStatus cs = (str.section(';', 1, 1) == "1") ? GameBoard::CellOccupied : GameBoard::CellFree; const QString seed = str.section(';', 2); if (!opBoard_.updateCell(pos, cs, seed)) { err = true; break; } } emit oppBoardUpdated(0, 0, 10, 10); return !err; } void GameModel::setOpponentDraw(bool draw) { oppDraw_ = draw; } void GameModel::setOpponentAcceptedDraw(bool accept) { if (draw_) { if (accept) setStatus(StatusDraw); else draw_ = false; } } void GameModel::opponentResign() { oppResign_ = true; setStatus(StatusWin); } void GameModel::sendCoveredBoard() { myBoard_.calculateCellsHash(); emit gameEvent("covered-board\n" + myBoard_.toStringList(true).join("\n")); } void GameModel::localTurn(int pos) { if (status_ == StatusMyTurn) { lastShot_ = pos; QString data = QString("turn\npos;%1").arg(pos); if (draw_) data.append("\ndraw"); setStatus(StatusWaitingTurnAccept); emit gameEvent(data); } } void GameModel::opponentTurn(int pos) { if (status_ == StatusWaitingOpponent) { lastShot_ = pos; destroyed_ = false; draw_ = false; if (pos != -1) { myBoard_.shot(pos); int row = pos / 10; int col = pos % 10; emit myBoardUpdated(col, row, 1, 1); if (lastShotResult() == "miss") setStatus(StatusMyTurn); else if (myBoard_.isAllDestroyed()) setStatus(StatusLose); else if (oppDraw_) setStatus(StatusMyTurn); else setStatus(StatusWaitingOpponent); } } } bool GameModel::handleResult() { if (myAccept_) { setStatus(StatusDraw); return true; } if (myResign_) { setStatus(StatusLose); return true; } return false; } bool GameModel::handleTurnResult(const QString &res, const QString &seed) { GameBoard::CellStatus cs = GameBoard::CellUnknown; if (res == "miss") cs = GameBoard::CellMiss; else if (res == "hit" || res == "destroy") cs = GameBoard::CellHit; if (cs != GameBoard::CellUnknown && opBoard_.updateCell(lastShot_, cs, seed)) { int snum = -1; if (res != "destroy" || (snum = opBoard_.findAndInitShip(lastShot_)) != -1) { QPoint p(lastShot_ / 10, lastShot_ % 10); QRect r; r.setTopLeft(p); r.setSize(QSize(1, 1)); if (snum != -1) { opBoard_.setShipDestroy(snum, true); r = opBoard_.shipRect(snum, true); } if (cs == GameBoard::CellMiss) setStatus(StatusWaitingOpponent); else if (snum != -1 && opBoard_.isAllDestroyed()) setStatus(StatusWin); else if (draw_) setStatus(StatusWaitingOpponent); else setStatus(StatusMyTurn); emit oppBoardUpdated(r.left(), r.top(), r.width(), r.height()); return true; } } setStatus(StatusError); return false; } QString GameModel::lastShotResult() const { QString res; if (lastShot_ != -1) { const GameBoard::GameCell &cell = myBoard_.cell(lastShot_); const GameBoard::CellStatus cs = cell.status; if (cs == GameBoard::CellHit) { if (destroyed_) res = "destroy"; else res = "hit"; } else res = "miss"; } return res; } QString GameModel::lastShotSeed() const { QString res; if (lastShot_ != -1) res = myBoard_.cell(lastShot_).seed; return res; } QStringList GameModel::getUncoveredBoard() const { return myBoard_.toStringList(false); } void GameModel::setStatus(GameStatus s) { status_ = s; emit statusChanged(); } void GameModel::myShipDestroyed() { destroyed_ = true; } void GameModel::setLocalDraw(bool draw) { draw_ = draw; } void GameModel::localAccept() { if (status_ == StatusMyTurn && oppDraw_) { myAccept_ = true; setStatus(StatusDraw); emit gameEvent("turn\naccept"); } } void GameModel::localResign() { if (status_ == StatusMyTurn) { myResign_ = true; setStatus(StatusLose); emit gameEvent("turn\nresign"); } } //------------- GameBoard ---------------- GameBoard::GameBoard(QObject *parent) : QObject(parent) { } void GameBoard::init(CellStatus s, bool genseed) { cells_.clear(); qDeleteAll(ships_); ships_.clear(); for (int i = 0; i < 100; ++i) { cells_.append(GameCell(s)); if (genseed) cells_[i].seed = genSeed(32); } ships_.append(new GameShip(5, QString(), this)); ships_.append(new GameShip(4, QString(), this)); ships_.append(new GameShip(3, QString(), this)); ships_.append(new GameShip(2, QString(), this)); ships_.append(new GameShip(2, QString(), this)); ships_.append(new GameShip(1, QString(), this)); ships_.append(new GameShip(1, QString(), this)); } void GameBoard::makeShipRandomPosition() { int scnt = ships_.count(); for (int snum = 0; snum < scnt; ++snum) { GameShip *ship = ships_.at(snum); int slen = ship->length(); GameShip::ShipType dir; for ( ; ; ) { dir = GameShip::ShipHorizontal; int div; if (slen > 1 && (qrand() & 1)) { dir = GameShip::ShipVertical; div = 100 - 10 * (slen - 1); } else div = 100 - (slen - 1); ship->setDirection(dir); ship->setPosition(qrand() % div); if (isShipPositionLegal(snum)) break; } int offset = 1; if (dir == GameShip::ShipVertical) offset = 10; int pos = ship->position(); QCryptographicHash sha1(QCryptographicHash::Sha1); for ( ; slen != 0; --slen) { cells_[pos].ship = snum; cells_[pos].status = CellOccupied; sha1.addData(cells_.at(pos).seed.toUtf8()); pos += offset; } ship->setDigest(sha1.result().toHex()); } } void GameBoard::calculateCellsHash() { int cnt = cells_.count(); QCryptographicHash sha1(QCryptographicHash::Sha1); for (int i = 0; i < cnt; ++i) { sha1.reset(); sha1.addData(cells_.at(i).seed.toUtf8()); sha1.addData((cells_.at(i).ship == -1) ? "0" : "1"); cells_[i].digest = QString(sha1.result().toHex()); } } bool GameBoard::updateCellDigest(int pos, const QString &digest) { if (pos >= 0 && pos < cells_.count() && digest.length() == 40) { cells_[pos].digest = digest; return true; } return false; } bool GameBoard::updateCell(int pos, CellStatus cs, const QString &seed) { if (pos >= 0 && pos < cells_.count()) { if (!cells_.at(pos).seed.isEmpty()) // again shot at this position return true; QString seed_ = seed + ((cs == CellHit || cs == CellOccupied) ? "1" : "0"); QString digest_ = QCryptographicHash::hash(seed_.toUtf8(), QCryptographicHash::Sha1).toHex(); if (digest_ == cells_.at(pos).digest) { cells_[pos].seed = seed; if (cells_.at(pos).status == CellUnknown) cells_[pos].status = cs; return true; } } return false; } bool GameBoard::updateShipDigest(int length, const QString &digest) { GameShip *ship = findShip(length, QString()); if (ship) { ship->setDigest(digest); return true; } return false; } void GameBoard::shot(int pos) { CellStatus cs = cells_.at(pos).status; if (cs == CellFree) cells_[pos].status = CellMiss; else if (cs == CellOccupied) { cells_[pos].status = CellHit; int snum = cells_.at(pos).ship; GameShip *ship = ships_.at(snum); bool destr = true; int p = -1; while ((p = ship->nextPosition(p)) != -1) if (cells_.at(p).status != CellHit) { destr = false; break; } if (destr) { ship->setDestroyed(true); emit shipDestroyed(snum); } } } GameShip::ShipType GameBoard::shipDirection(int pos) { GameShip::ShipType dir = GameShip::ShipDirUnknown; if ((pos >= 10 && (cells_.at(pos - 10).status == CellHit || cells_.at(pos - 10).status == CellOccupied)) || (pos <= 89 && (cells_.at(pos + 10).status == CellHit || cells_.at(pos + 10).status == CellOccupied))) dir = GameShip::ShipVertical; else { int col = pos % 10; if ((col > 0 && (cells_.at(pos - 1).status == CellHit || cells_.at(pos - 1).status == CellOccupied)) || (col < 9 && (cells_.at(pos + 1).status == CellHit || cells_.at(pos + 1).status == CellOccupied))) dir = GameShip::ShipHorizontal; } return dir; } int GameBoard::findAndInitShip(int pos) { GameShip::ShipType dir = shipDirection(pos); if (dir == GameShip::ShipDirUnknown) dir = GameShip::ShipHorizontal; // For one-cell ship // Find starting coordinate int spos = pos; if (dir == GameShip::ShipHorizontal) while (spos % 10 != 0 && (cells_.at(spos - 1).status == CellHit || cells_.at(spos - 1).status == CellOccupied)) --spos; else while (spos >= 10 && (cells_.at(spos - 10).status == CellHit || cells_.at(spos - 10).status == CellOccupied)) spos -= 10; // There do calculating the ship's hash and size int ssz = 0; int epos = spos; QCryptographicHash sha1(QCryptographicHash::Sha1); for ( ; ; ) { ++ssz; sha1.addData(cells_.at(epos).seed.toUtf8()); if (dir == GameShip::ShipHorizontal) { if (epos % 10 == 9 || (cells_.at(epos + 1).status != CellHit && cells_.at(epos + 1).status != CellOccupied)) break; ++epos; } else { if (epos >= 90 || (cells_.at(epos + 10).status != CellHit && cells_.at(epos + 10).status != CellOccupied)) break; epos += 10; } } // Find ship by hash and size QString digest = QString(sha1.result().toHex()); int snum = -1; for (int i = 0; i < ships_.count(); ++i) { GameShip *ship = ships_.at(i); if (ship->length() == ssz && ship->digest() == digest) { ship->setDirection(dir); ship->setPosition(spos); snum = i; break; } } if (snum != -1) { // Update cells for (int i = 0; i < ssz; ++i) { cells_[spos].ship = snum; ++spos; if (dir == GameShip::ShipVertical) spos += 9; } } return snum; } QRect GameBoard::shipRect(int snum, bool margin) const { QRect r; GameShip *ship = ships_.at(snum); int pos = ship->position(); r.setTopLeft(QPoint(pos % 10, pos / 10)); if (ship->direction() == GameShip::ShipHorizontal) { r.setWidth(ship->length()); r.setHeight(1); } else { r.setWidth(1); r.setHeight(ship->length()); } if (margin) { r.adjust(-1, -1, 1, 1); #ifdef HAVE_QT5 r = r.intersected(QRect(0, 0, 10, 10)); #else r = r.intersect(QRect(0, 0, 10, 10)); #endif } return r; } void GameBoard::setShipDestroy(int n, bool margin) { GameShip *ship = ships_.at(n); if (!ship->isDestroyed()) { ship->setDestroyed(true); if (margin) fillShipMargin(n); emit shipDestroyed(n); } } const GameBoard::GameCell &GameBoard::cell(int pos) const { return cells_.at(pos); } QStringList GameBoard::toStringList(bool covered) const { QStringList res; int cnt = cells_.count(); for (int i = 0; i < cnt; ++i) { const GameCell &c = cells_.at(i); QString s; if (covered) s = QString("cell;%1;%2").arg(i).arg(c.digest); else s = QString("%1;%2;%3") .arg(i) .arg((c.ship == -1) ? "0" : "1") .arg(c.seed); res.append(s); } if (covered) { cnt = ships_.count(); for (int i = 0; i < cnt; ++i) { const GameShip *ship = ships_.at(i); res.append(QString("ship;%1;%2").arg(ship->length()).arg(ship->digest())); } } return res; } bool GameBoard::isAllDestroyed() const { foreach (const GameShip *ship, ships_) if (!ship->isDestroyed()) return false; return true; } QString GameBoard::genSeed(int len) { static QString chars("1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM-=[]/!@#$%^&*()"); int ccnt = chars.length(); int rnd = 0; QString res; for (int i = 0; i < len; ++i) { if (rnd < ccnt) rnd = qrand(); res.append(chars.at(rnd % ccnt)); rnd /= ccnt; } return res; } GameShip *GameBoard::findShip(int length, const QString &digest) { foreach (GameShip *ship, ships_) if (ship->length() == length && ship->digest() == digest) return ship; return NULL; } bool GameBoard::isShipPositionLegal(int shipNum) { GameShip *ship = ships_.at(shipNum); GameShip::ShipType dir = ship->direction(); int pos = ship->position(); int len = ship->length(); int off = (dir == GameShip::ShipHorizontal) ? 1 : 10; int row = pos / 10; int col = pos % 10; int epos = pos + (len - 1) * off; if ((dir == GameShip::ShipHorizontal && (int)(epos) / 10 != row) || (dir == GameShip::ShipVertical && epos >= 100)) return false; int m = 1; if (dir == GameShip::ShipHorizontal) { if (row > 0) { ++m; pos -= 10; } if (col > 0) { --pos; ++len; } if (row < 9) ++m; if (epos % 10 < 9) ++len; } else { if (col > 0) { ++m; pos -= 1; } if (row > 0) { pos -= 10; ++len; } if (col < 9) ++m; if (epos < 90) ++len; } for ( ; m != 0; --m) { int p = pos; for (int l = len; l != 0; --l) { CellStatus cs = cells_.at(p).status; if ((cs == CellOccupied || cs == CellHit) && cells_.at(p).ship != shipNum) return false; p += off; } pos += (dir == GameShip::ShipHorizontal) ? 10 : 1; } return true; } void GameBoard::fillShipMargin(int n) { GameShip *ship = ships_.at(n); int pos = ship->position(); int len = ship->length(); GameShip::ShipType dir = ship->direction(); struct { int offset; int weight; } m[8]; m[7].offset = -11; m[0].offset = -10; m[1].offset = -9; m[6].offset = -1; m[2].offset = 1; m[5].offset = 9; m[4].offset = 10; m[3].offset = 11; for (int i = 1; i <= len; ++i) { int row = pos / 10; int col = pos % 10; for (int k = 0; k < 8; ++k) m[k].weight = 0; if (row > 0) { ++m[7].weight; ++m[0].weight; ++m[1].weight; } if (row < 9) { ++m[5].weight; ++m[4].weight; ++m[3].weight; } if (col > 0) { ++m[7].weight; ++m[6].weight; ++m[5].weight; } if (col < 9) { ++m[1].weight; ++m[2].weight; ++m[3].weight; } int nextOffset; if (dir == GameShip::ShipHorizontal) { nextOffset = 1; ++m[0].weight; ++m[4].weight; if (i == 1) { ++m[7].weight; ++m[6].weight; ++m[5].weight; } if (i == len) { ++m[1].weight; ++m[2].weight; ++m[3].weight; } } else { nextOffset = 10; ++m[6].weight; ++m[2].weight; if (i == 1) { ++m[7].weight; ++m[0].weight; ++m[1].weight; } if (i == len) { ++m[5].weight; ++m[4].weight; ++m[3].weight; } } for (int k = 0; k < 8; ++k) if (m[k].weight == 3 || ((k & 1) == 0 && m[k].weight == 2)) { if (cells_.at(pos + m[k].offset).status == CellUnknown) cells_[pos + m[k].offset].status = CellMargin; } pos += nextOffset; } } //------------- GameShip ---------------- GameShip::GameShip(int len, const QString &digest, QObject *parent) : QObject(parent) , length_(len) , direction_(ShipDirUnknown) , firstPos_(-1) , destroyed_(false) , digest_(digest) { } void GameShip::setDirection(ShipType dir) { direction_ = dir; } void GameShip::setPosition(int pos) { firstPos_ = pos; } void GameShip::setDigest(const QString &digest) { digest_ = digest; } void GameShip::setDestroyed(bool destr) { destroyed_ = destr; } int GameShip::nextPosition(int prev) { if (prev == -1) return firstPos_; int offs = (direction_ == ShipHorizontal) ? 1 : 10; if ((prev - firstPos_) >= (length_ - 1) * offs) return -1; return prev + offs; } plugins-1.5/dev/battleshipgameplugin/gamemodel.h000066400000000000000000000104631336777360500221560ustar00rootroot00000000000000/* * gamemodel.h - Battleship game plugin * Copyright (C) 2014 Aleksey Andreev * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef GAMEMODEL_H #define GAMEMODEL_H #include #include #include class GameShip : public QObject { Q_OBJECT public: enum ShipType { ShipDirUnknown, ShipHorizontal, ShipVertical }; GameShip(int len, const QString &digest = QString(), QObject *parent = 0); int length() const { return length_; } int position() const { return firstPos_; } ShipType direction() const { return direction_; } QString digest() const { return digest_; } bool isDestroyed() const { return destroyed_ ; } void setDirection(ShipType dir); void setPosition(int pos); void setDigest(const QString &digest); void setDestroyed(bool destr); int nextPosition(int prev); private: int length_; ShipType direction_; int firstPos_; bool destroyed_; QString digest_; }; class GameBoard : public QObject { Q_OBJECT public: enum CellStatus { CellFree, CellOccupied, CellUnknown, CellMiss, CellHit, CellMargin }; struct GameCell { CellStatus status; int ship; QString digest; QString seed; GameCell(CellStatus s) : status(s), ship(-1) {} }; GameBoard(QObject *parent = 0); void init(CellStatus s, bool genseed); void makeShipRandomPosition(); void calculateCellsHash(); bool updateCellDigest(int pos, const QString &digest); bool updateCell(int pos, CellStatus cs, const QString &seed); bool updateShipDigest(int length, const QString &digest); void shot(int pos); GameShip::ShipType shipDirection(int pos); int findAndInitShip(int pos); QRect shipRect(int snum, bool margin) const; void setShipDestroy(int n, bool margin); const GameCell &cell(int pos) const; QStringList toStringList(bool covered) const; bool isAllDestroyed() const; private: static QString genSeed(int len); GameShip *findShip(int length, const QString &digest); bool isShipPositionLegal(int shipNum); void fillShipMargin(int n); private: QList cells_; QList ships_; signals: void shipDestroyed(int snum); }; class GameModel : public QObject { Q_OBJECT public: enum GameStatus { StatusNone, StatusError, StatusBoardInit, StatusMyTurn, StatusWaitingTurnAccept, StatusWaitingOpponent, StatusWin, StatusLose, StatusDraw }; GameModel(QObject *parent = 0); void init(); GameStatus status() const { return status_; } void setStatus(GameStatus s); void setError(); bool initOpponentBoard(const QStringList &data); bool uncoverOpponentBoard(const QStringList &data); const GameBoard &myBoard() const { return myBoard_; } const GameBoard &oppBoard() const { return opBoard_; } void setOpponentDraw(bool draw); bool isOpponentDraw() const { return oppDraw_; } void setOpponentAcceptedDraw(bool accept); void opponentResign(); void opponentTurn(int pos); bool handleResult(); bool handleTurnResult(const QString &res, const QString &seed); QString lastShotResult() const; QString lastShotSeed() const; QStringList getUncoveredBoard() const; private: GameStatus status_; GameBoard myBoard_; GameBoard opBoard_; int lastShot_; bool draw_; bool oppDraw_; bool myAccept_; bool oppResign_; bool myResign_; bool destroyed_; private slots: void myShipDestroyed(); public slots: void sendCoveredBoard(); void localTurn(int pos); void setLocalDraw(bool draw); void localAccept(); void localResign(); signals: void acceptDraw(); void statusChanged(); void myBoardUpdated(int x, int y, int width, int height); void oppBoardUpdated(int x, int y, int width, int height); void gameEvent(QString data); }; #endif // GAMEMODEL_H plugins-1.5/dev/battleshipgameplugin/gamesessions.cpp000066400000000000000000000551411336777360500232610ustar00rootroot00000000000000/* * gamesessionlist.cpp - Battleship Game plugin * Copyright (C) 2014 Aleksey Andreev * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include #include "gamesessions.h" #include "options.h" #include "invitedialog.h" #define TIMEOUT_INTERVAL_SECS 60*60*1 // One hour GameSessionList::GameSessionList(QObject *parent) : QObject(parent) , stanzaId_(qrand() % 10000) { } GameSessionList::~GameSessionList() { // qDeleteAll(list_); because error: 'virtual GameSession::~GameSession()' is private QListvals = list_.values(); while(!vals.isEmpty()) delete vals.takeFirst(); } GameSessionList *GameSessionList::instance_ = NULL; GameSessionList *GameSessionList::instance() { if (!instance_) instance_ = new GameSessionList(); return instance_; } void GameSessionList::reset() { if (instance_) { delete instance_; instance_ = NULL; } } GameSession *GameSessionList::createSession(int account, const QString &jid, bool first, const QString &gameId) { if (findGame(account, jid, gameId)) return NULL; GameSession *gs = new GameSession(this, account, jid, first, gameId); list_[generateKey(account, jid, gameId)] = gs; connect(gs, SIGNAL(sendStanza(int,QString)), this, SIGNAL(sendStanza(int,QString))); connect(gs, SIGNAL(doPopup(QString)), this, SIGNAL(doPopup(QString))); connect(gs, SIGNAL(playSound(QString)), this, SIGNAL(playSound(QString))); connect(gs, SIGNAL(doInviteEvent(int,QString,QString,QObject*,const char*)), this, SIGNAL(doInviteEvent(int,QString,QString,QObject*,const char*))); return gs; } void GameSessionList::removeGame(GameSession *gs) { list_.remove(list_.key(gs)); gs->deleteLater(); } GameSession *GameSessionList::findGame(int account, const QString &jid, const QString &gameId) { QString key = generateKey(account, jid, gameId); GameSession *gs = list_.value(key, NULL); return gs; } GameSession *GameSessionList::findGameByStanzaId(int account, const QString &jid, const QString &stanzaId) { QListl = list_.values(); foreach (GameSession *gs, l) if (gs->account_ == account && gs->jid_ == jid && gs->stanzaId_ == stanzaId) return gs; return NULL; } bool GameSessionList::processIncomingIqStanza(int account, const QDomElement &xml, const QString &accStatus, bool fromPrivate) { const QString from = xml.attribute("from"); const QString iqType = xml.attribute("type"); if (iqType == "set") { QDomElement childEl = xml.firstChildElement(); if (childEl.isNull() || childEl.attribute("xmlns") != "games:board" || childEl.attribute("type") != "battleship") return false; const QString gameId = childEl.attribute("id"); if (gameId.isEmpty()) return true; GameSession *gs = NULL; const QString tagName = childEl.tagName(); if (tagName == "create") { Options *opt = Options::instance(); if ((!opt->getOption(constDndDisable).toBool() || accStatus != "dnd") && (!fromPrivate || !opt->getOption(constConfDisable).toBool())) { bool err = true; bool first = true; const QString firstStr = childEl.attribute("first"); if (firstStr.toLower() == "true") { first = false; err = false; } else if (firstStr.toLower() == "false") err = false; if (!err) gs = createSession(account, from, first, gameId); } } else if ((gs = findGame(account, from, gameId)) != NULL) { if (tagName == "board") { if (!gs->opBoardChecked_) { if (gs->stage_ == GameSession::StageInitBoard) gs->initOpponentBoard(childEl); else if (gs->stage_ == GameSession::StageShowBoard) { gs->checkOpponentBoard(childEl); } if (!gs->opBoardChecked_) gs->status_ = GameSession::StatusError; } else gs->status_ = GameSession::StatusError; } else if (tagName == "turn") { if (gs->stage_ == GameSession::StageShooting && gs->status_ == GameSession::StatusWaitOpponent) gs->opponentTurn(childEl); else gs->status_ = GameSession::StatusError; } } if (gs) { if (gs->stage_ != GameSession::StageNone) gs->sendIqResponse(xml.attribute("id")); else gs->stanzaId_ = xml.attribute("id"); gs->executeNextAction(); } else sendErrorIq(account, from, xml.attribute("id")); return true; } else { GameSession *gs = findGameByStanzaId(account, from, xml.attribute("id")); if (gs) { if (iqType == "result") { bool err = true; switch (gs->stage_) { case GameSession::StageInvitation: if (gs->status_ == GameSession::StatusWaitInviteConfirmation) { gs->status_ = GameSession::StatusNone; err = false; } break; case GameSession::StageInitBoard: case GameSession::StageShowBoard: if (gs->status_ == GameSession::StatusWaitBoardVerification) { gs->myBoardChecked_ = true; gs->status_ = GameSession::StatusNone; err = false; } case GameSession::StageShooting: if (gs->status_ == GameSession::StatusWaitShotConfirmation) { gs->status_ = GameSession::StatusNone; err = !gs->handleTurnResult(xml); } case GameSession::StageEnd: err = false; default: break; } if (err) gs->status_ = GameSession::StatusError; } else if (gs->stage_ == GameSession::StageInvitation) { QString msg = tr("From: %1
The game was rejected").arg(from); QString errMsg = getErrorMessage(xml); if (!errMsg.isEmpty()) msg.append(QString(" (%1)").arg(errMsg)); doPopup(msg); gs->endSession(); gs = NULL; } else gs->status_ = GameSession::StatusError; if (gs) gs->executeNextAction(); return true; } } return false; } void GameSessionList::invite(int account, const QString &jid, const QStringList &resList) { GameSession *gs = createSession(account, jid, true, QString()); if (gs) gs->invite(resList); } void GameSessionList::sendErrorIq(int account, const QString &jid, const QString &id) { emit sendStanza(account, XML::iqErrorString(jid, id)); } QString GameSessionList::generateKey(int account, const QString &jid, const QString &gameId) { return QString("%1:%2:%3").arg(QString::number(account)).arg(jid).arg(gameId); } QString GameSessionList::getStanzaId(bool bigOffset) { if (bigOffset) stanzaId_ += (qrand() % 50) + 5; else stanzaId_ += (qrand() % 5) + 2; return "bsg_" + QString::number(stanzaId_); } void GameSessionList::updateGameKey(GameSession *gs) { list_.remove(list_.key(gs)); list_[generateKey(gs->account_, gs->jid_, gs->gameId_)] = gs; } QString GameSessionList::getErrorMessage(const QDomElement &xml) { QDomElement el = xml.firstChildElement("error"); if (!el.isNull()) { el = el.firstChildElement("error-message"); if (!el.isNull()) return el.text(); } return QString(); } // ---------------- XML -------------------- QString XML::escapeString(const QString &str) { #ifdef HAVE_QT5 return str.toHtmlEscaped().replace("\"", """); #else return Qt::escape(str).replace("\"", """); #endif } QString XML::iqErrorString(const QString &jid, const QString &id) { QString stanza = QString("\n\n" "Not Acceptable\n\n") .arg(XML::escapeString(jid)) .arg(XML::escapeString(id)); return stanza; } // -------------- GameSession ------------------- GameSession::GameSession(GameSessionList *gsl, int account, const QString &jid, bool first, const QString &gameId) : QObject(NULL) , gsl_(gsl) , stage_(StageNone) , status_(StatusNone) , account_(account) , jid_(jid) , first_(first) , gameId_(gameId) , modifTime_(QDateTime::currentDateTime()) , inviteDlg_(NULL) , boardWid_(NULL) , myBoardChecked_(false) , opBoardChecked_(false) , resign_(false) { } GameSession::~GameSession() { if (!inviteDlg_.isNull()) inviteDlg_->close(); if (!boardWid_.isNull()) boardWid_->close(); } void GameSession::executeNextAction() { if (stage_ == StageEnd) return; bool modif = false; while (true) { GameStage old_stage = stage_; GameStatus old_status = status_; if (status_ != StatusError) { switch (stage_) { case StageNone: stage_ = StageInvitation; status_ = StatusWaitInviteConfirmation; processIncomingInvite(); break; case StageInvitation: if (status_ == StatusNone) { myBoardChecked_ = false; opBoardChecked_ = false; stage_ = StageInitBoard; } break; case StageInitBoard: if (status_ == StatusNone) { if (myBoardChecked_) { if (opBoardChecked_) { stage_ = StageShooting; startGame(); } } else { status_ = StatusWaitBoardVerification; initBoard(); } } break; case StageShooting: if (status_ == StatusNone) { if (checkEndGame()) { stage_ = StageShowBoard; status_ = StatusNone; myBoardChecked_ = false; opBoardChecked_ = false; } else if (!isMyNextTurn()) status_ = StatusWaitOpponent; } break; case StageShowBoard: if (status_ == StatusNone) { if (myBoardChecked_) { if (opBoardChecked_) stage_ = StageEnd; } else { status_ = StatusWaitBoardVerification; sendUncoveredBoard(); } } break; case StageEnd: if (status_ == StatusNone) { checkEndGame(); if (status_ == StatusNone) status_ = StatusError; } break; } } else if (stage_ != StageEnd) { setError(); stage_ = StageEnd; } if (old_stage == stage_ && old_status == status_) break; modif = true; } if (modif) modifTime_ = QDateTime::currentDateTime(); if (inviteDlg_.isNull() && boardWid_.isNull()) { if (stage_ == StageEnd) endSession(); else if (timer_.isNull()) setTimer(); } } void GameSession::processIncomingInvite() { if (!boardWid_.isNull()) showInvitationDialog(); else appendInvitationEvent(); } void GameSession::appendInvitationEvent() { emit doInviteEvent(account_, jid_, tr("%1: Invitation from %2").arg("Battleship Game Plugin").arg(jid_), this, SLOT(showInvitationDialog())); } void GameSession::showInvitationDialog() { inviteDlg_ = new InvitationDialog(jid_, first_, boardWid_.data()); connect(inviteDlg_.data(), SIGNAL(accepted()), this, SLOT(acceptInvitation())); connect(inviteDlg_.data(), SIGNAL(rejected()), this, SLOT(rejectInvitation())); inviteDlg_->show(); } void GameSession::acceptInvitation() { status_ = StatusNone; sendStanzaResult(stanzaId_); executeNextAction(); } void GameSession::rejectInvitation() { GameSessionList::instance()->sendErrorIq(account_, jid_, stanzaId_); endSession(); } void GameSession::invite(const QStringList &resList) { QWidget *parent = NULL; if (!boardWid_.isNull()) parent = boardWid_.data(); InviteDialog *dlg = new InviteDialog(jid_.section('/', 0, 0), resList, parent); connect(dlg, SIGNAL(acceptGame(QString,bool)), this, SLOT(sendInvite(QString,bool))); connect(dlg, SIGNAL(rejected()), this, SLOT(endSession())); inviteDlg_ = dlg; dlg->show(); } void GameSession::sendInvite(QString jid, bool first) { first_ = first; jid_ = jid; modifTime_ = QDateTime::currentDateTime(); boardStatus_ = QString(); generateGameId(); gsl_->updateGameKey(this); stage_ = StageInvitation; status_ = StatusWaitInviteConfirmation; stanzaId_ = gsl_->getStanzaId(true); QString stanza = QString("" "\n") .arg(XML::escapeString(jid)) .arg(stanzaId_) .arg(XML::escapeString(gameId_)) .arg((first) ? "true" : "false"); emit sendStanza(account_, stanza); } void GameSession::generateGameId() { gameId_ = "battleship_" + QString::number(qrand(), 16) + QString::number(qrand(), 16) + QString::number(qrand(), 16); } void GameSession::endSession() { if (boardWid_.isNull()) gsl_->removeGame(this); else if (stage_ != StageEnd) { stage_ = StageEnd; status_ = StatusError; } } void GameSession::setError() { status_ = StatusError; if (!boardWid_.isNull()) boardWid_.data()->setError(); } void GameSession::sendIqResponse(const QString &id) { if (status_ == StatusError) gsl_->sendErrorIq(account_, jid_, id); else { QString body; if (stage_ == StageShooting && !resign_) { body = QString("\n" "\n\n") .arg(XML::escapeString(gameId_)) .arg(lastTurnResult_) .arg(XML::escapeString(lastTurnSeed_)); } sendStanzaResult(id, body); } } void GameSession::sendStanzaResult(const QString &id, const QString &body) { QString stanza = QString("\n"); else stanza.append(">\n" + body + "\n"); emit sendStanza(account_, stanza); } void GameSession::initBoard() { if (boardWid_.isNull()) { boardWid_ = new PluginWindow(jid_); connect(boardWid_.data(), SIGNAL(gameEvent(QString)), this, SLOT(boardEvent(QString))); connect(boardWid_.data(), SIGNAL(destroyed()), this, SLOT(endSession())); } boardWid_->initBoard(); boardWid_->show(); } void GameSession::initOpponentBoard(const QDomElement &xml) { opBoardChecked_ = false; bool cells[100]; int cellsCnt = 0; QListships; for (int i = 0; i < 100; ++i) cells[i] = false; ships.append(5); ships.append(4); ships.append(3); ships.append(2); ships.append(2); ships.append(1); ships.append(1); QStringList data("init-opp-board"); QDomElement el = xml.firstChildElement(); while (!el.isNull()) { const QString nm = el.nodeName(); if (nm == "cell") { int row = el.attribute("row").toInt(); int col = el.attribute("col").toInt(); QString hash = el.attribute("hash"); if (row < 0 || row >= 10 || col < 0 || col >= 10 || hash.length() != 40) return; int pos = row * 10 + col; if (cells[pos]) return; data.append(QString("cell;%1;%2").arg(pos).arg(hash)); cells[pos] = true; ++cellsCnt; } else if (nm == "ship") { int len = el.attribute("length").toInt(); QString hash = el.attribute("hash"); if (!ships.removeOne(len) || hash.length() != 40) return; data.append(QString("ship;%1;%2").arg(len).arg(hash)); } el = el.nextSiblingElement(); } if (cellsCnt == 100 && ships.empty() && !boardWid_.isNull()) opBoardChecked_ = (boardWid_->dataExchange(data).first() == "ok"); } void GameSession::checkOpponentBoard(const QDomElement &xml) { opBoardChecked_ = false; bool cells[100]; int cellsCnt = 0; for (int i = 0; i < 100; ++i) cells[i] = false; QStringList data("check-opp-board"); QDomElement el = xml.firstChildElement(); while (!el.isNull()) { if (el.nodeName() == "cell") { int row = el.attribute("row").toInt(); int col = el.attribute("col").toInt(); QString seed = el.attribute("seed"); if (row < 0 || row >= 10 || col < 0 || col >= 10 || seed.isEmpty()) return; int pos = row * 10 + col; if (cells[pos]) return; QString ship = el.attribute("ship").toLower(); if (ship == "true") ship = "1"; else if (ship != "1") ship = "0"; data.append(QString("%1;%2;%3").arg(pos).arg(ship).arg(seed)); cells[pos] = true; ++cellsCnt; } el = el.nextSiblingElement(); } if (cellsCnt == 100 && !boardWid_.isNull()) opBoardChecked_ = (boardWid_->dataExchange(data).first() == "ok"); } void GameSession::opponentTurn(const QDomElement &xml) { bool err = false; int pos = -1; int draw = 0; int resign = 0; int accept = 0; QDomElement el = xml.firstChildElement(); while (!el.isNull()) { const QString tagName = el.tagName(); if (tagName == "shot") { err = true; const QString rowStr = el.attribute("row"); const QString colStr = el.attribute("col"); if (rowStr.isEmpty() || colStr.isEmpty() || pos != -1) break; int row = rowStr.toInt(); int col = colStr.toInt(); if (row < 0 || row >= 10 || col < 0 || col >= 10) break; pos = row * 10 + col; err = false; } else if (tagName == "draw") ++draw; else if (tagName == "accept") ++accept; else if (tagName == "resign") ++resign; el = el.nextSiblingElement(); } if (!err && draw + accept + resign <= 1 && (pos != -1 || resign + accept != 0)) { QStringList data("turn"); if (draw) data.append("draw"); if (accept) data.append("accept"); if (resign) data.append("resign"); if (pos != -1) data.append(QString("shot;%1").arg(pos)); QStringList res; if (!boardWid_.isNull()) res = boardWid_->dataExchange(data); if (res.takeFirst() == "ok") { while (!res.isEmpty()) { QString s = res.takeFirst(); QString t = s.section(';', 0, 0); if (t == "result") { lastTurnResult_ = s.section(';', 1, 1); lastTurnSeed_ = s.section(';', 2); } else if (t == "status") { boardStatus_ = s.section(';', 1); } } status_ = StatusNone; } else status_ = StatusError; } else status_ = StatusError; } bool GameSession::handleTurnResult(const QDomElement &xml) { if (boardWid_.isNull()) return false; QStringList data("turn-result"); QDomElement el = xml.firstChildElement("turn"); if (!el.isNull()) { if (el.attribute("xmlns") != "games:board" || el.attribute("type") != "battleship" || el.attribute("id") != gameId_) return false; el = el.firstChildElement("shot"); if (el.isNull()) return false; QString res = el.attribute("result"); if (res != "miss" && res != "hit" && res != "destroy") return false; QString seed = el.attribute("seed"); data.append(QString("shot-result;%1;%2").arg(res).arg(seed)); } QStringList res = boardWid_->dataExchange(data); QString s = res.takeFirst(); if (s == "ok") { while (!res.isEmpty()) { s = res.takeFirst(); if (s.section(';', 0, 0) == "status") { boardStatus_ = s.section(';', 1); break; } } return true; } return false; } void GameSession::boardEvent(QString data) { QStringList dataList = data.split('\n'); QString dataStr = dataList.takeFirst(); QString body; if (dataStr == "covered-board") { body = QString("\n") .arg(gameId_); while (!dataList.isEmpty()) { dataStr = dataList.takeFirst(); QString str = dataStr.section(';', 0, 0); if (str == "cell") { int pos = dataStr.section(';', 1, 1).toInt(); int row = pos / 10; int col = pos % 10; QString hash = dataStr.section(';', 2); body.append(QString("\n") .arg(row) .arg(col) .arg(hash)); } else if (str == "ship") { int len = dataStr.section(';', 1, 1).toInt(); QString hash = dataStr.section(';', 2); body.append(QString("\n") .arg(len) .arg(hash)); } } body.append("\n"); } else if (dataStr == "turn") { int pos = -1; bool draw = false; bool accept = false; bool resign = false; while (!dataList.isEmpty()) { dataStr = dataList.takeFirst(); QString str = dataStr.section(';', 0, 0); if (str == "pos") pos = dataStr.section(';', 1).toInt(); else if (str == "draw") draw = true; else if (str == "accept") accept = true; else if (str == "resign") resign = true; } body = QString("\n") .arg(XML::escapeString(gameId_)); if (pos != -1) { int row = pos / 10; int col = pos % 10; body.append(QString("\n").arg(row).arg(col)); } if (draw) body.append("\n"); if (accept) body.append("\n"); if (resign) body.append("\n"); body.append("\n"); status_ = StatusWaitShotConfirmation; if (accept || resign) boardStatus_ = "end"; } else if (dataStr == "new-game") { invite(QStringList(jid_.section('/', 1))); return; } stanzaId_ = gsl_->getStanzaId(false); QString stanza = QString("\n") .arg(XML::escapeString(jid_)) .arg(stanzaId_); stanza.append(body); stanza.append("\n"); emit sendStanza(account_, stanza); } void GameSession::startGame() { if (!boardWid_.isNull()) { QStringList data("start"); if (first_) data.append("first"); QStringList res = boardWid_->dataExchange(data); if (res.takeFirst() == "ok") { while (!res.isEmpty()) { QString s = res.takeFirst(); if (s.section(';', 0, 0) == "status") { boardStatus_ = s.section(';', 1); break; } } } else boardStatus_ == QString(); } } bool GameSession::checkEndGame() { return (boardStatus_ == "end"); } bool GameSession::isMyNextTurn() { return (boardStatus_ == "turn"); } void GameSession::sendUncoveredBoard() { if (boardWid_.isNull()) return; QStringList res = boardWid_->dataExchange(QStringList("get-uncovered-board")); QString body; while (!res.isEmpty()) { QString dataStr = res.takeFirst(); int pos = dataStr.section(';', 0, 0).toInt(); int row = pos / 10; int col = pos % 10; QString ship = dataStr.section(';', 1, 1); QString seed = dataStr.section(';', 2); body.append(QString("\n") .arg(row) .arg(col) .arg(ship) .arg(XML::escapeString(seed))); } stanzaId_ = gsl_->getStanzaId(false); QString stanza = QString("\n") .arg(XML::escapeString(jid_)) .arg(stanzaId_); stanza.append(QString("\n") .arg(XML::escapeString(gameId_))); stanza.append(body); stanza.append("\n\n"); emit sendStanza(account_, stanza); } void GameSession::setTimer() { timer_ = new QTimer(this); timer_->setSingleShot(true); connect(timer_.data(), SIGNAL(timeout()), this, SLOT(timeout())); timer_->setInterval(TIMEOUT_INTERVAL_SECS*1000); } void GameSession::timeout() { QDateTime currTime = QDateTime::currentDateTime(); if (inviteDlg_.isNull() && boardWid_.isNull()) { if (modifTime_.secsTo(currTime) >= TIMEOUT_INTERVAL_SECS) endSession(); } else delete timer_; } plugins-1.5/dev/battleshipgameplugin/gamesessions.h000066400000000000000000000110031336777360500227130ustar00rootroot00000000000000/* * gamesessionlist.cpp - Battleship game plugin * Copyright (C) 2014 Aleksey Andreev * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef GAMESESSIONLIST_H #define GAMESESSIONLIST_H #include #include #include #include #include #include #include "pluginwindow.h" class GameSession; namespace XML { QString escapeString(const QString &str); QString iqErrorString(const QString &jid, const QString &id); } class GameSessionList : public QObject { Q_OBJECT public: static GameSessionList *instance(); static void reset(); GameSession *createSession(int account, const QString &jid, bool first, const QString &gameId); void updateGameKey(GameSession *gs); void removeGame(GameSession *gs); GameSession *findGame(int account, const QString &jid, const QString &gameId); GameSession *findGameByStanzaId(int account, const QString &jid, const QString &stanzaId); bool processIncomingIqStanza(int account, const QDomElement &xml, const QString &accStatus, bool fromPrivate); void invite(int account, const QString &jid, const QStringList &resList); QString getStanzaId(bool bigOffset); void sendErrorIq(int account, const QString &jid, const QString &id); private: GameSessionList(QObject *parent = 0); ~GameSessionList(); QString generateKey(int account, const QString &jid, const QString &gameId); static QString getErrorMessage(const QDomElement &xml); private: static GameSessionList *instance_; QHash list_; int stanzaId_; signals: void sendStanza(int, QString); void doPopup(QString); void playSound(QString); void doInviteEvent(int, QString, QString, QObject *, const char *); }; class GameSession : public QObject { Q_OBJECT public: enum GameStage { StageNone, StageInvitation, StageInitBoard, StageShooting, StageShowBoard, StageEnd }; enum GameStatus { StatusNone, StatusError, StatusWaitInviteConfirmation, StatusWaitBoardVerification, StatusWaitShotConfirmation, StatusWaitOpponent }; typedef QPointer Timer; typedef QPointer InviteDlg; typedef QPointer BoardWidget; void executeNextAction(); void invite(const QStringList &resList); void initOpponentBoard(const QDomElement &xml); void checkOpponentBoard(const QDomElement &xml); void opponentTurn(const QDomElement &xml); bool handleTurnResult(const QDomElement &xml); private: friend class GameSessionList; GameSession(GameSessionList *gsl, int account, const QString &jid, bool first, const QString &gameId); ~GameSession(); void processIncomingInvite(); void appendInvitationEvent(); void generateGameId(); void sendIqResponse(const QString &id); void sendStanzaResult(const QString &id, const QString &body = QString()); void initBoard(); void setError(); void startGame(); bool checkEndGame(); bool isMyNextTurn(); void sendUncoveredBoard(); void setTimer(); private: GameSessionList *gsl_; GameStage stage_; GameStatus status_; int account_; QString jid_; bool first_; QString gameId_; QString stanzaId_; QDateTime modifTime_; Timer timer_; InviteDlg inviteDlg_; BoardWidget boardWid_; bool myBoardChecked_; bool opBoardChecked_; bool resign_; //int lastTurnPos_; //bool lastTurnMy_; QString lastTurnResult_; QString lastTurnSeed_; QString boardStatus_; private slots: void sendInvite(QString jid, bool first); void acceptInvitation(); void rejectInvitation(); void endSession(); void boardEvent(QString data); void timeout(); public slots: void showInvitationDialog(); signals: void sendStanza(int, QString); void doPopup(const QString); void playSound(const QString); void doInviteEvent(int, QString, QString, QObject *, const char *); }; #endif // GAMESESSIONLIST_H plugins-1.5/dev/battleshipgameplugin/img/000077500000000000000000000000001336777360500206235ustar00rootroot00000000000000plugins-1.5/dev/battleshipgameplugin/img/battleship.svg000066400000000000000000000204111336777360500235010ustar00rootroot00000000000000 image/svg+xml plugins-1.5/dev/battleshipgameplugin/img/battleship256.png000066400000000000000000000506731336777360500237400ustar00rootroot00000000000000PNG  IHDR!* sBIT|d pHYs lltEXtSoftwarewww.inkscape.org< IDATxyt}EDfUp vnIݔڒ(cY>d{)dcw}C̬fsh~Ik;#{$W-Kj>$6A} W H(^ }E13bbӹsp.T*EP(xii̙3|ٳg8w8U |EwwXXXmmmP( TT RJ("Hh}H$yfyy9l6hii N>m0X @vCa O/_BAI)]!~S7Q"af@P!`" 1@tƘ2 8NR1͛ٳ&Xbp8uZ;b1~uݖ  !h#6fn D"RĴc̬,2"7K)}ϥ|B`'nN @VC.\?ZXXHz -8>"j!4&) B2B303af2@23/"1f$Mcf9"J !BG!e؅mj.3#4Zc"a MAPYfd!f)뺓,fҙ3gAC @̦AD}N9rB !c Ga":&< 'HK))R"2ϯB  A`1:1faqf`~cq|ߟikk]pA;wl9b,|rjqqq8Ap D+RRJqQnF`C\. ƘZ{Zef5 efNW\'<່ !BNqJ)PJ(BcHJIZkZKuJkjicRpŋ ++N.//Q"noRޯjw]uG(HJ !o7JI)IJz'}?AD1\~}`Xbzgv) "z;M8"]mi7J%!G!RÈ|sW}_---M|EJy8m_ < ID]? !f\SSS6ɨa@tbv%̔H$T*!x)"_)UwRq8#II)Dt4Ͷ\xQtY7XbjAϟą ?˗/;/^L !ZKp)eR*UuBJ&)"zK&b]ٳgkTGG7q]7iR>!!A)eloWAJ )ֺGKKK z꩝.Cً3gΈg}1Ƥ\mUJ}Gk}T)k9&_)1!XDtR)uH)JYj3{=jii7QZ(eIQR!BRBJ+[rF(^Pw~vӒN;@OGp:D0s4[OCD8R)ED4 )p2Z`ryO:|[ѫz !8KJFDML="D$P8coe֞ʳ!m\قm"=&1KDo"SD&N!D")tBYz(h/I/Pd|:lCXϟqqxXJyHѢJH)U[>MLo0 6xbXbvw-Jd!I!B4)8לۨDƯf r<kmm{9Vsg>%lI&DŽBGRDs2tɤp]\Eԟ$2~Zo!RTꩧFb`o@x;B'_:{nc\.RB<"xPѕH$a;an~kAs:J& wTD{Rh^4rZ<H}8D&pl֝z'V ZhcQS`3W|9|>yf? @sIcB33Gnp=PG͢k/($Zf61\ RM̌w٠Am@, .bfY-CQˬ2<֖s{wZ{KA1 [0Mf`P1YTK_RЈ}И?/thCB#;rة@`d}~7 n(ۏr^c3/cy3J)|ߟ/JٳӍ @A?liiIRʇ1쬿=a4.\===){-𘔲+RJ%({~.Jֺ G( v&"rY%V"ak_5%h3gsٳgGÀ]~]XX8~!ēBRmJ)7R"U]!8}}Z 1Wf'p$l"!p`,eBfړR_^J8NT*h}͜;wG ?"BD1? 88NG"pǡ䟍SU(Z@JsjK~f~E1fq\Z af8 @cdRB@k<Ν;DFǿWb/BRƘPJu#d2H$H)uƯ6BDvE}co)c9 `3*J f2L}oC%@\pǎ Ҋ XَQX,  <" v.IA 3lhf.1s:Yf1L !CWgYZZZ*mF:#I)hǃ Zh<PmLq%!b`fpnmmB\5Ƥcz1Zzc%D} yxsE1CD̎1F*8kc8֞~KKK011aΞ=k>{}{ ʶbxPqBJy C!.|aЖy{J06"Ƅy )hwa!D"`iI2L0tq)9::tww;|%8$"&H|EigΜib,?="ʰP(,-- i{X6AG,11{^6&&&aL:\]JW_@vf#߁]@N-0`c/.@!p6m,Acu,Sb#\xaYH_-"<]:"CH膝fXA؍{=7ai3X H~[xFא /њ{mD#)K &f @L&=L,11{Xbb0ab &f @L&=L,11{Xbb0ab &f/ حŋ?9B! 5Bcv815RqR)455u]Q߽6c GP`SX!4:C JZk,,,`bbX\\NB@)=z'ODOODzJ%C)\.|>?bcH&hooǑ#Gp1Z <@2q;C,uH("8:6H(GJK,1 @P(4? 8[2ƠX,4?PuM,L(LMaUH8N]Kl)|uM,J8(afi :0y(,."m/Xc`<rKK0̐unL } n$%3D!,iX! I$;;ގdN#|cEd 3wH15^B)tM8puu!YÀE߇;3k EB@Kbg R)$ǾGwo/RT] ߀e X!@RB&plkC=v]8͐HJNc`7@ ŀAq abb\X^^&[o8t;& Vq˿K`q5 cxxCCC[J)>|ǎñcۋ^8qMMM[1[K,ꫯҥKx"}zEhʑRMozN>G}4]6ds|S !~0L~8NRJ%gffhZF).Z(C W!:"weм%4|x!!:0gy_kfub!S~?+gD ;ZO'9Nbf( 6t:?z(zzz|^3L-C\.q6,//ov`93 b* 6ADͰ}p`>'NO<GEoo/:;;﹬d2n޼W^y׮]۬=Ofm&-:jxg;v o{O<Z[[7"^yKxo& |'9{%F,[D+mmmo}?o}+|Q|>^{ _k/,,(}|#Ǹk5gM)ܹ$jii#G~~##G,| 7aNh{Q"[xm DD/Ѯ_P"z /^o^gofq/ &@D6>?yo-fᵾ GD##D6|x/lUf~ {A^{ {~ o{ro |_ݲUf> Wh#ږn ]@DDnm af3m]v'0>AD_ {bݫp; 7~;fu%k &38WgsA[ --\ )aD[T['!l"jDpWf.mif.1yX!Ȉ>u`T޿cx"#I݂i{?gSXj&|vx ifT{ޞN߈j @$i/Sd[[Ǜ>˘ P"z'8K|E}6paRb@DNmY`֗*NO>ZN- ɞ":X̻̿~~3Kr4{Z[טcPM |V=K-m{Vȅ7m(R&> ltFgñgvQ?f?؎l>u^غ'ٓ@Dm(Nϲ։=Ǟ":/yxO /ºS.$Yj"P=jg϶|v-6d3~,ޖ>j<=3@D?}z3ՍKlYW7º'&|]O:/$'vZݦ< ̫[g"gn_5f`){Y?֝Ox߿Q{GOuaih/^%?֭@{*Ḫ֑j4ܪP %Dt @yoSnZakJ/m =l]ֱa/xHau!HDZz_Ue|f\9V`[zFn lKY藶HFխn"JzӪւNmOqYcHk yR>7c <σZC,aYڀ[g~ 1Nc` ,aOJ V?ƽ Km_qHztAO<.^իW}---XXX@SSTJDBhH!(1sS*JAPpPJ^{}H+{ kV,BƘ3``%fX= ,..b߾ 5cI\~{ccckb6lP~*|3`@ky~~ixxMRTI$$4FFF*K$xGD1ɓ'JP)3pddށYyq^Z`u4`%JvQ,ZWlvdpp0߯9<SkCo-c)e8^@4 snn߯rlvX,uXB[fAD v@1|>izzzƍ+WᕠN@*jujɭ<7<<+W7n'%c`mTn@Axd%7OLL$ġThmm8z.lV**]V}Z뗍1`w>ZsvШ1u[aP<(ܼA J)#l[9b<+I6T[E_fii1cuT\lMPpPkjP0JړɤH$h3籸XyvOOj\cvzzz*1??m Ak~W\Y{ RZلd\ZKRK6mTMMMtZ% B"̻ؖjV###"~Klv,w ~kikW1 ¥-(XՊ fUǶ6׷6wT e#rDl͓((J8u=eԮc[-Qoii cccu[u,(5Aq7LvR)u]!DssNz.bZuVݼW#zzj&跌*Al(bV\ȈL&;8lip$;GpUr?4447??sMo5~kp< `3JR:&m8J):x RԖDlſ'MŌtww#LV\n+ќi\z7o.f١R"l$ BCX}?U,SLƹq}㴸ݽ%à J1㷝V7 P,1337np__qF. | 52㎛hf]tIkr.GJ٫jvGJ)kS7<Z皚6;bb֣Z]Z<)cATB&kזFsA +0Jp>zZ8ywrrR)+RBJI#PKaqYƤV]"gY K̵kז''' x1?pP\0n.sǥRq&iA{{;\׽gX^^z.bZumyyDy 70׮]ˏOrKhy  n8跖ҭI28%Q%<8NJ)%طo=okUK{{wٻ|{"{9+[=`sF(OB__/N/--y-c̫NF0}(>y71NTrQr'@[[=% պxB~yܖ| /߹J˽qq###r効rJqtttvqqJTVw{1~ ,4;??KTR*@kk]' mE<BKK˦ٟƿw[Gf]rW={)_>w tn@CWܜ344$R$R$lJc1>{9Ͻz*._و܍羾>ohhhnnnzTzYkhAϚ|M E`@-Jn&qR)ծr"lD.a;"pѪ 01$;z,~|?00dJEVqDni}wLFI)8MX#sq]MRxߍ/˛ٍĝ Go6/ W|eXT6YBV1nXtgff{™3g|d2"?яpBhQY~333b5c̋@%M0(xyԔRw-Xxߌ__ݴm>|[mmm_e|pl|ķ6꥖gݼy,|>z3~kْN!@1syT:o([J):ujcX7TH5׮]ˇY~Zx7S{-[@,Q(`$ 'LJ e KFjy._l akrD4r cT-8>>Rf :SUBb.5!DQcmY~W\)gy2_-_Bwb",[PFقRJAD+قD Ncii鶿o4B_WVoju_n}}}pz ۲vY-ق ȈTJuJ)V7o߾l6]|X?}cx߾%lU$Q\r\|422]XXi>m-&j377$B$GV7PkYX֡P(OOnI虜g>X6I6ϼܵRRY_wǽh% Zb,8AD\"*@oo/oVao <]|;ǷP;}3.]lZX|Ik"VWDmtf jEPl6Kd- `;P.ǎٵ6 LMMU=744 :Ԫcusr^(^Z#0o#>Z^SHkMBL@"PKrYvff2kB[kZ+X-8 e2p@;BO\vj]`.@%tw͹L&S߲kvD+c;iV ttt NWĎ-{=1x.Nc=V=?T*2 "q}}}}~:z=7~sw;,m"0XOX,R&!"z@{8r=ZQŋl /^zѣ\&F#@?PTPiivv̎1F8q_W*~ŋ}h|}IB=qJߥKb%_ԙu"@E fgg p_ꫯnZ1V|D,{,wFtϝU߿o|7000]Q7dɓ}De\r'O2؟` !^=!Pj! CJ|KEȰm|o߯|\ߛ}_^1)SSSP6(/sQW"Xf Ƙ JW|/ @TZT(E{xJ%RITPJ$Du? Lڿ9Xʍ>2n{% >3H콏=SBwa͏ ?q09xb9X\eصZ5z=cyv2CCItv8pE=ZġC%ttX!p%Fxgj]y ^WwffZ뀈+^@6E{{lI%lX;1_a5mnYTdֽpR,Zk<3>"ŢܜRq ##ILOdU߼A}{}Rfg#ObtԶ̭ݫr~+Dùd2.mz{xO?pVd>װ[vmJ!E?S>,Μy:075ǓWO[faUh@W+[%Zwo l$&&\d2.mý+(JhfyOS3~` ">-^3_LOZ䪔WU!X\tX<~#GҢW;1|4%QԔ]z\mƁELO_{],@_G^34P*5XtWmdU\LMY!)[\oW| 2}^XPr12`)LMє|^֥%bb1l6ZOv\,O> cfg_cʤze*|Yiegflȵ!(nۚ2$ff\&14d |@wNz3`y#uqzS!g SS{ 65Vae> ;_e VBP]"hll. kLOK\ã VkVS~u/q(Ggg]9~8'D%׮5avv朕yvZno.#ڈE U. awyXO;C0Y /X _ /!`Bh+g+5-vְӰ7ŪW`HReQRޅn&pfo܌K;YpRNEN i;T8;D?7PǑۅOVB7~~+N/T:eGے{X5<a60۝ R`2Sn}0V#ZҡRE y*GQR ߯HdDIhͽߺI:oa_1+R?:|XqX5\y"DviN:;X5tV^kzj/x>" <δmς#x\}TZ} unkJwu[e7*6G`ܯn: `)lS}s IDATIؖ$$li_x.jи7ʧV[  9׎n(.27"eawZ|غP .땅m]}@2n{g t]Vaklolq<UGF>,Rj >hҔBكE4]k]."2z@L`E¡b5Ck#غP߄K[&y;Em ?k lk&vղC2X>l0g@/~VD!D 6X>R.7X!(t*|2 wOM5*a%iXO-J:ao>-$l1뉆ЏbՋ^6/Ah jk;T5mv/VXGV]3V@Virz օe5{{Qj޹UUqBB_R (b6>6H@+!@E !1  ZHHh A$Pb- Jb;}tN;}Σe]~X{ݳ>gwfz=3s]w^{M۰| h> @dߋ-:12`\XY"a]\r=S7ԍBOGJ71oJ,om`.#AD'#X%s`D0$2 is޾ڇb3FmtcZmxH>$ʮ 7~_ 7S|3PB?^v48ʸm+ p9z8sq]=q?bZA;F H5Cˠ#woVlyE2dYx}^v@O_'8n7(m#( lIJoǨ0WB"qN.l`T_y('=q4xI1҈7iFh(*PGE(s2!]7azZ*j,'_8\3u`360]/!g>7Ur" zS+&xFޑ>W.OF}MWfHn%#A6v, >0$Bl |ъ- vR{p26XxLW^lp;T]ZxTZWg8xhW'h~/"OUU VQ] \dpHA~vlߌyA:H,r U\m`~sI ͈ty#q'l7^AcNlFER8scw6`+#<數ψ1U}1*[=B,"5f[34I9@Dnl\v xGq1iЦV®Ì%@v Lx16J=05CkpܥOչEw`V q>FyҩZ|w`=)BDyN^ڎ$3:p|)s=Q[ڱPi$ `l|SH\[g2(sH(̧vӽq8i;![1a :ڵID`&xx`RՇ(ŗY#yXkŲ1  9vl!;!uD`UˎKTZ3yu2 D`x]#MmCлŢ%R c̿[VQ}lag;b\zɣzg뱗ĠZ{H TU7R%X%"."/%噈N-Xǜ3j ["T"| 'ãb}7&>5?pRU(burc6&i2?\cY;t#(Pq$9$v Wwpσ؏u :Y|aK=Ue A 8[DnUr!eF5{v&IlRkH:d ܜk E#SwWvar cC{Lj-pE,b0~L'Iwá˽p~r>q67bDڑ,, 64_ǎcpyAd$z0m7gp*ZD>v!"T`U, vcD:S& )9}KXb+4C 6l #*}z7 3,U/Ed\nD2;,&Jig%dP#Tw}CkGEdJz-)"6uU d ]6'c."%;C."`To)M^fd0Dj܀pTfvj{%"ȷ0U zվ U]~공&mcP(ɘ,m,Jeb"za}a #:@UUuj(6Y'"Bb˘L qA\+T;FbP7+>:)"kEdqybYE潀}Zк0^dNP՜R{;@<,"&2rym_}Zr 4k0寜w[^a,oG%HD~%WTC`{u-daU8?-øO A۩m[ 0BX]iQUc "s1 R,-z1Vcx+Um2T@F Fp Ijq+!{4#~Jɿ #)XE)XqQJ^YB!V7Mma nJR@Fc! <BU5z"d7`Wf;?RShIENDB`plugins-1.5/dev/battleshipgameplugin/invitationdialog.ui000066400000000000000000000030361336777360500237540ustar00rootroot00000000000000 InvitationDialog 0 0 202 72 0 0 Gomoku Game Plugin - Invitation Qt::Horizontal 0 20 Accept Reject plugins-1.5/dev/battleshipgameplugin/invitedialog.cpp000066400000000000000000000047251336777360500232410ustar00rootroot00000000000000/* * invitedialog.cpp - Battleship Game plugin * Copyright (C) 2014 Aleksey Andreev * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "invitedialog.h" InviteDialog::InviteDialog(const QString &jid, const QStringList &resources, QWidget *parent) : QDialog(parent) , ui(new Ui::InviteDialog) , accepted_(false) , jid_(jid) { setAttribute(Qt::WA_DeleteOnClose); ui->setupUi(this); ui->leJid->setText(jid_); ui->cbResource->addItems(resources); adjustSize(); connect(ui->btnFirst, SIGNAL(clicked()), this, SLOT(acceptFirst())); connect(ui->btnSecond, SIGNAL(clicked()), this, SLOT(acceptSecond())); connect(ui->btnCancel, SIGNAL(clicked()), this, SLOT(close())); } InviteDialog::~InviteDialog() { delete ui; } void InviteDialog::acceptFirst() { emit acceptGame(jid_ + "/" + ui->cbResource->currentText(), true); accepted_ = true; accept(); close(); } void InviteDialog::acceptSecond() { emit acceptGame(jid_ + "/" + ui->cbResource->currentText(), false); accepted_ = true; accept(); close(); } void InviteDialog::closeEvent(QCloseEvent *event) { if (!accepted_) reject(); event->accept(); } // ---------------------------------------- InvitationDialog::InvitationDialog(const QString &jid, bool first, QWidget *parent) : QDialog(parent) { setAttribute(Qt::WA_DeleteOnClose); setModal(false); ui_.setupUi(this); QString posStr; if(first) posStr = tr("second", "He wants to play second"); else posStr = tr("first", "He wants to play first"); ui_.lbl_text->setText(tr("Player %1 invites you \nto play battleship. He wants to play %2.") .arg(jid).arg(posStr)); connect(ui_.pb_accept, SIGNAL(clicked()), this, SLOT(okPressed())); connect(ui_.pb_reject, SIGNAL(clicked()), this, SLOT(close())); adjustSize(); setFixedSize(size()); } void InvitationDialog::okPressed() { accept(); close(); } plugins-1.5/dev/battleshipgameplugin/invitedialog.h000066400000000000000000000031221336777360500226740ustar00rootroot00000000000000/* * invitedialog.h - Battleship Game plugin * Copyright (C) 2014 Aleksey Andreev * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef INVITEDIALOG_H #define INVITEDIALOG_H #include #include #include "ui_invitedialog.h" #include "ui_invitationdialog.h" namespace Ui { class InvateDialog; } class InviteDialog : public QDialog { Q_OBJECT public: InviteDialog(const QString &jid, const QStringList &resources, QWidget *parent = 0); ~InviteDialog(); private: Ui::InviteDialog *ui; bool accepted_; QString jid_; protected: void closeEvent(QCloseEvent *event); private slots: void acceptFirst(); void acceptSecond(); signals: void acceptGame(QString jid, bool first); }; class InvitationDialog : public QDialog { Q_OBJECT public: InvitationDialog(const QString &jid, bool first, QWidget *parent = 0); private: Ui::InvitationDialog ui_; private slots: void okPressed(); }; #endif // INVITEDIALOG_H plugins-1.5/dev/battleshipgameplugin/invitedialog.ui000066400000000000000000000057121336777360500230710ustar00rootroot00000000000000 InviteDialog 0 0 413 78 Battliship Game Plugin - Invite Opponent: 75 true Select resource: 0 0 Qt::Horizontal 0 20 Qt::Horizontal 0 20 I want to play first I want to play second Cancel cbResource btnFirst btnSecond btnCancel acceptBlack() acceptWhite() plugins-1.5/dev/battleshipgameplugin/options.cpp000066400000000000000000000104711336777360500222510ustar00rootroot00000000000000/* * options.cpp - Battleship Game plugin * Copyright (C) 2014 Aleksey Andreev * * 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. * * You can also redistribute and/or modify this program under the * terms of the Psi License, specified in the accompanied COPYING * file, as published by the Psi Project; either dated January 1st, * 2005, 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include "options.h" //#include "common.h" #include "optionaccessinghost.h" Options::Options(QObject *parent) : QObject(parent), dndDisable(false), confDisable(false), saveWndPosition(false), saveWndWidthHeight(false), windowTop(-1), windowLeft(-1), windowWidth(-1), windowHeight(-1), defSoundSettings(false), soundStart("sound/chess_start.wav"), soundFinish("sound/chess_finish.wav"), soundMove("sound/chess_move.wav"), soundError("sound/chess_error.wav") { if (psiOptions) { dndDisable = psiOptions->getPluginOption(constDndDisable, QVariant(dndDisable)).toBool(); confDisable = psiOptions->getPluginOption(constConfDisable, QVariant(confDisable)).toBool(); saveWndPosition = psiOptions->getPluginOption(constSaveWndPosition, QVariant(saveWndPosition)).toBool(); saveWndWidthHeight = psiOptions->getPluginOption(constSaveWndWidthHeight, QVariant(saveWndWidthHeight)).toBool(); windowTop = psiOptions->getPluginOption(constWindowTop, QVariant(windowTop)).toInt(); windowLeft = psiOptions->getPluginOption(constWindowLeft, QVariant(windowLeft)).toInt(); windowWidth = psiOptions->getPluginOption(constWindowWidth, QVariant(windowWidth)).toInt(); windowHeight = psiOptions->getPluginOption(constWindowHeight, QVariant(windowHeight)).toInt(); defSoundSettings = psiOptions->getPluginOption(constDefSoundSettings, QVariant(defSoundSettings)).toBool(); soundStart = psiOptions->getPluginOption(constSoundStart, QVariant(soundStart)).toString(); soundFinish = psiOptions->getPluginOption(constSoundFinish, QVariant(soundFinish)).toString(); soundMove = psiOptions->getPluginOption(constSoundMove, QVariant(soundMove)).toString(); soundError = psiOptions->getPluginOption(constSoundError, QVariant(soundError)).toString(); } } OptionAccessingHost *Options::psiOptions = NULL; Options *Options::instance_ = NULL; Options *Options::instance() { if (instance_ == NULL) Options::instance_ = new Options(); return Options::instance_; } void Options::reset() { if (instance_ != NULL) { delete Options::instance_; Options::instance_ = NULL; } } QVariant Options::getOption(const QString &option_name) const { if (option_name == constDndDisable) return dndDisable; if (option_name == constConfDisable) return confDisable; if (option_name == constSaveWndPosition) return saveWndPosition; if (option_name == constSaveWndWidthHeight) return saveWndWidthHeight; if (option_name == constWindowTop) return windowTop; if (option_name == constWindowLeft) return windowLeft; if (option_name == constWindowWidth) return windowWidth; if (option_name == constWindowHeight) return windowHeight; if (option_name == constDefSoundSettings) return defSoundSettings; if (option_name == constSoundStart) return soundStart; if (option_name == constSoundFinish) return soundFinish; if (option_name == constSoundMove) return soundMove; if (option_name == constSoundError) return soundError; return QVariant(); } void Options::setOption(const QString &option_name, const QVariant &option_value) { if ((saveWndPosition || (option_name != constWindowTop && option_name != constWindowLeft)) && (saveWndWidthHeight || (option_name != constWindowWidth && option_name != constWindowHeight))) { Options::psiOptions->setPluginOption(option_name, option_value); } } plugins-1.5/dev/battleshipgameplugin/options.h000066400000000000000000000045501336777360500217170ustar00rootroot00000000000000/* * options.h - Battleship Game plugin * Copyright (C) 2014 Aleksey Andreev * * 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. * * You can also redistribute and/or modify this program under the * terms of the Psi License, specified in the accompanied COPYING * file, as published by the Psi Project; either dated January 1st, * 2005, 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef OPTIONS_H #define OPTIONS_H #include #include #include "optionaccessor.h" #define constDndDisable "dnddsbl" #define constConfDisable "confdsbl" #define constSaveWndPosition "savewndpos" #define constSaveWndWidthHeight "savewndwh" #define constWindowTop "wndtop" #define constWindowLeft "wndleft" #define constWindowWidth "wndwidth" #define constWindowHeight "wndheight" #define constDefSoundSettings "defsndstngs" #define constSoundStart "soundstart" #define constSoundFinish "soundfinish" #define constSoundMove "soundmove" #define constSoundError "sounderror" class Options : public QObject { Q_OBJECT public: static OptionAccessingHost *psiOptions; static Options *instance(); static void reset(); QVariant getOption(const QString &option_name) const; void setOption(const QString &option_name, const QVariant &option_value); private: static Options *instance_; bool dndDisable; bool confDisable; bool saveWndPosition; bool saveWndWidthHeight; int windowTop; int windowLeft; int windowWidth; int windowHeight; bool defSoundSettings; QString soundStart; QString soundFinish; QString soundMove; QString soundError; private: Options(QObject *parent = 0); signals: public slots: }; #endif // OPTIONS_H plugins-1.5/dev/battleshipgameplugin/options.ui000066400000000000000000000200541336777360500221020ustar00rootroot00000000000000 options 0 0 338 318 Form Select Sounds: Game started: Game finished: Your turn: Error message: 0 0 25 25 25 25 0 0 25 25 25 25 0 0 25 25 25 25 0 0 25 25 25 25 If checked, the sound will always enabled (or disabled) Override default sound settings Disable invitations if status is DND Disable invitations from conference Save window height and width Save window position http://psi-plus.com/wiki/plugins#battleship_game_plugin <a href="http://psi-plus.com/wiki/plugins#battleship_game_plugin">Wiki (online)</a> true Qt::Vertical 20 0 le_start select_start play_start le_finish select_finish play_finish le_move select_move play_move le_error select_error play_error cb_sound_override cb_disable_dnd cb_disable_conf cb_save_w_h cb_save_pos plugins-1.5/dev/battleshipgameplugin/pluginwindow.cpp000066400000000000000000000132101336777360500232760ustar00rootroot00000000000000/* * pluginwindow.cpp - Battleship Game plugin * Copyright (C) 2014 Aleksey Andreev * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "pluginwindow.h" #include "boarddelegate.h" PluginWindow::PluginWindow(const QString &jid, QWidget *parent) : QMainWindow(parent) , gm_(NULL) { setAttribute(Qt::WA_DeleteOnClose); ui.setupUi(this); ui.lbOpponent->setText(jid); } void PluginWindow::initBoard() { if (!gm_) { gm_ = new GameModel(this); connect(gm_, SIGNAL(gameEvent(QString)), this, SIGNAL(gameEvent(QString))); connect(gm_, SIGNAL(statusChanged()), this, SLOT(updateStatus())); connect(ui.actionNewGame, SIGNAL(triggered()), this, SLOT(newGame())); connect(ui.actionExit, SIGNAL(triggered()), this, SLOT(close())); connect(ui.btnFreeze, SIGNAL(clicked()), this, SLOT(freezeShips())); connect(ui.btnDraw, SIGNAL(toggled(bool)), gm_, SLOT(setLocalDraw(bool))); connect(ui.btnAccept, SIGNAL(clicked()), gm_, SLOT(localAccept())); connect(ui.btnResign, SIGNAL(clicked()), gm_, SLOT(localResign())); connect(ui.actionResign, SIGNAL(triggered()), gm_, SLOT(localResign())); BoardModel *bmodel = new BoardModel(this); bmodel->init(gm_); BoardDelegate *bd_ = new BoardDelegate(bmodel, this); ui.tvBoard->setItemDelegate(bd_); ui.tvBoard->setModel(bmodel); } gm_->init(); ui.tvBoard->reset(); } void PluginWindow::setError() { gm_->setError(); } QStringList PluginWindow::dataExchange(const QStringList &data) { const QString cmd = data.at(0); int cnt = data.count(); if (cmd == "init-opp-board") { QStringList b = data; b.removeAt(0); if (gm_->initOpponentBoard(b)) return QStringList("ok"); } else if (cmd == "check-opp-board") { QStringList b = data; b.removeAt(0); if (gm_->uncoverOpponentBoard(b)) return QStringList("ok"); } else if (cmd == "start") { GameModel::GameStatus st = GameModel::StatusWaitingOpponent; if (cnt == 2 && data.at(1) == "first") st = GameModel::StatusMyTurn; gm_->setStatus(st); } else if (cmd == "turn") { int pos = -1; bool draw = false; bool accept = false; bool resign = false; for (int i = 1; i < cnt; ++i) { const QString str = data.at(i); const QString t = str.section(';', 0, 0); if (t == "shot") pos = str.section(';', 1, 1).toInt(); else if (t == "draw") draw = true; else if (t == "accept") accept = true; else if (t == "resign") resign = true; } QStringList res("ok"); gm_->setOpponentDraw(draw); gm_->setOpponentAcceptedDraw(accept); gm_->opponentTurn(pos); if (pos != -1) res.append(QString("result;%1;%2").arg(gm_->lastShotResult()).arg(gm_->lastShotSeed())); if (resign) gm_->opponentResign(); res.append(QString("status;%1").arg(stringStatus(true))); return res; } else if (cmd == "turn-result") { bool err = true; if (cnt == 2) { QString str = data.at(1); if (str.section(';', 0, 0) == "shot-result") { const QString res = str.section(';', 1, 1); const QString seed = str.section(';', 2); if (gm_->handleTurnResult(res, seed)) err = false; } } else if (gm_->handleResult()) err = false; if (!err) { QStringList res("ok"); res.append(QString("status;%1").arg(stringStatus(true))); return res; } } else if (cmd == "get-uncovered-board") { QStringList res = gm_->getUncoveredBoard(); return res; } return QStringList("error"); } QString PluginWindow::stringStatus(bool short_) const { switch (gm_->status()) { case GameModel::StatusBoardInit: return short_ ? QString("init") : tr("Setting ships position"); break; case GameModel::StatusMyTurn: return short_ ? QString("turn") : tr("Your turn"); case GameModel::StatusWaitingTurnAccept: return short_ ? QString("waiting") : tr("Waiting for accept"); case GameModel::StatusWaitingOpponent: return short_ ? QString("waiting") : tr("Waiting for opponent"); case GameModel::StatusWin: return short_ ? QString("end") : tr("You Win!"); case GameModel::StatusLose: return short_ ? QString("end") : tr("You Lose."); case GameModel::StatusDraw: return short_ ? QString("end") : tr("Draw"); case GameModel::StatusError: return short_ ? QString("err") : tr("Error"); default: break; } return QString(); } void PluginWindow::updateStatus() { updateWidgets(); ui.lbStatus->setText(stringStatus(false)); } void PluginWindow::freezeShips() { ui.btnFreeze->setEnabled(false); gm_->sendCoveredBoard(); } void PluginWindow::updateWidgets() { GameModel::GameStatus st = gm_->status(); ui.btnFreeze->setEnabled((st == GameModel::StatusBoardInit)); bool f = (st == GameModel::StatusMyTurn); ui.btnDraw->setEnabled(f && !gm_->isOpponentDraw()); if (f) ui.btnDraw->setChecked(false); ui.btnAccept->setEnabled((f && gm_->isOpponentDraw())); ui.btnResign->setEnabled(f); ui.actionResign->setEnabled(f); ui.actionNewGame->setEnabled((st == GameModel::StatusWin || st == GameModel::StatusLose || st == GameModel::StatusDraw || st == GameModel::StatusError)); } void PluginWindow::newGame() { emit gameEvent("new-game"); } plugins-1.5/dev/battleshipgameplugin/pluginwindow.h000066400000000000000000000025721336777360500227540ustar00rootroot00000000000000/* * pluginwindow.h - Battleship Game plugin * Copyright (C) 2014 Aleksey Andreev * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef PLUGINWINDOW_H #define PLUGINWINDOW_H #include "ui_pluginwindow.h" #include "gamemodel.h" class PluginWindow : public QMainWindow { Q_OBJECT public: PluginWindow(const QString &jid, QWidget *parent = 0); void initBoard(); void setError(); QStringList dataExchange(const QStringList &data); private: QString stringStatus(bool short_) const; private: Ui::PluginWindow ui; GameModel *gm_; private: void updateWidgets(); private slots: void updateStatus(); void freezeShips(); void newGame(); signals: void gameEvent(QString data); }; #endif // PLUGINWINDOW_H plugins-1.5/dev/battleshipgameplugin/pluginwindow.ui000066400000000000000000000153421336777360500231410ustar00rootroot00000000000000 PluginWindow 0 0 667 634 Battleship game 0 0 Opponent: 75 true 0 0 Status: 75 true 1 0 true QAbstractItemView::SingleSelection false false false 0 0 Qt::ScrollBarAlwaysOn Qt::ScrollBarAlwaysOff Freeze ships position false Press button and make move if you want to propose draw Propose a draw true false Press button if you want to accept the draw proposal Accept the draw proposal false Press button if you want to resign Resign the game 0 0 667 18 File Game false New game -- Exit false Resign BoardView QTableView
boardview.h
tvBoard listView_2 btnFreeze btnDraw btnAccept btnResign
plugins-1.5/dev/pstoplugin/000077500000000000000000000000001336777360500160435ustar00rootroot00000000000000plugins-1.5/dev/pstoplugin/changelog.txt000066400000000000000000000007131336777360500205340ustar00rootroot000000000000002013-08-13 v0.0.3 taurus + Иконка плагина 2011-03-29 v0.0.2 liuch * Плагин терерь работает под Windows * Исправлен диалог выбора цвета * Мелкие исправления * Чистка кода 2011-03-15 v0.0.1 mva * Первый коммит (автор отказался от оригинального плагина, теперь разработчиком буду я) plugins-1.5/dev/pstoplugin/preferences.ui000066400000000000000000000071331336777360500207070ustar00rootroot00000000000000 PreferencesWidget 0 0 175 176 Form @username usernameColorButton #post_id postColorButton * tag tagColorButton > quote quoteColorButton message Qt::Horizontal 40 20 Qt::Vertical 20 24 plugins-1.5/dev/pstoplugin/preferenceswidget.cpp000066400000000000000000000076621336777360500222670ustar00rootroot00000000000000#include "preferenceswidget.h" PreferencesWidget::PreferencesWidget(const QColor &username_color, const QColor &post_id_color, const QColor &tag_color, const QColor "e_color, const QColor &message_color, QWidget *parent) : QWidget(parent), now_changing_button(NULL), color_dialog(this), curr_username_color(username_color), curr_post_id_color(post_id_color), curr_tag_color(tag_color), curr_quote_color(quote_color), curr_message_color(message_color) { connect(&color_dialog, SIGNAL(accepted()), this, SLOT(colorDialogOk())); connect(&color_dialog, SIGNAL(rejected()), this, SLOT(colorDialogCancel())); color_dialog.setModal(true); preferences_ui.setupUi(this); // @username preferences_ui.usernameColorButton->setStyleSheet(QString("background-color: %1;").arg(username_color.name())); connect(preferences_ui.usernameColorButton, SIGNAL(clicked()), this, SLOT(usernameColorClicked())); // #post/id preferences_ui.postColorButton->setStyleSheet(QString("background-color: %1;").arg(post_id_color.name())); connect(preferences_ui.postColorButton, SIGNAL(clicked()), this, SLOT(postColorClicked())); // *tag preferences_ui.tagColorButton->setStyleSheet(QString("background-color: %1;").arg(tag_color.name())); connect(preferences_ui.tagColorButton, SIGNAL(clicked()), this, SLOT(tagColorClicked())); // > quote preferences_ui.quoteColorButton->setStyleSheet(QString("background-color: %1;").arg(quote_color.name())); connect(preferences_ui.quoteColorButton, SIGNAL(clicked()), this, SLOT(quoteColorClicked())); // message preferences_ui.messageColorButton->setStyleSheet(QString("background-color: %1;").arg(message_color.name())); connect(preferences_ui.messageColorButton, SIGNAL(clicked()), this, SLOT(messageColorClicked())); } void PreferencesWidget::usernameColorClicked() { color_dialog.setCurrentColor(curr_username_color); showChangeButtonColorDialog(preferences_ui.usernameColorButton); } void PreferencesWidget::postColorClicked() { color_dialog.setCurrentColor(curr_post_id_color); showChangeButtonColorDialog(preferences_ui.postColorButton); } void PreferencesWidget::tagColorClicked() { color_dialog.setCurrentColor(curr_tag_color); showChangeButtonColorDialog(preferences_ui.tagColorButton); } void PreferencesWidget::quoteColorClicked() { color_dialog.setCurrentColor(curr_quote_color); showChangeButtonColorDialog(preferences_ui.quoteColorButton); } void PreferencesWidget::messageColorClicked() { color_dialog.setCurrentColor(curr_message_color); showChangeButtonColorDialog(preferences_ui.messageColorButton); } void PreferencesWidget::showChangeButtonColorDialog(QAbstractButton * button) { now_changing_button = button; color_dialog.show(); } void PreferencesWidget::colorDialogOk() { if (now_changing_button) { QColor new_color = color_dialog.currentColor(); now_changing_button->setStyleSheet(QString("background-color: %1;").arg(new_color.name())); if (now_changing_button == preferences_ui.usernameColorButton) { emit usernameColorChanged(new_color); } else if (now_changing_button == preferences_ui.postColorButton) { emit postColorChanged(new_color); } else if (now_changing_button == preferences_ui.tagColorButton) { emit tagColorChanged(new_color); } else if (now_changing_button == preferences_ui.quoteColorButton) { emit quoteColorChanged(new_color); } else if (now_changing_button == preferences_ui.messageColorButton) { emit messageColorChanged(new_color); } } now_changing_button = NULL; } void PreferencesWidget::colorDialogCancel() { now_changing_button = NULL; } plugins-1.5/dev/pstoplugin/preferenceswidget.h000066400000000000000000000025271336777360500217270ustar00rootroot00000000000000#ifndef PREFERENCESWIDGET_H #define PREFERENCESWIDGET_H #include #include #include "ui_preferences.h" #include "optionaccessor.h" class PreferencesWidget : public QWidget { Q_OBJECT public: explicit PreferencesWidget(const QColor & username_color, const QColor & post_id_color, const QColor & tag_color, const QColor & quote_color, const QColor & message_color, QWidget *parent = 0); private: Ui::PreferencesWidget preferences_ui; QAbstractButton * now_changing_button; QColorDialog color_dialog; QColor curr_username_color; QColor curr_post_id_color; QColor curr_tag_color; QColor curr_quote_color; QColor curr_message_color; private: void showChangeButtonColorDialog(QAbstractButton *); signals: void usernameColorChanged(QColor); void postColorChanged(QColor); void tagColorChanged(QColor); void quoteColorChanged(QColor); void messageColorChanged(QColor); private slots: void usernameColorClicked(); void postColorClicked(); void tagColorClicked(); void quoteColorClicked(); void messageColorClicked(); void colorDialogOk(); void colorDialogCancel(); }; #endif // PREFERENCESWIDGET_H plugins-1.5/dev/pstoplugin/psto.png000066400000000000000000000016571336777360500175470ustar00rootroot00000000000000PNG  IHDR(-SgAMA asRGB cHRMz&u0`:pQ<PLTEj"| }~~#~~jtRNS2 s s2ۈ¬bKGD- pHYs  IDATeG0䜓`6nhݤIj"0-\2 !@VuӶM]FBơ߃02]) !N֍ǫnkCϋ)dCpܙ'SV&L>(yO%tEXtdate:create2011-02-11T15:47:24+06:00q!%tEXtdate:modify2011-02-11T15:47:24+06:00RFtEXtsoftwareImageMagick 6.6.7-6 2011-03-13 Q16 http://www.imagemagick.org*fotEXtThumb::Document::Pages1/tEXtThumb::Image::height64>+'tEXtThumb::Image::Width64DOi tEXtThumb::Mimetypeimage/png?VNtEXtThumb::MTime1297417644١%ztEXtThumb::Size1.21KBB%tEXtThumb::URIfile:///home/anti/psto.pngIENDB`plugins-1.5/dev/pstoplugin/pstoplugin.cpp000066400000000000000000000343001336777360500207530ustar00rootroot00000000000000#include "pstoplugin.h" PstoPlugin::PstoPlugin() : psto_jids(QStringList() << PSTO_JIDS) , post_id_regexp_str("(#[\\w/]+)") , user_regexp_str("(\\@[\\w-_]+)") , link_regexp_str("((https?|ftp)://\\S+)") , quote_regexp_str("^[>] .*$") , tag_regexp_str("^[*] .*$") // #abcde[/123] http://dfgfdhfdh.psto.net/abcde[#123] , post_footer_regexp_str("^(\\#(\\w+)(/(\\d+))?) (http://(.*)psto[.]net/\\2(\\#\\4)?)$") , enabled(false) { } QString PstoPlugin::name() const { return PLUGIN_NAME; } QString PstoPlugin::shortName() const { return PLUGIN_NAME_SHORT; } QString PstoPlugin::version() const { return VERSION; } QWidget * PstoPlugin::options() { PreferencesWidget * preferences_widget = new PreferencesWidget( username_color, post_id_color, tag_color, quote_color, message_color ); connect(preferences_widget, SIGNAL(destroyed()), this, SLOT(onOptionsClose())); connect(preferences_widget, SIGNAL(usernameColorChanged(QColor)), this, SLOT(usernameColorChanged(QColor))); connect(preferences_widget, SIGNAL(postColorChanged(QColor)), this, SLOT(postColorChanged(QColor))); connect(preferences_widget, SIGNAL(tagColorChanged(QColor)), this, SLOT(tagColorChanged(QColor))); connect(preferences_widget, SIGNAL(quoteColorChanged(QColor)), this, SLOT(quoteColorChanged(QColor))); connect(preferences_widget, SIGNAL(messageColorChanged(QColor)), this, SLOT(messageColorChanged(QColor))); return preferences_widget; } void PstoPlugin::usernameColorChanged(QColor c) { new_username_color = c; } void PstoPlugin::postColorChanged(QColor c) { new_post_id_color = c; } void PstoPlugin::tagColorChanged(QColor c) { new_tag_color = c; } void PstoPlugin::quoteColorChanged(QColor c) { new_quote_color = c; } void PstoPlugin::messageColorChanged(QColor c) { new_message_color = c; } void PstoPlugin::onOptionsClose() { } void PstoPlugin::applyOptions() { username_color = new_username_color; psiOptions->setPluginOption(USERNAME_COLOR, username_color); post_id_color = new_post_id_color; psiOptions->setPluginOption(POST_ID_COLOR, post_id_color); tag_color = new_tag_color; psiOptions->setPluginOption(TAG_COLOR, tag_color); quote_color = new_quote_color; psiOptions->setPluginOption(QUOTE_COLOR, quote_color); message_color = new_message_color; psiOptions->setPluginOption(MESSAGE_COLOR, message_color); } void PstoPlugin::optionChanged(const QString & option) { Q_UNUSED(option); } QString PstoPlugin::pluginInfo() { return "plugin info"; } bool PstoPlugin::enable() { if (psiOptions) { enabled = true; } return enabled; } bool PstoPlugin::disable() { enabled = false; return true; } bool PstoPlugin::processMessage(int account, const QString & fromJid, const QString & body, const QString & subject) { Q_UNUSED(account); Q_UNUSED(fromJid); Q_UNUSED(body); Q_UNUSED(subject); return false; } bool PstoPlugin::processOutgoingMessage(int account, const QString &fromJid, QString &body, const QString &type, QString &subject) { Q_UNUSED(account); Q_UNUSED(fromJid); Q_UNUSED(body); Q_UNUSED(type); Q_UNUSED(subject); return false; } bool PstoPlugin::processEvent(int account, QDomElement &e) { Q_UNUSED(account); Q_UNUSED(e); if (!enabled) { return false; } QDomDocument doc = e.ownerDocument(); QString jid = e.childNodes().at(3).firstChild().nodeValue().split("/").at(0); // always here if (psto_jids.contains(jid)) { QString full_jid = e.childNodes().at(5).attributes() .namedItem("from").nodeValue(); QDomElement body = e.childNodes().at(5).firstChildElement(); // the same QDomText body_text = body.firstChild().toText(); QDomElement html = doc.createElement("html"); html.setAttribute("xmlns", "http://jabber.org/protocol/xhtml-im"); body.parentNode().appendChild(html); QDomElement html_body = doc.createElement("body"); html_body.setAttribute("xmlns", "http://www.w3.org/1999/xhtml"); html.appendChild(html_body); QStringList message_strings = body_text.nodeValue().split("\n"); int line_number = 0; foreach (QString line, message_strings) { processMessageString(line_number, line, full_jid, html_body); line_number++; } } return false; } void PstoPlugin::setOptionAccessingHost(OptionAccessingHost * host) { psiOptions = host; QVariant value; value = psiOptions->getPluginOption(USERNAME_COLOR); if (value.isNull()) { username_color = DEFAULT_USERNAME_COLOR; psiOptions->setPluginOption(USERNAME_COLOR, DEFAULT_USERNAME_COLOR); } else { username_color = qvariant_cast(value); } new_username_color = username_color; value = psiOptions->getPluginOption(POST_ID_COLOR); if (value.isNull()) { post_id_color = DEFAULT_POST_ID_COLOR; psiOptions->setPluginOption(POST_ID_COLOR, DEFAULT_POST_ID_COLOR); } else { post_id_color = qvariant_cast(value); } new_post_id_color = post_id_color; value = psiOptions->getPluginOption(TAG_COLOR); if (value.isNull()) { tag_color = DEFAULT_TAG_COLOR; psiOptions->setPluginOption(TAG_COLOR, DEFAULT_TAG_COLOR); } else { tag_color = qvariant_cast(value); } new_tag_color = tag_color; value = psiOptions->getPluginOption(QUOTE_COLOR); if (value.isNull()) { quote_color = DEFAULT_QUOTE_COLOR; psiOptions->setPluginOption(QUOTE_COLOR, DEFAULT_QUOTE_COLOR); } else { quote_color = qvariant_cast(value); } new_quote_color = quote_color; value = psiOptions->getPluginOption(MESSAGE_COLOR); if (value.isNull()) { message_color = DEFAULT_MESSAGE_COLOR; psiOptions->setPluginOption(MESSAGE_COLOR, DEFAULT_MESSAGE_COLOR); } else { message_color = qvariant_cast(value); } new_message_color = message_color; } QString PstoPlugin::generateXMPPUrl(const QString & jid, const QString & message) { QString message_percent(message.toLatin1().toPercentEncoding()); return QString("xmpp:%1?message;type=chat;body=%2").arg(jid, message_percent); } QDomElement PstoPlugin::generateLinkSpan(const QString & value, const QString & link_str, const QColor & color, QDomDocument & doc, const bool bold, const bool italic) { QString style = QString("color: %1").arg(color.name()); if (bold) { style.append("; font-weight: bold"); } if (italic) { style.append("; font-style: italic"); } QDomElement span = doc.createElement("span"); span.setAttribute("style", style); span.appendChild(doc.createTextNode(value)); QDomElement link = doc.createElement("a"); link.setAttribute("href", link_str); link.setAttribute("style", "text-decoration: none"); link.appendChild(span); return link; } QDomElement PstoPlugin::generateSpan(const QString & value, const QColor & color, QDomDocument & doc, const bool bold, const bool italic) { QString style = QString("color: %1").arg(color.name()); if (bold) { style.append("; font-weight: bold"); } if (italic) { style.append("; font-style: italic"); } QDomElement span = doc.createElement("span"); span.setAttribute("style", style); span.appendChild(doc.createTextNode(value)); return span; } QDomElement PstoPlugin::generateLink(const QString & value, const QString & link_str, QDomDocument & doc) { QDomElement link = doc.createElement("a"); link.setAttribute("href", link_str); link.appendChild(doc.createTextNode(value)); return link; } RegExpPartitions * PstoPlugin::splitRegexpSimple(const QString & source1, const QString & regexp_str, const PairType value) { QString source(source1); QRegExp regexp(regexp_str); RegExpPartitions* result = new RegExpPartitions(); int index = regexp.indexIn(source); while (index != -1) { QString before_match = source.left(index); if (!before_match.isEmpty()) { result->append(RegExpPair(PairMessage, before_match)); } QString match = regexp.cap(0); result->append(RegExpPair(value, match)); source = source.right(source.length() - index - match.length()); // for a time, without optimizations index = regexp.indexIn(source); } result->append(RegExpPair(PairMessage, source)); return result; } RegExpPartitions * PstoPlugin::splitPostIdRegexp(const QString &source) { return splitRegexpSimple(source, post_id_regexp_str, PairPostId); } RegExpPartitions * PstoPlugin::splitUserRegexp(const QString &source) { return splitRegexpSimple(source, user_regexp_str, PairUser); } RegExpPartitions * PstoPlugin::splitLinkRegexp(const QString &source) { return splitRegexpSimple(source, link_regexp_str, PairLink); } void PstoPlugin::processMessageString(const int /*pos_number*/, const QString & line, const QString & psto_jid, QDomElement &html_body) { QDomDocument doc = html_body.ownerDocument(); // qDebug() << pos_number << line; QRegExp post_footer_regexp(post_footer_regexp_str); if (post_footer_regexp.indexIn(line) != -1) { QString full_post = post_footer_regexp.cap(1); QString post_id = post_footer_regexp.cap(2); QString post_link = post_footer_regexp.cap(5); bool is_comment = !post_footer_regexp.cap(3).isEmpty(); // #abcde/123 html_body.appendChild(generateLinkSpan( full_post, generateXMPPUrl(psto_jid, full_post), post_id_color, doc, true, false)); html_body.appendChild(doc.createTextNode(" ")); // ! #abcde/123 html_body.appendChild(generateLinkSpan( "!", generateXMPPUrl(psto_jid, QString("! %1").arg(full_post)), post_id_color, doc, true, false)); html_body.appendChild(doc.createTextNode(" ")); if (is_comment) { // u #abcde html_body.appendChild(generateLinkSpan( "U", generateXMPPUrl(psto_jid, QString("u #%1").arg(post_id)), post_id_color, doc, true, false)); } else { // s #abcde html_body.appendChild(generateLinkSpan( "S", generateXMPPUrl(psto_jid, QString("s #%1").arg(post_id)), post_id_color, doc, true, false)); html_body.appendChild(doc.createTextNode(" ")); // #abcde+ html_body.appendChild(generateLinkSpan( "+", generateXMPPUrl(psto_jid, QString("#%1+").arg(post_id)), post_id_color, doc, true, false)); } html_body.appendChild(doc.createTextNode(" ")); // ~ #abcde/123 html_body.appendChild(generateLinkSpan( "~", generateXMPPUrl(psto_jid, QString("~ %1").arg(full_post)), post_id_color, doc, true, false)); html_body.appendChild(doc.createTextNode(" ")); html_body.appendChild(generateLink(post_link, post_link, doc)); return; } if (/*pos_number == 3 &&*/ QRegExp(tag_regexp_str).indexIn(line) != -1) { html_body.appendChild(generateSpan(line, tag_color, doc, false, true)); html_body.appendChild(doc.createElement("br")); return; } if (QRegExp(quote_regexp_str).indexIn(line) != -1) { html_body.appendChild(generateSpan(line, quote_color, doc)); html_body.appendChild(doc.createElement("br")); return; } RegExpPartitions * link_list = splitLinkRegexp(line); foreach (RegExpPair p, (*link_list)) { if (p.first == PairLink) { html_body.appendChild(generateLink( p.second, p.second, doc)); } else { RegExpPartitions * user_list = splitUserRegexp(p.second); foreach (RegExpPair p, (*user_list)) { if (p.first == PairUser) { html_body.appendChild(generateLinkSpan( p.second, generateXMPPUrl(psto_jid, p.second), username_color, doc)); } else { RegExpPartitions * post_id_list = splitPostIdRegexp(p.second); foreach (RegExpPair p, (*post_id_list)) { if (p.first == PairPostId) { html_body.appendChild(generateLinkSpan( p.second, generateXMPPUrl(psto_jid, p.second), post_id_color, doc, true, false)); } else { html_body.appendChild(doc.createTextNode(p.second)); } } delete post_id_list; } } delete user_list; } } delete link_list; html_body.appendChild(doc.createElement("br")); } QPixmap PstoPlugin::icon() const { return QPixmap(":/icons/psto.png"); } #ifndef HAVE_QT5 Q_EXPORT_PLUGIN(PstoPlugin); #endif plugins-1.5/dev/pstoplugin/pstoplugin.h000066400000000000000000000112621336777360500204220ustar00rootroot00000000000000#ifndef PSTOPLUGIN_H #define PSTOPLUGIN_H #include #include #include #include "psiplugin.h" #include "eventfilter.h" #include "stanzafilter.h" #include "optionaccessor.h" #include "optionaccessinghost.h" #include "plugininfoprovider.h" #include "preferenceswidget.h" #define VERSION "0.0.3" #define PLUGIN_NAME "Psto Plugin" #define PLUGIN_NAME_SHORT "psto" #define DEFAULT_USERNAME_COLOR QColor(0, 85, 255) #define DEFAULT_POST_ID_COLOR QColor(87, 165, 87) #define DEFAULT_TAG_COLOR QColor(131, 145, 145) #define DEFAULT_QUOTE_COLOR QColor(131, 145, 145) #define DEFAULT_MESSAGE_COLOR QColor(0, 0, 0) #define USERNAME_COLOR "username_color" #define POST_ID_COLOR "post_id_color" #define TAG_COLOR "tag_color" #define QUOTE_COLOR "quote_color" #define MESSAGE_COLOR "message_color" // jid1 << jid2 << ... #define PSTO_JIDS "psto@psto.net" << "d@psto.net" enum PairType { PairMessage, PairPostId, PairUser, PairLink }; typedef QPair RegExpPair; typedef QList RegExpPartitions; class PstoPlugin : public QObject , public PsiPlugin , public EventFilter , public OptionAccessor , public StanzaFilter , public PluginInfoProvider { Q_OBJECT #ifdef HAVE_QT5 Q_PLUGIN_METADATA(IID "com.psi-plus.PstoPlugin") #endif Q_INTERFACES(PsiPlugin EventFilter StanzaFilter OptionAccessor PluginInfoProvider) public: PstoPlugin(); virtual QString name() const; virtual QString shortName() const; virtual QString version() const; virtual QWidget * options(); virtual bool enable(); virtual bool disable(); virtual bool processEvent(int account, QDomElement & e); virtual bool processMessage(int account, const QString & fromJid, const QString & body, const QString & subject); virtual bool processOutgoingMessage(int account, const QString &fromJid, QString &body, const QString &type, QString &subject); virtual void logout(int) {} virtual void setOptionAccessingHost(OptionAccessingHost * host); virtual void optionChanged(const QString & option); virtual void applyOptions(); virtual void restoreOptions() {} virtual bool incomingStanza(int account, const QDomElement & stanza) { Q_UNUSED(account); Q_UNUSED(stanza); return false; } virtual bool outgoingStanza(int account, QDomElement & stanza) { Q_UNUSED(account); Q_UNUSED(stanza); return false; } virtual QString pluginInfo(); virtual QPixmap icon() const; private: const QStringList psto_jids; QColor username_color, new_username_color; QColor tag_color, new_tag_color; QColor quote_color, new_quote_color; QColor message_color, new_message_color; QColor post_id_color, new_post_id_color; const QString post_id_regexp_str; const QString user_regexp_str; const QString link_regexp_str; const QString quote_regexp_str; const QString tag_regexp_str; const QString post_footer_regexp_str; bool enabled; OptionAccessingHost * psiOptions; QString generateXMPPUrl(const QString & jid, const QString & message); QDomElement generateLinkSpan(const QString & value, const QString & link, const QColor & color, QDomDocument & doc, const bool bold = false, const bool italic = false); QDomElement generateSpan(const QString & value, const QColor & color, QDomDocument & doc, const bool bold = false, const bool italic = false); QDomElement generateLink(const QString & value, const QString & link, QDomDocument & doc); // QPair RegExpPartitions * splitRegexpSimple(const QString & source, const QString & regexp, const PairType value); RegExpPartitions * splitPostIdRegexp(const QString & source); RegExpPartitions * splitUserRegexp(const QString & source); RegExpPartitions * splitLinkRegexp(const QString & source); void processMessageString(const int pos_number, const QString & string, const QString & psto_jid, QDomElement & html_body); private slots: void usernameColorChanged(QColor); void postColorChanged(QColor); void tagColorChanged(QColor); void quoteColorChanged(QColor); void messageColorChanged(QColor); void onOptionsClose(); }; #endif // PSTOPLUGIN_H plugins-1.5/dev/pstoplugin/pstoplugin.pro000066400000000000000000000003511336777360500207700ustar00rootroot00000000000000CONFIG += release QT += network include(../../psiplugin.pri) SOURCES += pstoplugin.cpp \ preferenceswidget.cpp FORMS += \ preferences.ui HEADERS += \ preferenceswidget.h \ pstoplugin.h RESOURCES += resources.qrc plugins-1.5/dev/pstoplugin/resources.qrc000066400000000000000000000001341336777360500205620ustar00rootroot00000000000000 psto.png plugins-1.5/dev/redirectorplugin/000077500000000000000000000000001336777360500172205ustar00rootroot00000000000000plugins-1.5/dev/redirectorplugin/options.ui000066400000000000000000000022721336777360500212550ustar00rootroot00000000000000 Options 0 0 600 497 Form Redirect to JID: node@domain/resource Qt::Vertical 20 40 plugins-1.5/dev/redirectorplugin/redirectorplugin.pro000066400000000000000000000003341336777360500233230ustar00rootroot00000000000000CONFIG += release TARGET = redirectplugin exists($$sdkdir) { include($$sdkdir/psiplugin.pri) } else { include(../../psiplugin.pri) } SOURCES += redirectplugin.cpp HEADERS += redirectplugin.h FORMS += options.ui plugins-1.5/dev/redirectorplugin/redirectplugin.cpp000066400000000000000000000070071336777360500227500ustar00rootroot00000000000000/* * redirectplugin.cpp - plugin * Copyright (C) 2013 Sergey Ilinykh * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include #include #include #include "redirectplugin.h" #include "optionaccessinghost.h" #include "stanzasendinghost.h" #include "accountinfoaccessinghost.h" #include "applicationinfoaccessinghost.h" #include "contactinfoaccessinghost.h" #ifndef HAVE_QT5 Q_EXPORT_PLUGIN2(redirectplugin, Redirector) #endif bool Redirector::enable() { if (psiOptions) { enabled = true; targetJid = psiOptions->getPluginOption("jid").toString(); } return enabled; } bool Redirector::disable() { enabled = false; return true; } void Redirector::applyOptions() { if (!options_) return; targetJid = ui_.le_jid->text(); psiOptions->setPluginOption("jid", targetJid); } void Redirector::restoreOptions() { if (!options_) return; targetJid = psiOptions->getPluginOption("jid").toString(); ui_.le_jid->setText(targetJid); } QWidget* Redirector::options() { if (!enabled) { return 0; } options_ = new QWidget(); ui_.setupUi(options_); restoreOptions(); return options_; } bool Redirector::incomingStanza(int account, const QDomElement& stanza) { Q_UNUSED(account) if (!enabled || stanza.tagName() != "message") { return false; } int targetAccount = accInfoHost->findOnlineAccountForContact(targetJid); QDomNodeList bodies = stanza.elementsByTagName("body"); if (targetAccount == -1 || bodies.count() == 0) { return false; } int contactId; QString from = stanza.attribute("from"); QDomDocument doc; QDomElement e = doc.createElement("message"); e.setAttribute("to", ui_.le_jid->text()); e.setAttribute("type", "chat"); // TODO id? contactId = contactIdMap.value(from); if (!contactId) { contactIdMap.insert(from, nextContactId); contactId = nextContactId++; } QDomElement body = doc.createElement("body"); e.appendChild(body); #ifdef HAVE_QT5 body.appendChild(doc.createTextNode(QString("#%1 %2").arg(contactId).arg(bodies.at(0).toElement().text().toHtmlEscaped()))); #else body.appendChild(doc.createTextNode(QString("#%1 %2").arg(contactId).arg(Qt::escape(bodies.at(0).toElement().text())))); #endif QDomElement forward = e.appendChild(doc.createElementNS("urn:xmpp:forward:0", "forwarded")).toElement(); forward.appendChild(doc.createElementNS("urn:xmpp:delay", "delay")).toElement() .setAttribute("stamp", QDateTime::currentDateTimeUtc().toString("yyyy-MM-ddThh:mm:ssZ")); forward.appendChild(doc.importNode(stanza, true)); stanzaHost->sendStanza(targetAccount, e); return true; } bool Redirector::outgoingStanza(int /*account*/, QDomElement& /*xml*/) { return false; } QString Redirector::pluginInfo() { return tr("Author: ") + "rion\n" + tr("Email: ") + "rion4ik@gmail.com\n\n" + trUtf8("Redirects all incoming messages to some jid and allows to redirect messages back."); } plugins-1.5/dev/redirectorplugin/redirectplugin.h000066400000000000000000000062501336777360500224140ustar00rootroot00000000000000/* * redirectplugin.h - plugin * Copyright (C) 2013 Sergey Ilinykh * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef REDIRECTPLUGIN_H #define REDIRECTPLUGIN_H #include #include "psiplugin.h" #include "optionaccessor.h" #include "stanzafilter.h" #include "stanzasender.h" #include "accountinfoaccessor.h" #include "applicationinfoaccessor.h" #include "plugininfoprovider.h" #include "contactinfoaccessor.h" class QDomElement; class OptionAccessingHost; class StanzaSendingHost; class AccountInfoAccessingHost; class ApplicationInfoAccessingHost; class ContactInfoAccessingHost; #include "ui_options.h" class Redirector: public QObject, public PsiPlugin, public OptionAccessor, public StanzaSender, public StanzaFilter, public AccountInfoAccessor, public ApplicationInfoAccessor, public PluginInfoProvider, public ContactInfoAccessor { Q_OBJECT #ifdef HAVE_QT5 Q_PLUGIN_METADATA(IID "com.psi-plus.Redirector") #endif Q_INTERFACES(PsiPlugin OptionAccessor StanzaSender StanzaFilter AccountInfoAccessor ApplicationInfoAccessor PluginInfoProvider ContactInfoAccessor) public: inline Redirector() : enabled(false) , psiOptions(0) , stanzaHost(0) , accInfoHost(0) , appInfoHost(0) , contactInfo(0) {} QString name() const { return "Redirect Plugin"; } QString shortName() const { return "redirect"; } QString version() const { return "0.0.2"; } //PsiPlugin::Priority priority() {return PriorityNormal;} QWidget* options(); bool enable(); bool disable(); void applyOptions(); void restoreOptions(); QPixmap icon() const { return QPixmap(); } void setOptionAccessingHost(OptionAccessingHost* host) { psiOptions = host; } void optionChanged(const QString& ) {} void setStanzaSendingHost(StanzaSendingHost *host) { stanzaHost = host; } bool incomingStanza(int account, const QDomElement& xml); bool outgoingStanza(int account, QDomElement& xml); void setAccountInfoAccessingHost(AccountInfoAccessingHost* host) { accInfoHost = host; } void setApplicationInfoAccessingHost(ApplicationInfoAccessingHost* host) { appInfoHost = host; } void setContactInfoAccessingHost(ContactInfoAccessingHost* host) { contactInfo = host; } QString pluginInfo(); private slots: private: QString targetJid; QHash contactIdMap; int nextContactId; QWidget *options_; bool enabled; OptionAccessingHost* psiOptions; StanzaSendingHost* stanzaHost; AccountInfoAccessingHost *accInfoHost; ApplicationInfoAccessingHost *appInfoHost; ContactInfoAccessingHost* contactInfo; Ui::Options ui_; }; #endif plugins-1.5/dev/ripperccplugin/000077500000000000000000000000001336777360500166655ustar00rootroot00000000000000plugins-1.5/dev/ripperccplugin/CMakeLists.txt000066400000000000000000000033051336777360500214260ustar00rootroot00000000000000unset(_HDRS) unset(_UIS) unset(_SRCS) unset(_RSCS) unset(PLUGIN) set(PLUGIN ripperccplugin) project(${PLUGIN}) cmake_minimum_required( VERSION 3.1.0 ) if(NOT WIN32) set(LIB_SUFFIX "" CACHE STRING "Define suffix of directory name (32/64)") set(PLUGINS_PATH "lib${LIB_SUFFIX}/psi-plus/plugins" CACHE STRING "Install suffix for plugins") else() set(PLUGINS_PATH "psi-plus/plugins" CACHE STRING "Install suffix for plugins") endif() add_definitions(-DQT_PLUGIN) include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ../../include ) set(HEADERS rippercc.h ripperccoptions.h ) set(PLAIN_HEADERS qjsonwrapper.h ) set(SOURCES rippercc.cpp ripperccoptions.cpp qjsonwrapper.cpp ) set(FORMS ripperccoptions.ui ) set(RESOURCES resources.qrc ) find_package(Qt5 COMPONENTS Core Gui Widgets Xml Network REQUIRED) add_definitions(-DHAVE_QT5) set(QT_DEPLIBS Qt5::Core Qt5::Gui Qt5::Widgets Qt5::Xml Qt5::Network) unset(MOC_SOURCES) qt5_wrap_cpp(MOC_SOURCES ${HEADERS}) unset(UI_SOURCES) qt5_wrap_ui(UI_SOURCES ${FORMS}) unset(QRC_SOURCES) qt5_add_resources(QRC_SOURCES ${RESOURCES}) add_library(${PLUGIN} MODULE ${SOURCES} ${HEADERS} ${PLAIN_HEADERS} ${QRC_SOURCES} ${RESOURCES} ${MOC_SOURCES} ${FORMS} ${UI_SOURCES}) target_link_libraries(${PLUGIN} ${QT_DEPLIBS}) if(LINUX) install( TARGETS ${PLUGIN} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} ) elseif(WIN32) install( TARGETS ${PLUGIN} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} ) endif() plugins-1.5/dev/ripperccplugin/qjsonwrapper.cpp000066400000000000000000000101211336777360500221170ustar00rootroot00000000000000/* Copyright 2014, Uwe L. Korn * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "qjsonwrapper.h" // Qt version specific includes #if QT_VERSION >= QT_VERSION_CHECK( 5, 0, 0 ) #include #include #include #else #include #include #include #endif namespace QJsonWrapper { QVariantMap qobject2qvariant( const QObject* object ) { #if QT_VERSION >= QT_VERSION_CHECK( 5, 0, 0 ) QVariantMap map; if ( object == NULL ) { return map; } const QMetaObject* metaObject = object->metaObject(); for ( int i = 0; i < metaObject->propertyCount(); ++i ) { QMetaProperty metaproperty = metaObject->property( i ); if ( metaproperty.isReadable() ) { map[ QLatin1String( metaproperty.name() ) ] = object->property( metaproperty.name() ); } } return map; #else return QJson::QObjectHelper::qobject2qvariant( object ); #endif } void qvariant2qobject( const QVariantMap& variant, QObject* object ) { #if QT_VERSION >= QT_VERSION_CHECK( 5, 0, 0 ) for ( QVariantMap::const_iterator iter = variant.begin(); iter != variant.end(); ++iter ) { QVariant property = object->property( iter.key().toLatin1() ); Q_ASSERT( property.isValid() ); if ( property.isValid() ) { QVariant value = iter.value(); if ( value.canConvert( property.type() ) ) { value.convert( property.type() ); object->setProperty( iter.key().toLatin1(), value ); } else if ( QString( QLatin1String("QVariant") ).compare( QLatin1String( property.typeName() ) ) == 0 ) { object->setProperty( iter.key().toLatin1(), value ); } } } #else QJson::QObjectHelper::qvariant2qobject( variant, object ); #endif } QVariant parseJson( const QByteArray& jsonData, bool* ok ) { #if QT_VERSION >= QT_VERSION_CHECK( 5, 0, 0 ) QJsonParseError error; QJsonDocument doc = QJsonDocument::fromJson( jsonData, &error ); if ( ok != NULL ) { *ok = ( error.error == QJsonParseError::NoError ); } return doc.toVariant(); #else QJson::Parser p; return p.parse( jsonData, ok ); #endif } QByteArray toJson( const QVariant &variant, bool* ok ) { #if QT_VERSION >= QT_VERSION_CHECK( 5, 0, 0 ) QVariant _variant = variant; if ( variant.type() == QVariant::Hash ) { // QJsonDocument cannot deal with QVariantHash, so convert. const QVariantHash hash = variant.toHash(); QVariantMap map; QHashIterator it(hash); while ( it.hasNext() ) { it.next(); map.insert( it.key(), it.value() ); } _variant = map; } QJsonDocument doc = QJsonDocument::fromVariant( _variant ); if ( ok != NULL ) { *ok = !doc.isNull(); } return doc.toJson(); #else QJson::Serializer serializer; return serializer.serialize( variant, ok ); #endif } } plugins-1.5/dev/ripperccplugin/qjsonwrapper.h000066400000000000000000000060301336777360500215700ustar00rootroot00000000000000/* Copyright 2014, Uwe L. Korn * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #pragma once #ifndef QJSONWRAPPER_JSON_H #define QJSONWRAPPER_JSON_H #include namespace QJsonWrapper { /** * Convert a QObject instance to a QVariantMap by adding its properties * as key-value pairs. * * @param object Object that shall be "serialised" * @return All properties of the object stored as QVariantMap */ QVariantMap qobject2qvariant( const QObject* object ); /** * Write out all key-value pairs into the respective properties of the * given object. * * @param variant The key-value pairs that shall be stored in the object. * @param object The destiation object where we store the key-value pairs of the map as properties. */ void qvariant2qobject( const QVariantMap& variant, QObject* object ); /** * Parse the JSON string and return the result as a QVariant. * * @param jsonData The string containing the data as JSON. * @param ok Set to true if the conversion was successful, otherwise false. * @return After a successful conversion the parsed data either as QVariantMap or QVariantList. */ QVariant parseJson( const QByteArray& jsonData, bool* ok = 0 ); /** * Convert a QVariant to a JSON representation. * * This function will accept Strings, Number, QVariantList and QVariantMaps * as input types. Although Qt5's JSON implementation itself does not * support the serialisation of QVariantHash, we will convert a QVariantHash * to a QVariantMap but it is suggest to convert all QVariantHash to * QVariantMap in your code than passing them here. * * @param variant The data to be serialised. * @param ok Set to true if the conversion was successful, otherwise false. * @return After a successful serialisation the data of the QVariant represented as JSON. */ QByteArray toJson( const QVariant &variant, bool* ok = 0 ); } #endif // QJSONWRAPPER_JSON_H plugins-1.5/dev/ripperccplugin/resources.qrc000066400000000000000000000001401336777360500214010ustar00rootroot00000000000000 rippercc.png plugins-1.5/dev/ripperccplugin/rippercc.cpp000066400000000000000000000174231336777360500212070ustar00rootroot00000000000000/* * rippercc.cpp * * Copyright (C) 2016 * * 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 "rippercc.h" #include "qjsonwrapper.h" #include #include #include #include #include #include #include #include #include #include #include #define TIMER_INTERVAL (30 * 60 * 1000) /* 30 minutes */ #define RIPPER_DB_URL "https://ripper.cc/api/v1/plugin/jabber?format=json" #define RIPPER_PREFIX "Ripper! " #define RIPPER_GROUP "Rippers" #define NONASCII_PREFIX "non ASCII " #define ATTENTION_MESSAGE \ "ATTENTION! WARNING! This man real ripper, read more here in his profile.
" \ "ВНИМАНИЕ! ОСТОРОЖНО! Этот человек реальный обманщик, подробнее прочитать в его профиле.
" \ "https://ripper.cc%1" #define NONASCII_MESSAGE "WARNING! NON ASCII | Jabber с русскими буквами!" #ifndef HAVE_QT5 Q_EXPORT_PLUGIN2(RipperCC, RipperCC); #endif RipperCC::RipperCC() : _enabled(false) , _accountHost(0) , _optionHost(0) , _stanzaSending(0) , _accountInfo(0) , _appInfo(0) , _nam(0) , _timer(new QTimer(this)) , _optionsForm(0) { _timer->setInterval(TIMER_INTERVAL); _timer->setSingleShot(true); connect(_timer, SIGNAL(timeout()), SLOT(updateRipperDb())); } RipperCC::~RipperCC() { } QWidget *RipperCC::options() { if (!_enabled) { return 0; } _optionsForm = new RipperCCOptions(); _optionsForm->setOptionAccessingHost(_optionHost); _optionsForm->loadSettings(); return qobject_cast(_optionsForm); } bool RipperCC::enable() { _enabled = true; Proxy psiProxy = _appInfo->getProxyFor(name()); QNetworkProxy::ProxyType type; if(psiProxy.type == "socks") { type = QNetworkProxy::Socks5Proxy; } else { type = QNetworkProxy::HttpProxy; } QNetworkProxy proxy(type, psiProxy.host, psiProxy.port, psiProxy.user, psiProxy.pass); _nam = new QNetworkAccessManager(this); if (!proxy.hostName().isEmpty()) _nam->setProxy(proxy); updateRipperDb(); return _enabled; } bool RipperCC::disable() { _timer->stop(); _enabled = false; _nam->deleteLater(); _nam = 0; return true; } void RipperCC::applyOptions() { _optionsForm->saveSettings(); } void RipperCC::restoreOptions() { } QPixmap RipperCC::icon() const { return QPixmap(":/icons/rippercc.png"); } QString RipperCC::pluginInfo() { return QString(); } bool RipperCC::incomingStanza(int account, const QDomElement& stanza) { if (!_enabled) { return false; } handleStanza(account, stanza, true); return false; } bool RipperCC::outgoingStanza(int account, QDomElement &stanza) { if (!_enabled) { return false; } handleStanza(account, stanza, false); return false; } void RipperCC::handleStanza(int account, const QDomElement &stanza, bool incoming) { if (stanza.tagName() != QLatin1String("message") || stanza.attribute(QLatin1String("type")) != QLatin1String("chat")) return; QString from = incoming ? stanza.attribute(QLatin1String("from")) : stanza.attribute(QLatin1String("to")); QString jid = from.split(QLatin1Char('/')).first(); QString contactNick = _contactInfo->name(account, jid); QString newContactNick = contactNick; QString group; // Check for non ascii symbols in JID bool needAlert = false; for (int i = 0; i < jid.length(); i++) { if (jid[i].toLatin1() == 0) { needAlert = true; break; } } if (needAlert) { _accountHost->appendSysMsg(account, from, QString::fromUtf8(NONASCII_MESSAGE)); if (!newContactNick.startsWith(QLatin1String(NONASCII_PREFIX)) && !newContactNick.startsWith(QLatin1String(RIPPER_PREFIX))) { newContactNick.prepend(QLatin1String(NONASCII_PREFIX)); } } // Check for ripper int ripperIndex = -1; for (int i = 0; i < _rippers.size(); ++i) { if (_rippers.at(i).jid == jid) { ripperIndex = i; break; } } if (ripperIndex >= 0) { int attentionInterval = _optionHost->getPluginOption("attention-interval", 1).toInt() * 60; if (!_rippers.at(ripperIndex).lastAttentionTime.isValid() || _rippers.at(ripperIndex).lastAttentionTime.secsTo(QDateTime::currentDateTime()) >= attentionInterval) { _rippers[ripperIndex].lastAttentionTime = QDateTime::currentDateTime(); _accountHost->appendSysMsg(account, from, QString::fromUtf8(ATTENTION_MESSAGE).arg(_rippers.at(ripperIndex).url)); if (!newContactNick.startsWith(QLatin1String(RIPPER_PREFIX))) { group = QLatin1String(RIPPER_GROUP); newContactNick.prepend(QLatin1String(RIPPER_PREFIX)); } } } if (newContactNick != contactNick) updateNameGroup(account, jid, newContactNick, group); } void RipperCC::updateRipperDb() { QNetworkRequest request(QString(RIPPER_DB_URL)); request.setRawHeader("User-Agent", "RipperCC Plugin (Psi+)"); QNetworkReply *reply = _nam->get(request); connect(reply, SIGNAL(finished()), SLOT(parseRipperDb())); } void RipperCC::parseRipperDb() { _timer->start(); QNetworkReply *reply = qobject_cast(sender()); // Occurs error if(reply->error() != QNetworkReply::NoError) { qDebug() << "RippperCC Plugin:" << reply->errorString(); reply->close(); return; } // No errors QByteArray ba = reply->readAll(); QVariantMap ripperMap = QJsonWrapper::parseJson(ba).toMap(); if (!ripperMap.contains(QLatin1String("rippers"))) return; QVariantList ripperList = ripperMap.value(QLatin1String("rippers")).toList(); if (ripperList.isEmpty()) return; _rippers.clear(); foreach (const QVariant &item, ripperList) { Ripper ripper; ripper.jid = item.toMap().value(QLatin1String("jabber")).toString(); ripper.url = item.toMap().value(QLatin1String("link")).toString(); _rippers << ripper; } } void RipperCC::updateNameGroup(int account, const QString &jid, const QString &name, const QString &group) { if (name.isEmpty()) return; // // // // // // // QDomDocument doc; QDomElement iqElement = doc.createElement(QLatin1String("iq")); iqElement.setAttribute(QLatin1String("type"), QLatin1String("set")); iqElement.setAttribute(QLatin1String("id"), _stanzaSending->uniqueId(account)); QDomElement queryElement = doc.createElement(QLatin1String("query")); queryElement.setAttribute(QLatin1String("xmlns"), QLatin1String("jabber:iq:roster")); QDomElement itemElement = doc.createElement(QLatin1String("item")); itemElement.setAttribute(QLatin1String("name"), name); itemElement.setAttribute(QLatin1String("jid"), jid); if (!group.isEmpty()) { QDomElement groupElement = doc.createElement(QLatin1String("group")); QDomText textNode = doc.createTextNode(group); groupElement.appendChild(textNode); itemElement.appendChild(groupElement); } queryElement.appendChild(itemElement); iqElement.appendChild(queryElement); _stanzaSending->sendStanza(account, iqElement); } plugins-1.5/dev/ripperccplugin/rippercc.h000066400000000000000000000075201336777360500206510ustar00rootroot00000000000000/* * rippercc.cpp * * Copyright (C) 2016 * * 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. */ #ifndef RIPPERCC_H #define RIPPERCC_H #include "ripperccoptions.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include class RipperCC : public QObject , public PsiPlugin , public PluginInfoProvider , public StanzaFilter , public PsiAccountController , public OptionAccessor , public StanzaSender , public AccountInfoAccessor , public ApplicationInfoAccessor , public ContactInfoAccessor { Q_OBJECT #ifdef HAVE_QT5 Q_PLUGIN_METADATA(IID "com.psi-plus.RipperCC") #endif Q_INTERFACES(PsiPlugin PluginInfoProvider StanzaFilter PsiAccountController OptionAccessor StanzaSender AccountInfoAccessor ApplicationInfoAccessor ContactInfoAccessor) public: RipperCC(); ~RipperCC(); // from PsiPlugin QString name() const { return "RipperCC"; } QString shortName() const { return "rippercc"; } QString version() const { return "0.0.3"; } QWidget *options(); bool enable(); bool disable(); void applyOptions(); void restoreOptions(); QPixmap icon() const; // from PluginInfoProvider QString pluginInfo(); // from StanzaSender void setStanzaSendingHost(StanzaSendingHost *host) { _stanzaSending = host; } // from StanzaFilter bool incomingStanza(int account, const QDomElement &stanza); bool outgoingStanza(int account, QDomElement &stanza); // from PsiAccountController void setPsiAccountControllingHost(PsiAccountControllingHost *host) { _accountHost = host; } // from OptionAccessor void setOptionAccessingHost(OptionAccessingHost *host) { _optionHost = host; } void optionChanged(const QString &/*option*/) { } // from AccountInfoAccessor void setAccountInfoAccessingHost(AccountInfoAccessingHost* host) { _accountInfo = host; } // from ApplicationInfoAccessor void setApplicationInfoAccessingHost(ApplicationInfoAccessingHost *host) { _appInfo = host; } // from ContactInfoAccessor void setContactInfoAccessingHost(ContactInfoAccessingHost *host) { _contactInfo = host; } void handleStanza(int account, const QDomElement &stanza, bool incoming); public slots: void updateRipperDb(); void parseRipperDb(); private: void updateNameGroup(int account, const QString &jid, const QString &name, const QString &group); bool _enabled; PsiAccountControllingHost *_accountHost; OptionAccessingHost *_optionHost; StanzaSendingHost *_stanzaSending; AccountInfoAccessingHost *_accountInfo; ApplicationInfoAccessingHost *_appInfo; ContactInfoAccessingHost *_contactInfo; QNetworkAccessManager *_nam; QTimer *_timer; RipperCCOptions *_optionsForm; struct Ripper { QString jid; QString url; QDateTime lastAttentionTime; }; QList _rippers; }; #endif // RIPPERCC_H plugins-1.5/dev/ripperccplugin/rippercc.png000066400000000000000000000016151336777360500212050ustar00rootroot00000000000000PNG  IHDR(-SgAMA a cHRMz&u0`:pQ<zPLTE))vv}}&&把::**{{뤤&&}}ԅ''길||偁 J((WYYmmm껻++ܢ(( EGG((++ƭद*  CDDÓƹgg++aatt윜줤""円扉tttRNSIJ믑84bKGD$IDATb@Y`WAM\bz1{3{m98^HCV$J1ô,ӈ %dv멊@3٪ԯɫ^[WHtY*v``phxdtl@&& N76wv,tyu.cJ7w,׽b?}v}}g3^P=qTRI'Ǎ2$^. |Y''_m%tEXtdate:create2016-10-28T08:46:33+05:00 e%tEXtdate:modify2016-10-25T23:06:15+05:00J!KIENDB`plugins-1.5/dev/ripperccplugin/ripperccoptions.cpp000066400000000000000000000024421336777360500226160ustar00rootroot00000000000000/* * ripperccoptions.cpp * * Copyright (C) 2016 * * 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 "ripperccoptions.h" #include "ui_ripperccoptions.h" #include "optionaccessinghost.h" RipperCCOptions::RipperCCOptions(QWidget *parent) : QWidget(parent), ui(new Ui::RipperCCOptions) { ui->setupUi(this); } RipperCCOptions::~RipperCCOptions() { delete ui; } void RipperCCOptions::loadSettings() { ui->sbInterval->setValue(_optionHost->getPluginOption("attention-interval", 1).toInt()); } void RipperCCOptions::saveSettings() { _optionHost->setPluginOption("attention-interval", ui->sbInterval->value()); } plugins-1.5/dev/ripperccplugin/ripperccoptions.h000066400000000000000000000024301336777360500222600ustar00rootroot00000000000000/* * ripperccoptions.h * * Copyright (C) 2016 * * 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. */ #ifndef RIPPERCCOPTIONS_H #define RIPPERCCOPTIONS_H #include class OptionAccessingHost; namespace Ui { class RipperCCOptions; } class RipperCCOptions : public QWidget { Q_OBJECT public: explicit RipperCCOptions(QWidget *parent = 0); ~RipperCCOptions(); void update(); void setOptionAccessingHost(OptionAccessingHost* host) { _optionHost = host; } void loadSettings(); void saveSettings(); private: Ui::RipperCCOptions *ui; OptionAccessingHost *_optionHost; }; #endif // RIPPERCCOPTIONS_H plugins-1.5/dev/ripperccplugin/ripperccoptions.ui000066400000000000000000000031071336777360500224500ustar00rootroot00000000000000 RipperCCOptions 0 0 400 300 Form Qt::Horizontal 40 20 Qt::Vertical 20 250 min. 1 600 Attention interval: plugins-1.5/dev/ripperccplugin/ripperccplugin.pro000066400000000000000000000007621336777360500224420ustar00rootroot00000000000000CONFIG += release QT += network isEmpty(PSISDK) { include(../../psiplugin.pri) } else { include($$PSISDK/plugins/psiplugin.pri) } equals(QT_MAJOR_VERSION, 4) { CONFIG += link_pkgconfig PKGCONFIG += QJson } INCLUDEPATH += $$PWD DEPENDPATH += $$PWD SOURCES += ripperccoptions.cpp \ rippercc.cpp \ qjsonwrapper.cpp HEADERS += ripperccoptions.h \ rippercc.h \ qjsonwrapper.h FORMS += ripperccoptions.ui RESOURCES += resources.qrc plugins-1.5/generic/000077500000000000000000000000001336777360500144755ustar00rootroot00000000000000plugins-1.5/generic/CMakeLists.txt000066400000000000000000000020731336777360500172370ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.1.0) #set( deprecated_list # captchaformsplugin # gmailserviceplugin #) set( plugins_list attentionplugin autoreplyplugin birthdayreminderplugin chessplugin cleanerplugin conferenceloggerplugin contentdownloaderplugin enummessagesplugin extendedmenuplugin extendedoptionsplugin gnupgplugin gomokugameplugin historykeeperplugin httpuploadplugin icqdieplugin imageplugin imagepreviewplugin jabberdiskplugin juickplugin messagefilterplugin otrplugin pepchangenotifyplugin qipxstatusesplugin screenshotplugin skinsplugin stopspamplugin storagenotesplugin translateplugin videostatusplugin watcherplugin ) if( NOT MSVC ) list(APPEND plugins_list clientswitcherplugin ) endif() if( "${BUILD_PLUGINS}" STREQUAL "ALL" ) set ( plugins ${plugins_list} ) else() set ( plugins "${BUILD_PLUGINS}" ) endif() foreach(plugin ${plugins_list}) foreach(subdir ${plugins}) if( ${plugin} STREQUAL ${subdir} ) message("Parse subdirectory: ./${plugin}") add_subdirectory("./${plugin}") endif() endforeach() endforeach() plugins-1.5/generic/attentionplugin/000077500000000000000000000000001336777360500177215ustar00rootroot00000000000000plugins-1.5/generic/attentionplugin/CMakeLists.txt000066400000000000000000000025311336777360500224620ustar00rootroot00000000000000unset(_HDRS) unset(_UIS) unset(_SRCS) unset(_RSCS) unset(PLUGIN) set( PLUGIN attentionplugin ) project(${PLUGIN}) cmake_minimum_required(VERSION 3.1.0) set( CMAKE_AUTOMOC TRUE ) IF( NOT WIN32 ) set( LIB_SUFFIX "" CACHE STRING "Define suffix of directory name (32/64)" ) set( PLUGINS_PATH "lib${LIB_SUFFIX}/psi-plus/plugins" CACHE STRING "Install suffix for plugins" ) ELSE() set( PLUGINS_PATH "psi-plus/plugins" CACHE STRING "Install suffix for plugins" ) ENDIF() add_definitions( -DQT_PLUGIN -DHAVE_QT5 ) include_directories( ${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ../../include . ) set( _HDRS ${PLUGIN}.h ) set( _SRCS ${PLUGIN}.cpp ) set( _UIS options.ui ) set( _RSCS ${PLUGIN}.qrc ) find_package( Qt5 COMPONENTS Widgets Xml REQUIRED ) set(QT_DEPLIBS Qt5::Widgets Qt5::Xml ) qt5_wrap_ui(UIS ${_UIS}) qt5_add_resources(RSCS ${_RSCS}) add_library( ${PLUGIN} MODULE ${_SRCS} ${UIS} ${RSCS} ) target_link_libraries( ${PLUGIN} ${QT_DEPLIBS} ) if( UNIX AND NOT( APPLE OR CYGWIN ) ) install( TARGETS ${PLUGIN} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} ) endif() if( WIN32 ) install( TARGETS ${PLUGIN} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} ) endif() plugins-1.5/generic/attentionplugin/attention.png000066400000000000000000000016471336777360500224440ustar00rootroot00000000000000PNG  IHDRabKGDԂ pHYsHHFk> vpAg\ƭIDAT8UOhSY^158Qd`mStaF7"ЅVQЅ ԕ,FZWZ3P4iw\ù;|+JY~(ֺ޵rg; Ѐ h۝f_f(OavH>0 ]kx])˒7n; Rs0ٛ&w #include #include "psiplugin.h" #include "stanzafilter.h" #include "accountinfoaccessor.h" #include "accountinfoaccessinghost.h" #include "optionaccessor.h" #include "optionaccessinghost.h" #include "activetabaccessinghost.h" #include "activetabaccessor.h" #include "stanzasender.h" #include "stanzasendinghost.h" #include "iconfactoryaccessor.h" #include "iconfactoryaccessinghost.h" #include "toolbariconaccessor.h" #include "popupaccessor.h" #include "popupaccessinghost.h" #include "menuaccessor.h" #include "applicationinfoaccessor.h" #include "applicationinfoaccessinghost.h" #include "plugininfoprovider.h" #include "soundaccessinghost.h" #include "soundaccessor.h" #include "ui_options.h" #define cVer "0.2.0" #define constSoundFile "sndfl" #define constInterval "intrvl" #define constInfPopup "infPopup" #define constTimeout "timeout" #define constDisableDnd "dsbldnd" #define POPUP_OPTION "Attention Plugin" class AttentionPlugin: public QObject, public PsiPlugin, public StanzaFilter, public AccountInfoAccessor, public OptionAccessor, public ActiveTabAccessor, public ToolbarIconAccessor, public ApplicationInfoAccessor, public IconFactoryAccessor, public PopupAccessor, public StanzaSender, public MenuAccessor, public PluginInfoProvider, public SoundAccessor { Q_OBJECT #ifdef HAVE_QT5 Q_PLUGIN_METADATA(IID "com.psi-plus.AttentionPlugin") #endif Q_INTERFACES(PsiPlugin StanzaFilter AccountInfoAccessor OptionAccessor ActiveTabAccessor ApplicationInfoAccessor ToolbarIconAccessor IconFactoryAccessor PopupAccessor StanzaSender MenuAccessor PluginInfoProvider SoundAccessor) public: AttentionPlugin(); virtual QString name() const; virtual QString shortName() const; virtual QString version() const; virtual QWidget* options(); virtual bool enable(); virtual bool disable(); virtual void applyOptions(); virtual void restoreOptions(); virtual bool incomingStanza(int account, const QDomElement& xml); virtual bool outgoingStanza(int account, QDomElement& xml); virtual void setAccountInfoAccessingHost(AccountInfoAccessingHost* host); virtual void setOptionAccessingHost(OptionAccessingHost* host); virtual void optionChanged(const QString& option); virtual void setActiveTabAccessingHost(ActiveTabAccessingHost* host); virtual void setIconFactoryAccessingHost(IconFactoryAccessingHost* host); virtual void setPopupAccessingHost(PopupAccessingHost* host); virtual void setStanzaSendingHost(StanzaSendingHost *host); virtual QList < QVariantHash > getButtonParam(); virtual QAction* getAction(QObject* , int , const QString& ) { return 0; }; virtual QList < QVariantHash > getAccountMenuParam(); virtual QList < QVariantHash > getContactMenuParam(); virtual QAction* getContactAction(QObject* , int , const QString& ) { return 0; }; virtual QAction* getAccountAction(QObject* , int ) { return 0; }; virtual void setApplicationInfoAccessingHost(ApplicationInfoAccessingHost* host); virtual void setSoundAccessingHost(SoundAccessingHost* host); virtual QString pluginInfo(); virtual QPixmap icon() const; private: bool enabled; OptionAccessingHost* psiOptions; AccountInfoAccessingHost *accInfoHost; ActiveTabAccessingHost* activeTab; IconFactoryAccessingHost *icoHost; PopupAccessingHost* popup; StanzaSendingHost *stanzaSender; ApplicationInfoAccessingHost* appInfo; SoundAccessingHost* sound_; QString soundFile; int timeout_; bool infPopup, disableDnd; QTimer *nudgeTimer_; QPointer nudgeWindow_; QPoint oldPoint_; QPointer options_; int popupId; struct Blocked { int Acc; QString Jid; QDateTime LastMes; }; QVector blockedJids_; Ui::Options ui_; enum { FakeAccount = 9999 }; bool findAcc(int account, const QString& Jid, int &i); void sendAttention(int account, const QString& yourJid, const QString& jid); void nudge(); void playSound(const QString& soundFile); void showPopup(int account, const QString& jid, const QString& text); private slots: void checkSound(); void getSound(); void sendAttentionFromTab(); void sendAttentionFromMenu(); void nudgeTimerTimeout(); }; #ifndef HAVE_QT5 Q_EXPORT_PLUGIN(AttentionPlugin); #endif AttentionPlugin::AttentionPlugin() : enabled(false) , psiOptions(0) , accInfoHost(0) , activeTab(0) , icoHost(0) , popup(0) , stanzaSender(0) , appInfo(0) , sound_(0) , soundFile("sound/attention.wav") , timeout_(30) , infPopup(false) , disableDnd(false) , nudgeTimer_(0) , popupId(0) { } QString AttentionPlugin::name() const { return "Attention Plugin"; } QString AttentionPlugin::shortName() const { return "attention"; } QString AttentionPlugin::version() const { return cVer; } bool AttentionPlugin::enable() { QFile file(":/attentionplugin/attention.png"); if ( file.open(QIODevice::ReadOnly) ) { QByteArray image = file.readAll(); icoHost->addIcon("attentionplugin/attention",image); file.close(); } else { enabled = false; return enabled; } if(psiOptions) { blockedJids_.clear(); enabled = true; soundFile = psiOptions->getPluginOption(constSoundFile, QVariant(soundFile)).toString(); timeout_ = psiOptions->getPluginOption(constTimeout, QVariant(timeout_)).toInt(); infPopup = psiOptions->getPluginOption(constInfPopup, QVariant(infPopup)).toBool(); disableDnd = psiOptions->getPluginOption(constDisableDnd, QVariant(disableDnd)).toBool(); popupId = popup->registerOption(POPUP_OPTION, psiOptions->getPluginOption(constInterval, QVariant(4000)).toInt()/1000, "plugins.options."+shortName()+"."+constInterval); QWidgetList wl = qApp->allWidgets(); foreach(QWidget *w, wl) { if(w->objectName() == "MainWin") { nudgeWindow_ = w; break; } } nudgeTimer_ = new QTimer(this); nudgeTimer_->setInterval(50); connect(nudgeTimer_, SIGNAL(timeout()), SLOT(nudgeTimerTimeout())); } return enabled; } bool AttentionPlugin::disable() { enabled = false; nudgeTimer_->stop(); delete nudgeTimer_; nudgeTimer_ = 0; popup->unregisterOption(POPUP_OPTION); return true; } QWidget* AttentionPlugin::options() { if(!enabled) { return 0; } options_ = new QWidget(); ui_.setupUi(options_); ui_.tb_open->setIcon(icoHost->getIcon("psi/browse")); ui_.tb_test->setIcon(icoHost->getIcon("psi/play")); connect(ui_.tb_open, SIGNAL(clicked()), SLOT(getSound())); connect(ui_.tb_test, SIGNAL(clicked()), SLOT(checkSound())); restoreOptions(); return options_; } bool AttentionPlugin::incomingStanza(int account, const QDomElement& stanza) { if (enabled) { if(stanza.tagName() == "message" && stanza.attribute("type") == "headline" && !stanza.firstChildElement("attention").isNull()) { if(disableDnd && accInfoHost->getStatus(account) == "dnd") return false; QString from = stanza.attribute("from"); int i = blockedJids_.size(); if(findAcc(account, from, i)) { Blocked &B = blockedJids_[i]; if(QDateTime::currentDateTime().secsTo(B.LastMes) > -timeout_) { return false; } else { B.LastMes = QDateTime::currentDateTime(); } } else { Blocked B = { account, from, QDateTime::currentDateTime() }; blockedJids_ << B; } const QString optAway = "options.ui.notifications.passive-popups.suppress-while-away"; QVariant suppressAway = psiOptions->getGlobalOption(optAway); const QString optDnd = "options.ui.notifications.passive-popups.suppress-while-dnd"; QVariant suppressDnd = psiOptions->getGlobalOption(optDnd); int interval = popup->popupDuration(POPUP_OPTION); if(infPopup && (accInfoHost->getStatus(account) == "away" || accInfoHost->getStatus(account) == "xa")) { psiOptions->setGlobalOption(optAway, false); popup->setPopupDuration(POPUP_OPTION, -1); } psiOptions->setGlobalOption(optDnd, disableDnd); showPopup(account, from.split("/").first(), from + tr(" sends Attention message to you!")); psiOptions->setGlobalOption(optAway, suppressAway); psiOptions->setGlobalOption(optDnd, suppressDnd); popup->setPopupDuration(POPUP_OPTION, interval); if(psiOptions->getGlobalOption("options.ui.notifications.sounds.enable").toBool()) playSound(soundFile); /*QTextEdit *te = activeTab->getEditBox(); if(te) nudgeWindow_ = te->window(); else nudgeWindow_ = qApp->activeWindow();*/ if(nudgeWindow_ && nudgeWindow_->isVisible()) nudge(); } else if(stanza.tagName() == "iq" && stanza.attribute("type") == "get") { QDomElement query = stanza.firstChildElement("query"); if(!query.isNull() && query.attribute("xmlns") == "http://jabber.org/protocol/disco#info") { if(query.attribute("node") == "http://psi-dev.googlecode.com/caps#at-pl") { QString reply = QString("" "" "") .arg(stanzaSender->escape(stanza.attribute("from")), stanzaSender->escape(stanza.attribute("id"))); stanzaSender->sendStanza(account, reply); return true; } } } } return false; } bool AttentionPlugin::outgoingStanza(int /*account*/, QDomElement& xml) { if(enabled) { if(xml.tagName() == "iq" && xml.attribute("type") == "result") { QDomNodeList list = xml.elementsByTagNameNS("http://jabber.org/protocol/disco#info", "query"); if(!list.isEmpty()) { QDomElement query = list.at(0).toElement(); if(!query.hasAttribute("node")) { QDomDocument doc = xml.ownerDocument(); QDomElement feature = doc.createElement("feature"); feature.setAttribute("var", "urn:xmpp:attention:0"); query.appendChild(feature); } } } else if(xml.tagName() == "presence") { QDomNodeList list = xml.elementsByTagNameNS("http://jabber.org/protocol/caps", "c"); if(!list.isEmpty()) { QDomElement c = list.at(0).toElement(); if(c.hasAttribute("ext")) { QString ext = c.attribute("ext"); ext += " at-pl"; c.setAttribute("ext", ext); } } } } return false; } void AttentionPlugin::applyOptions() { if (!options_) return; soundFile = ui_.le_sound->text(); psiOptions->setPluginOption(constSoundFile,soundFile); timeout_ = ui_.sb_count->value(); psiOptions->setPluginOption(constTimeout, timeout_); infPopup = ui_.cb_dontHide->isChecked(); psiOptions->setPluginOption(constInfPopup, infPopup); disableDnd = ui_.cb_disableDND->isChecked(); psiOptions->setPluginOption(constDisableDnd, disableDnd); } void AttentionPlugin::restoreOptions() { if (!options_) return; ui_.le_sound->setText(soundFile); ui_.sb_count->setValue(timeout_); ui_.cb_dontHide->setChecked(infPopup); ui_.cb_disableDND->setChecked(disableDnd); } void AttentionPlugin::optionChanged(const QString &option) { Q_UNUSED(option); } void AttentionPlugin::setAccountInfoAccessingHost(AccountInfoAccessingHost* host) { accInfoHost = host; } void AttentionPlugin::setOptionAccessingHost(OptionAccessingHost* host) { psiOptions = host; } void AttentionPlugin::setActiveTabAccessingHost(ActiveTabAccessingHost* host) { activeTab = host; } void AttentionPlugin::setIconFactoryAccessingHost(IconFactoryAccessingHost *host) { icoHost = host; } void AttentionPlugin::setStanzaSendingHost(StanzaSendingHost *host) { stanzaSender = host; } void AttentionPlugin::setPopupAccessingHost(PopupAccessingHost* host) { popup = host; } void AttentionPlugin::setApplicationInfoAccessingHost(ApplicationInfoAccessingHost* host) { appInfo = host; } void AttentionPlugin::setSoundAccessingHost(SoundAccessingHost *host) { sound_ = host; } QList < QVariantHash > AttentionPlugin::getButtonParam() { QList< QVariantHash > l; QVariantHash hash; hash["tooltip"] = QVariant(tr("Send Attention")); hash["icon"] = QVariant(QString("attentionplugin/attention")); hash["reciver"] = qVariantFromValue(qobject_cast(this)); hash["slot"] = QVariant(SLOT(sendAttentionFromTab())); l.push_back(hash); return l; } void AttentionPlugin::playSound(const QString& f) { sound_->playSound(f); } void AttentionPlugin::getSound() { QString fileName = QFileDialog::getOpenFileName(0,tr("Choose a sound file"),"", tr("Sound (*.wav)")); if(fileName.isEmpty()) return; ui_.le_sound->setText(fileName); } void AttentionPlugin::checkSound() { playSound(ui_.le_sound->text()); } void AttentionPlugin::showPopup(int account, const QString &jid, const QString &text) { if(account == FakeAccount) { popup->initPopup(text, tr("Attention Plugin"), "attentionplugin/attention", popupId); } else { popup->initPopupForJid(account, jid, text, tr("Attention Plugin"), "attentionplugin/attention", popupId); } } void AttentionPlugin::sendAttention(int account, const QString& yourJid, const QString& jid) { if(accInfoHost->getStatus(account) == "offline") return; QString msg = QString("").arg(yourJid).arg(jid); stanzaSender->sendStanza(account, msg); showPopup(FakeAccount, QString(), tr("You sent Attention message to %1").arg(jid)); } void AttentionPlugin::sendAttentionFromTab() { if(!enabled) return; QString yourJid = activeTab->getYourJid(); QString jid = activeTab->getJid(); QString tmpJid(""); int account = 0; while (yourJid != (tmpJid = accInfoHost->getJid(account))){ ++account; if (tmpJid == "-1") return; } sendAttention(account, yourJid, jid); } void AttentionPlugin::sendAttentionFromMenu() { int acc = sender()->property("account").toInt(); QString jid = sender()->property("jid").toString(); QString yourJid = accInfoHost->getJid(acc); sendAttention(acc, yourJid, jid); } bool AttentionPlugin::findAcc(int account, const QString& Jid, int &i) { for(; i > 0;) { Blocked Block = blockedJids_[--i]; if(Block.Acc == account && Block.Jid == Jid) { return true; } } return false; } QList < QVariantHash > AttentionPlugin::getAccountMenuParam() { return QList < QVariantHash >(); } QList < QVariantHash > AttentionPlugin::getContactMenuParam() { QVariantHash hash; hash["icon"] = QVariant(QString("attentionplugin/attention")); hash["name"] = QVariant(tr("Send Attention")); hash["reciver"] = qVariantFromValue(qobject_cast(this)); hash["slot"] = QVariant(SLOT(sendAttentionFromMenu())); QList< QVariantHash > l; l.push_back(hash); return l; } void AttentionPlugin::nudge() { if(!nudgeWindow_ || !nudgeTimer_ || nudgeTimer_->isActive()) return; oldPoint_ = nudgeWindow_->pos(); nudgeTimer_->start(); } void AttentionPlugin::nudgeTimerTimeout() { static uint count = 0; if(!nudgeWindow_) { nudgeTimer_->stop(); count = 0; return; } if(count < 40) { int rH = qrand()%10, rW = qrand()%10; QPoint newPoint(oldPoint_.x()+rH, oldPoint_.y()+rW); nudgeWindow_->move(newPoint); count++; } else { count = 0; nudgeTimer_->stop(); nudgeWindow_->move(oldPoint_); } } QString AttentionPlugin::pluginInfo() { return tr("Author: ") + "Dealer_WeARE\n" + tr("Email: ") + "wadealer@gmail.com\n\n" + trUtf8("This plugin is designed to send and receive special messages such as Attentions.\n" "To work correctly, the plugin requires that the client of the other part supports XEP-0224 (for example: Pidgin, Miranda IM with Nudge plugin)."); } QPixmap AttentionPlugin::icon() const { return QPixmap(":/attentionplugin/attention.png"); } #include "attentionplugin.moc" plugins-1.5/generic/attentionplugin/attentionplugin.pro000066400000000000000000000002771336777360500236750ustar00rootroot00000000000000isEmpty(PSISDK) { include(../../psiplugin.pri) } else { include($$PSISDK/plugins/psiplugin.pri) } RESOURCES = attentionplugin.qrc SOURCES += attentionplugin.cpp FORMS += options.ui plugins-1.5/generic/attentionplugin/attentionplugin.qrc000066400000000000000000000001541336777360500236540ustar00rootroot00000000000000 attention.png plugins-1.5/generic/attentionplugin/changelog.txt000066400000000000000000000067111336777360500224160ustar00rootroot000000000000002013-08-13 v0.2.0 - taurus + Иконка плагина 2012-02-20 v0.1.9 * исправления для нового попап-интерфейса * в попапе используется иконка плагина 2011-02-08 v0.1.7 * для проигрывания звука теперь используется новый плагинный интерфейс 2011-02-03 v0.1.6 * плагин теперь использует настройки попапов из настроек приложения * оптимизация кода 2011-01-13 v0.1.5 + во всплывающем уведомлении теперь показывается аватарка и иконка статуса отправителя + щелчок мыши на всплывающем уведомлении вызывает теперь окно чата с данным контактом 2011-01-05 v0.1.4 + теперь плагин умеет сообщать о том, что ваш клиент поддерживает сообщения типа Attention. Это позволит таким клиентам, как например Pidgin, отправлять вам такие сообщения (для этого используется XEP-0115: Entity Capabilities, Version: 1.3) 2010-10-26 v0.1.3 + добавлена тряска окна ростера при получении сообщений типа Attention 2010-09-11 v0.1.2 * обновлена ссылка на wiki ( http://psi-plus.com/wiki/plugins#attention_plugin ) 2010-08-25 v0.1.1 * совместимость с последней версией Psi+ 2010-05-17 v0.1.0 + добавлена информация о плагине 2010-05-04 v0.0.9 * исправлена ссылка на wiki 2010-04-13 v0.0.8 + в настройки по-умолчанию добавлен звуковой файл attention.wav 2010-03-11 v0.0.7 + иконки на кнопках в настройках плагина 2010-02-23 v0.0.6 + добавлен пункт меню в контекстное меню контакта 2010-01-26 v0.0.5 * более корректное отключение плагина 2010-01-25 v0.0.4 + добавлена возможность отключить уведомления, если статус "do not disturb" (не беспокоить) + добавлена возможность задать интервал, в течение которого будет показано только одно уведомление для каждого контакта 2010-01-19 v0.0.3 + добавлена возможность отключить исчезновение всплывающих окон, если статус "отсутствую" или "недоступен" + добавлена возможность отключить исчезновение всплывающих окон для всех статусов 2010-01-12 v0.0.2 * исправлена совместимость с новыми ревизиями Psi+ 2010-01-11 v0.0.1 ! initial version Данный плагин предназначен для отправки и приёма сообщений типа Attention. Для работы необходимо, чтобы клиент собеседника поддерживал XEP-0224: Attention (например: Pidgin, Miranda IM с плагином Nudge) plugins-1.5/generic/attentionplugin/options.ui000066400000000000000000000056351336777360500217640ustar00rootroot00000000000000 Options 0 0 502 172 Form Allow receiving one Attention from the same contact every sec Qt::Horizontal 0 0 Don't hide popup if status is Away or XA Disable notifications if status is DND Play sound: Qt::Vertical 20 0 <a href="http://psi-plus.com/wiki/plugins#attention_plugin">Wiki (Online)</a> true plugins-1.5/generic/autoreplyplugin/000077500000000000000000000000001336777360500177405ustar00rootroot00000000000000plugins-1.5/generic/autoreplyplugin/CMakeLists.txt000066400000000000000000000024151336777360500225020ustar00rootroot00000000000000unset(_HDRS) unset(_UIS) unset(_SRCS) unset(_RSCS) unset(PLUGIN) set( PLUGIN autoreplyplugin ) project(${PLUGIN}) cmake_minimum_required(VERSION 3.1.0) set( CMAKE_AUTOMOC TRUE ) IF( NOT WIN32 ) set( LIB_SUFFIX "" CACHE STRING "Define suffix of directory name (32/64)" ) set( PLUGINS_PATH "lib${LIB_SUFFIX}/psi-plus/plugins" CACHE STRING "Install suffix for plugins" ) ELSE() set( PLUGINS_PATH "psi-plus/plugins" CACHE STRING "Install suffix for plugins" ) ENDIF() add_definitions( -DQT_PLUGIN -DHAVE_QT5 ) set( _SRCS ${PLUGIN}.cpp ) set( _RSCS resources.qrc ) include_directories( ${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ../../include . ) find_package( Qt5 COMPONENTS Widgets Xml REQUIRED ) set(QT_DEPLIBS Qt5::Widgets Qt5::Xml ) qt5_add_resources(RSCS ${_RSCS}) add_library( ${PLUGIN} MODULE ${_SRCS} ${UIS} ${RSCS} ) target_link_libraries( ${PLUGIN} ${QT_DEPLIBS} ) if( UNIX AND NOT( APPLE OR CYGWIN ) ) install( TARGETS ${PLUGIN} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} ) endif() if( WIN32 ) install( TARGETS ${PLUGIN} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} ) endif() plugins-1.5/generic/autoreplyplugin/autoreply.png000066400000000000000000000012021336777360500224650ustar00rootroot00000000000000PNG  IHDRatEXtSoftwareAdobe ImageReadyqe<$IDATxڜRMhAf: Cb *?JxVSY)ݢQ3L64*"X{E/S 4mkzTX, SI'l^Jn2ւf+0Ђ$ ,?#qVdn*~l?"i,dnyQR&Qq{l•>p8o-_hQ1q?29^;v]afVÍ.\%ԁ:lBu:w\ T9fɭt ܍YQ~^Yi|M><r)a3}=IENDB`plugins-1.5/generic/autoreplyplugin/autoreplyplugin.cpp000066400000000000000000000565561336777360500237300ustar00rootroot00000000000000/* * autoreplyplugin.cpp - plugin * Copyright (C) 2009-2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include #include #include #include #include #include #include #include #include #include "psiplugin.h" #include "optionaccessor.h" #include "optionaccessinghost.h" #include "stanzafilter.h" #include "stanzasender.h" #include "stanzasendinghost.h" #include "activetabaccessor.h" #include "activetabaccessinghost.h" #include "accountinfoaccessor.h" #include "accountinfoaccessinghost.h" #include "plugininfoprovider.h" #define cVer "0.3.2" #define constMessage "mssg" #define constDisableFor "dsblfr" #define constEnableFor "enblfr" #define constTimes "tms" #define constActiveTab "actvtb" #define constResetTime "rsttm" #define constEnableDisable "enbldsbl" #define constDisableForAcc "dsblfracc" #define constSOnline "online" #define constSAway "away" #define constSChat "chat" #define constSDnd "dnd" #define constSInvis "invis" #define constSXa "xa" #define constNotInRoster "ntnrstr" class AutoReply: public QObject, public PsiPlugin, public OptionAccessor, public StanzaSender, public StanzaFilter, public ActiveTabAccessor, public AccountInfoAccessor, public PluginInfoProvider { Q_OBJECT #ifdef HAVE_QT5 Q_PLUGIN_METADATA(IID "com.psi-plus.AutoReplyPlugin") #endif Q_INTERFACES(PsiPlugin OptionAccessor StanzaSender StanzaFilter ActiveTabAccessor AccountInfoAccessor PluginInfoProvider) public: AutoReply(); virtual QString name() const; virtual QString shortName() const; virtual QString version() const; virtual QWidget* options(); virtual bool enable(); virtual bool disable(); virtual void applyOptions(); virtual void restoreOptions(); virtual void setOptionAccessingHost(OptionAccessingHost* host); virtual void optionChanged(const QString& option); virtual void setStanzaSendingHost(StanzaSendingHost *host); virtual bool incomingStanza(int account, const QDomElement& stanza); virtual bool outgoingStanza(int account, QDomElement& stanza); virtual void setActiveTabAccessingHost(ActiveTabAccessingHost* host); virtual void setAccountInfoAccessingHost(AccountInfoAccessingHost* host); virtual QString pluginInfo(); virtual QPixmap icon() const; private: bool enabled; AccountInfoAccessingHost* AccInfoHost; ActiveTabAccessingHost* ActiveTabHost; OptionAccessingHost* psiOptions; StanzaSendingHost* StanzaHost; QTextEdit *messageWidget; QTextEdit *disableforWidget; QString Message; QString DisableFor; QSpinBox *spinWidget; QSpinBox *resetWidget; QCheckBox *activetabWidget; QComboBox *enabledisableWidget; QTextEdit *DisableForAccWidget; QCheckBox *sonlineWidget; QCheckBox *sawayWidget; QCheckBox *sdndWidget; QCheckBox *sxaWidget; QCheckBox *schatWidget; QCheckBox *sinvisWidget; QCheckBox *NotInRosterWidget; bool NotInRoster; int EnableDisable; struct Base { int Account; QString Jid; int count; QDateTime LastMes; }; QVector Counter; int Times; int ResetTime; bool ActiveTabIsEnable; bool SOnline; bool SAway; bool SDnd; bool SXa; bool SChat; bool SInvis; QString DisableForAcc; bool FindAcc(int account, QString jid, int &i); private slots: void setEnableDisableText(int Arg); }; #ifndef HAVE_QT5 Q_EXPORT_PLUGIN(AutoReply); #endif AutoReply::AutoReply() { ActiveTabIsEnable = true; NotInRosterWidget = 0; NotInRoster = true; EnableDisable = 1; Counter.clear(); Times = 2; ResetTime = 5; spinWidget = 0; activetabWidget = 0; DisableForAcc = ""; DisableForAccWidget = 0; resetWidget = 0; DisableFor = "juick@juick.com\npsi-dev@conference.jabber.ru\njubo@nologin.ru\njabrss@cmeerw.net\nrss2jabber.com\nbot.talk.google.com\nbot.rambler.ru\nnotify@planary.ru\nwebtoim@gmail.com\nwebtoim1@gmail.com\narx-bot-11@onblabla.ru\nen2ru@jtalk.ru\nru2en@jtalk.ru\ngluxi@inhex.net\nisida@xmpp.ru\ntwitter.tweet.im\nrss@isida-bot.com\nhuti.ua@gmail.com"; enabled = false; Message = "I'll write you later..."; messageWidget = 0; ActiveTabHost = 0; AccInfoHost = 0; disableforWidget = 0; psiOptions = 0; StanzaHost = 0; sonlineWidget = 0; sawayWidget = 0; sdndWidget = 0; sxaWidget = 0; schatWidget = 0; sinvisWidget = 0; SOnline = 0; SAway = 1; SDnd = 1; SXa = 1; SChat = 0; SInvis = 0; } QString AutoReply::name() const { return "Auto Reply Plugin"; } QString AutoReply::shortName() const { return "replyer"; } QString AutoReply::version() const { return cVer; } bool AutoReply::enable() { if (psiOptions) { enabled = true; QVariant vMessage(Message); vMessage = psiOptions->getPluginOption(constMessage); if (!vMessage.isNull()) { Message = vMessage.toString(); } QVariant vEnableDisable(EnableDisable); vEnableDisable = psiOptions->getPluginOption(constEnableDisable); if(!vEnableDisable.isNull()) { EnableDisable = vEnableDisable.toInt(); } if(EnableDisable) { QVariant vDisableFor(DisableFor); vDisableFor = psiOptions->getPluginOption(constDisableFor); if(!vDisableFor.isNull()) { DisableFor = vDisableFor.toString(); } } else { QVariant vDisableFor(DisableFor); vDisableFor = psiOptions->getPluginOption(constEnableFor); if(!vDisableFor.isNull()) { DisableFor = vDisableFor.toString(); } else { DisableFor = ""; } } QVariant vTimes(Times); vTimes = psiOptions->getPluginOption(constTimes); if (!vTimes.isNull()) { Times = vTimes.toInt(); } QVariant vActiveTabIsEnable(ActiveTabIsEnable); vActiveTabIsEnable = psiOptions->getPluginOption(constActiveTab); if(!vActiveTabIsEnable.isNull()) { ActiveTabIsEnable = vActiveTabIsEnable.toBool(); } QVariant vResetTime(ResetTime); vResetTime = psiOptions->getPluginOption(constResetTime); if(!vResetTime.isNull()) { ResetTime = vResetTime.toInt(); } QVariant vDisableForAcc(DisableForAcc); vDisableForAcc = psiOptions->getPluginOption(constDisableForAcc); if (!vDisableForAcc.isNull()) { DisableForAcc = vDisableForAcc.toString(); } QVariant vSOnline(SOnline); vSOnline = psiOptions->getPluginOption(constSOnline); if(!vSOnline.isNull()) { SOnline = vSOnline.toBool(); } QVariant vSAway(SAway); vSAway = psiOptions->getPluginOption(constSAway); if(!vSAway.isNull()) { SAway = vSAway.toBool(); } QVariant vSDnd(SDnd); vSDnd = psiOptions->getPluginOption(constSDnd); if(!vSDnd.isNull()) { SDnd = vSDnd.toBool(); } QVariant vSXa(SXa); vSXa = psiOptions->getPluginOption(constSXa); if(!vSXa.isNull()) { SXa = vSXa.toBool(); } QVariant vSChat(SChat); vSChat = psiOptions->getPluginOption(constSChat); if(!vSChat.isNull()) { SChat = vSChat.toBool(); } QVariant vSInvis(SInvis); vSInvis = psiOptions->getPluginOption(constSInvis); if(!vSInvis.isNull()) { SInvis = vSInvis.toBool(); } QVariant vNotInRoster(NotInRoster); vNotInRoster = psiOptions->getPluginOption(constNotInRoster); if(!vNotInRoster.isNull()) { NotInRoster = vNotInRoster.toBool(); } } return enabled; } bool AutoReply::disable() { enabled = false; return true; } void AutoReply::applyOptions() { if (messageWidget == 0 || disableforWidget == 0 || spinWidget == 0 || activetabWidget == 0 || resetWidget == 0 || enabledisableWidget ==0) { return; } QVariant vMessage(messageWidget->toPlainText()); psiOptions->setPluginOption(constMessage, vMessage); Message = vMessage.toString(); QVariant vEnableDisable(enabledisableWidget->currentIndex()); psiOptions->setPluginOption(constEnableDisable, vEnableDisable); EnableDisable = vEnableDisable.toInt(); if(EnableDisable) { QVariant vDisableFor(disableforWidget->toPlainText()); psiOptions->setPluginOption(constDisableFor, vDisableFor); DisableFor = vDisableFor.toString(); } else { QVariant vDisableFor(disableforWidget->toPlainText()); psiOptions->setPluginOption(constEnableFor, vDisableFor); DisableFor = vDisableFor.toString(); } QVariant vTimes(spinWidget->value()); psiOptions->setPluginOption(constTimes, vTimes); Times = vTimes.toInt(); QVariant vActiveTabIsEnable(activetabWidget->isChecked()); psiOptions->setPluginOption(constActiveTab, vActiveTabIsEnable); ActiveTabIsEnable = vActiveTabIsEnable.toBool(); QVariant vResetTime(resetWidget->value()); psiOptions->setPluginOption(constResetTime, vResetTime); ResetTime = vResetTime.toInt(); QVariant vDisableForAcc(DisableForAccWidget->toPlainText()); psiOptions->setPluginOption(constDisableForAcc, vDisableForAcc); DisableForAcc = vDisableForAcc.toString(); QVariant vSOnline(sonlineWidget->isChecked()); psiOptions->setPluginOption(constSOnline, vSOnline); SOnline = vSOnline.toBool(); QVariant vSAway(sawayWidget->isChecked()); psiOptions->setPluginOption(constSAway, vSAway); SAway = vSAway.toBool(); QVariant vSDnd(sdndWidget->isChecked()); psiOptions->setPluginOption(constSDnd, vSDnd); SDnd = vSDnd.toBool(); QVariant vSXa(sxaWidget->isChecked()); psiOptions->setPluginOption(constSXa, vSXa); SXa = vSXa.toBool(); QVariant vSChat(schatWidget->isChecked()); psiOptions->setPluginOption(constSChat, vSChat); SChat = vSChat.toBool(); QVariant vSInvis(sinvisWidget->isChecked()); psiOptions->setPluginOption(constSInvis, vSInvis); SInvis = vSInvis.toBool(); QVariant vNotInRoster(NotInRosterWidget->isChecked()); psiOptions->setPluginOption(constNotInRoster, vNotInRoster); NotInRoster = vNotInRoster.toBool(); } void AutoReply::restoreOptions() { if (messageWidget == 0 || disableforWidget == 0 || spinWidget == 0 || activetabWidget == 0 || resetWidget ==0 || enabledisableWidget == 0) { return; } QVariant vMessage(Message); vMessage = psiOptions->getPluginOption(constMessage); if (!vMessage.isNull()) { messageWidget->setText(vMessage.toString()); } else { messageWidget->setText(Message); } QVariant vEnableDisable(EnableDisable); vEnableDisable = psiOptions->getPluginOption(constEnableDisable); if(!vEnableDisable.isNull()) { enabledisableWidget->setCurrentIndex(vEnableDisable.toInt()); } else { enabledisableWidget->setCurrentIndex(EnableDisable); } if(EnableDisable) { QVariant vDisableFor(DisableFor); vDisableFor = psiOptions->getPluginOption(constDisableFor); if(!vDisableFor.isNull()) { disableforWidget->setText(vDisableFor.toString()); } else { disableforWidget->setText(DisableFor); } } else { QVariant vDisableFor(DisableFor); vDisableFor = psiOptions->getPluginOption(constEnableFor); if(!vDisableFor.isNull()) { disableforWidget->setText(vDisableFor.toString()); } else { disableforWidget->setText(""); } } QVariant vTimes(Times); vTimes = psiOptions->getPluginOption(constTimes); if (!vTimes.isNull()) { spinWidget->setValue(vTimes.toInt()); } else { spinWidget->setValue(Times); } QVariant vActiveTabIsEnable(ActiveTabIsEnable); vActiveTabIsEnable = psiOptions->getPluginOption(constActiveTab); if(!vActiveTabIsEnable.isNull()) { activetabWidget->setChecked(vActiveTabIsEnable.toBool()); } else { activetabWidget->setChecked(ActiveTabIsEnable); } QVariant vResetTime(ResetTime); vResetTime = psiOptions->getPluginOption(constResetTime); if (!vResetTime.isNull()) { resetWidget->setValue(vResetTime.toInt()); } else { resetWidget->setValue(ResetTime); } QVariant vDisableForAcc(DisableForAcc); vDisableForAcc = psiOptions->getPluginOption(constDisableForAcc); if (!vDisableForAcc.isNull()) { DisableForAccWidget->setText(vDisableForAcc.toString()); } else { DisableForAccWidget->setText(DisableForAcc); } QVariant vSOnline(SOnline); vSOnline = psiOptions->getPluginOption(constSOnline); if(!vSOnline.isNull()) { sonlineWidget->setChecked(vSOnline.toBool()); } else { sonlineWidget->setChecked(SOnline); } QVariant vSAway(SAway); vSAway = psiOptions->getPluginOption(constSAway); if(!vSAway.isNull()) { sawayWidget->setChecked(vSAway.toBool()); } else { sawayWidget->setChecked(SAway); } QVariant vSDnd(SDnd); vSDnd = psiOptions->getPluginOption(constSDnd); if(!vSDnd.isNull()) { sdndWidget->setChecked(vSDnd.toBool()); } else { sdndWidget->setChecked(SDnd); } QVariant vSXa(SXa); vSXa = psiOptions->getPluginOption(constSXa); if(!vSXa.isNull()) { sxaWidget->setChecked(vSXa.toBool()); } else { sxaWidget->setChecked(SXa); } QVariant vSChat(SChat); vSChat = psiOptions->getPluginOption(constSChat); if(!vSChat.isNull()) { schatWidget->setChecked(vSChat.toBool()); } else { schatWidget->setChecked(SChat); } QVariant vSInvis(SInvis); vSInvis = psiOptions->getPluginOption(constSInvis); if(!vSInvis.isNull()) { sinvisWidget->setChecked(vSInvis.toBool()); } else { sinvisWidget->setChecked(SInvis); } QVariant vNotInRoster(NotInRoster); vNotInRoster = psiOptions->getPluginOption(constNotInRoster); if(!vNotInRoster.isNull()) { NotInRosterWidget->setChecked(vNotInRoster.toBool()); } else { NotInRosterWidget->setChecked(NotInRoster); } } QWidget* AutoReply::options() { if (!enabled) { return 0; } QWidget *optionsWid = new QWidget(); messageWidget = new QTextEdit(); messageWidget->setMaximumHeight(60); messageWidget->setText(Message); disableforWidget = new QTextEdit(); disableforWidget->setText(DisableFor); enabledisableWidget = new QComboBox(); enabledisableWidget->addItem(tr("Enable")); enabledisableWidget->addItem(tr("Disable")); enabledisableWidget->setCurrentIndex(EnableDisable); DisableForAccWidget = new QTextEdit(); DisableForAccWidget->setText(DisableForAcc); spinWidget = new QSpinBox(); spinWidget->setMinimum(-1); spinWidget->setValue(Times); resetWidget = new QSpinBox(); resetWidget->setMaximum(2000); resetWidget->setMinimum(1); resetWidget->setValue(ResetTime); activetabWidget = new QCheckBox(tr("Disable if chat window is active")); activetabWidget->setChecked(ActiveTabIsEnable); NotInRosterWidget = new QCheckBox(tr("Disable if contact isn't from your roster")); NotInRosterWidget->setChecked(NotInRoster); sonlineWidget = new QCheckBox(tr("Online")); sonlineWidget->setChecked(SOnline); sawayWidget = new QCheckBox(tr("Away")); sawayWidget->setChecked(SAway); sdndWidget = new QCheckBox(tr("Dnd")); sdndWidget->setChecked(SDnd); sxaWidget = new QCheckBox(tr("XA")); sxaWidget->setChecked(SXa); schatWidget = new QCheckBox(tr("Chat")); schatWidget->setChecked(SChat); sinvisWidget = new QCheckBox(tr("Invisible")); sinvisWidget->setChecked(SInvis); QGroupBox *groupBox = new QGroupBox(tr("Enable if status is:")); QHBoxLayout *statusLayout = new QHBoxLayout; statusLayout->addWidget(sonlineWidget); if(psiOptions->getGlobalOption("options.ui.menu.status.chat").toBool()) { statusLayout->addWidget(schatWidget); } statusLayout->addWidget(sawayWidget); statusLayout->addWidget(sdndWidget); if(psiOptions->getGlobalOption("options.ui.menu.status.xa").toBool()) { statusLayout->addWidget(sxaWidget); } if(psiOptions->getGlobalOption("options.ui.menu.status.invisible").toBool()) { statusLayout->addWidget(sinvisWidget); } statusLayout->addStretch(); groupBox->setLayout(statusLayout); QVBoxLayout *Layout = new QVBoxLayout; Layout->addWidget(new QLabel(tr("Auto Reply Message:"))); Layout->addWidget(messageWidget); QVBoxLayout *disableLayout = new QVBoxLayout; QHBoxLayout *EnDis = new QHBoxLayout; EnDis->addWidget(enabledisableWidget); EnDis->addWidget(new QLabel(tr("for JIDs and conferences:"))); QLabel *Label = new QLabel(tr("You can also specify a part of JID\n(without any additional symbols)")); QFont font; font.setPointSize(8); Label->setFont(font); disableLayout->addLayout(EnDis); disableLayout->addWidget(disableforWidget); disableLayout->addWidget(Label); QVBoxLayout *AccLayout = new QVBoxLayout; AccLayout->addWidget(new QLabel(tr("Disable for your accounts (specify your JIDs):"))); AccLayout->addWidget(DisableForAccWidget); QHBoxLayout *resetLayout = new QHBoxLayout; resetLayout->addWidget(new QLabel(tr("Timeout to reset counter:"))); resetLayout->addWidget(resetWidget); resetLayout->addWidget(new QLabel(tr("min."))); resetLayout->addStretch(); QHBoxLayout *timesLayout = new QHBoxLayout; timesLayout->addWidget(new QLabel(tr("Send maximum"))); timesLayout->addWidget(spinWidget); timesLayout->addWidget(new QLabel(tr("times (-1=infinite)"))); timesLayout->addStretch(); QVBoxLayout *flags = new QVBoxLayout; flags->addLayout(AccLayout); flags->addStretch(); flags->addLayout(timesLayout); flags->addLayout(resetLayout); flags->addWidget(activetabWidget); flags->addWidget(NotInRosterWidget); QHBoxLayout *hLayout = new QHBoxLayout; hLayout->addLayout(disableLayout); QFrame *frame = new QFrame(); frame->setMinimumWidth(8); hLayout->addWidget(frame); hLayout->addLayout(flags); QLabel *wikiLink = new QLabel(tr("Wiki (Online)")); wikiLink->setOpenExternalLinks(true); QVBoxLayout *tab1Layout = new QVBoxLayout(optionsWid); tab1Layout->addLayout(Layout); tab1Layout->addStretch(); tab1Layout->addLayout(hLayout); tab1Layout->addWidget(groupBox); tab1Layout->addWidget(wikiLink); connect(enabledisableWidget, SIGNAL(currentIndexChanged(int)), SLOT(setEnableDisableText(int))); return optionsWid; } void AutoReply::setOptionAccessingHost(OptionAccessingHost* host) { psiOptions = host; } void AutoReply::optionChanged(const QString& option) { Q_UNUSED(option); } void AutoReply::setStanzaSendingHost(StanzaSendingHost *host) { StanzaHost = host; } bool AutoReply::incomingStanza(int account, const QDomElement& stanza) { if (enabled) { if (stanza.tagName() == "message") { QString Status = AccInfoHost->getStatus(account); bool state = false; if(Status == "online" && SOnline) { state = true; } else { if(Status == "away" && SAway) { state = true; } else { if(Status == "chat" && SChat) { state = true; } else { if(Status == "xa" && SXa) { state = true; } else { if(Status == "dnd" && SDnd) { state = true; } else { if(Status == "invisible" && SInvis) { state = true; } } } } } } if(!state) return false; QStringList Disable = DisableForAcc.split(QRegExp("\\s+"), QString::SkipEmptyParts); QString AccJid = AccInfoHost->getJid(account); while(!Disable.isEmpty()) { if(AccJid == Disable.takeFirst()) return false; } QString type = ""; type = stanza.attribute("type"); if(type == "groupchat" || type == "error" || type == "normal") return false; QDomElement Body = stanza.firstChildElement("body"); if(Body.isNull()) return false; if(Body.text() == Message) return false; QDomElement rec = stanza.firstChildElement("received"); if(!rec.isNull()) return false; QDomElement subj = stanza.firstChildElement("subject"); if (subj.text() == "AutoReply" || subj.text() == "StopSpam" || subj.text() == "StopSpam Question") return false; QString from = stanza.attribute("from"); QString to = stanza.attribute("to"); QString valF = from.split("/").takeFirst(); QString valT = to.split("/").takeFirst(); if(valF.toLower() == valT.toLower()) return false; if(!from.contains("@")) return false; Disable = DisableFor.split(QRegExp("\\s+"), QString::SkipEmptyParts); if(EnableDisable) { while(!Disable.isEmpty()) { QString J = Disable.takeFirst(); if(J.toLower() == valF.toLower() || from.contains(J, Qt::CaseInsensitive)) { return false; } } } else { bool b = false; while(!Disable.isEmpty()) { QString J = Disable.takeFirst(); if(J.toLower() == valF.toLower() || from.contains(J, Qt::CaseInsensitive)) { b = true; } } if(!b) { return false; } } if(ActiveTabIsEnable) { QString getJid = ActiveTabHost->getJid(); if(getJid.toLower() == from.toLower()) return false; } if(NotInRoster) { QStringList Roster = AccInfoHost->getRoster(account); if(!Roster.contains(valF, Qt::CaseInsensitive)) return false; } if(Times == 0) return false; if(Times != -1) { int i = Counter.size(); if(FindAcc(account, from, i)) { Base &B = Counter[i]; if(B.count >= Times) { if(QDateTime::currentDateTime().secsTo(B.LastMes) >= -ResetTime*60) { return false; } else { B.count = 1; B.LastMes = QDateTime::currentDateTime(); } } else { B.count++; B.LastMes = QDateTime::currentDateTime(); } } else { Base B = {account, from, 1, QDateTime::currentDateTime() }; Counter << B; } } QString mes = "escape(type) + "'"; } else { mes += ">AutoReplyescape(Message) + ""; StanzaHost->sendStanza(account, mes); } } return false; } bool AutoReply::outgoingStanza(int /*account*/, QDomElement& /*stanza*/) { return false; } bool AutoReply::FindAcc(int account, QString jid, int &i) { for(; i > 0;) { Base B = Counter[--i]; if(B.Account == account && B.Jid == jid) { return true; } } return false; } void AutoReply::setActiveTabAccessingHost(ActiveTabAccessingHost* host) { ActiveTabHost = host; } void AutoReply::setAccountInfoAccessingHost(AccountInfoAccessingHost* host) { AccInfoHost = host; } void AutoReply::setEnableDisableText(int Arg) { if(Arg) { QVariant vDisableFor(DisableFor); vDisableFor = psiOptions->getPluginOption(constDisableFor); if(!vDisableFor.isNull()) { disableforWidget->setText(vDisableFor.toString()); } else { disableforWidget->setText(DisableFor); } } else { QVariant vDisableFor(DisableFor); vDisableFor = psiOptions->getPluginOption(constEnableFor); if(!vDisableFor.isNull()) { disableforWidget->setText(vDisableFor.toString()); } else { disableforWidget->setText(""); } } } QString AutoReply::pluginInfo() { return tr("Author: ") + "Dealer_WeARE\n" + tr("Email: ") + "wadealer@gmail.com\n\n" + trUtf8("This plugin acts as an auto-answering machine. It has a number of simple configuration options, which you can use to:\n" "* set a text message for auto-answer\n" "* exclude specified jids, including conferences, from the objects for auto-answer (if a jid conference is set, the exception will include all private messages)\n" "* disable the auto-responder for some of your accounts\n" "* set the number of sent auto messages\n" "* set the time interval after which the number of auto messages counter will be reset\n" "* disable the auto-responder for the active tab\n" "* disable the auto-responder for contacts that are not in your roster\n" "The list of exceptions for jids has two operating modes:\n" "* auto-responder is switched off for the list of exceptions, for the others is switched on (Disable mode)\n" "* auto-responder is switched on for the list of exceptions, for the others is switched off (Enable mode) "); } QPixmap AutoReply::icon() const { return QPixmap(":/icons/autoreply.png"); } #include "autoreplyplugin.moc" plugins-1.5/generic/autoreplyplugin/autoreplyplugin.pro000066400000000000000000000002441336777360500237250ustar00rootroot00000000000000isEmpty(PSISDK) { include(../../psiplugin.pri) } else { include($$PSISDK/plugins/psiplugin.pri) } SOURCES += autoreplyplugin.cpp RESOURCES += resources.qrc plugins-1.5/generic/autoreplyplugin/changelog.txt000066400000000000000000000162301336777360500224320ustar00rootroot000000000000002013-08-13 v0.3.2 - taurus + Иконка плагина 2010-09-11 v0.3.0 + добавлены в исключения некоторые боты (rss@isida-bot.com, huti.ua@gmail.com) * обновлена ссылка на wiki ( http://psi-plus.com/wiki/plugins#autoreply_plugin ) 2010-05-17 v0.2.9 + добавлена информация о плагине 2010-05-04 v0.2.8 * исправлена ссылка на wiki 2010-03-24 v0.2.7 * исправлено отключение Psi+ от сервера при попытке плагином послать сообщение, содержащее некоторые спецсимволы 2010-02-19 v0.2.6 + в исключения по умолчанию добавлен twitter.tweet.im * исправлен перевод сообщения по-умолчанию 2009-12-25 v0.2.5 * some fixes and optimizations 2009-12-08 v0.2.4 + в настройках плагина добавлена ссылка на wiki 2009-11-17 v0.2.3 * fixes 2009-11-11 v0.2.2 * теперь есть возможность задать два независимых списка для двух режимов работы автоответчика (Enable/Disable). таким образом, можно быстро переключаться между этими режимами без необходимости постоянно редактировать списки исключений ВНИМАНИЕ! Если вы уже пользовались этим плагином и у вас включен режим Enabled, то вам необходимо заново настроить список исключений (точнее, просто переключитесь в режим Disabled и скопируйте его оттуда) 2009-10-28 v0.2.1 + добавлена возможность отключить автоответчик для контактов, которых нет в вашем ростере * улучшена совместимость с плагином Stop Spam * различные исправления 2009-10-26 v0.2.0 + теперь на чат-сообщения плагин отвечает без темы + исключено срабатывание на сообщения от транспортов (контакты, не имеющие значка " @ " в jid) + добавлена возможность отключать автоответчик поаккаунтно(в списке исключения необходимо указать jid нужного аккаунта) * в исключения по умолчанию добавлено несколько распространённых ботов + добавлена возможность выбрать статусы, для которых будет работать автоответчик * в окне настроек появляются только те статусы, которые включены в глобальных опциях 2009-10-23 v0.1.3 * добавлена совместимость с новым патчем 580-psi-get-account-info-from-plugins.diff * улучшена совместимость с GMail (более корректная обработка оффлайн-сообщений) 2009-10-21 v0.1.2 + добавлена поддержка сервера Gmail и других серверов, основанных не на ejabberd2 2009-10-20 v0.1.1 + в исключения по умолчанию добавлен бот jabrss@cmeerw.net + добавлена возможность изменить действие списка исключений. Доступны два режима: автоответчик выключен для списка исключения, для остальных включен (Disable); автоответчик включен для списка исключений, для остальных выключен (Enable). * минимальное значение интервала времени для сброса счетчика теперь 1 минута (было 0) 2009-10-19 v0.1.0 + добавлена опция для выбора интервала времени (в минутах), после которого будет сброшен счётчик количества автоответов для данного контакта + в списке исключений можно указать часть JID'а (без символов " * " или " ? "). если указать ник, то в конференциях приваты от этого пользователя тоже будут в исключениях * редизайнинг опций 2009-10-19 v0.0.9 + в настройки плагина по умолчанию добавлен бот jubo@nologin.ru (примечание: обратите внимание на то, что настройки по умолчанию предполагают, что вы используете плагин впервые. если вы пользовались предыдущими версиями - будут использованы ваши настройки!) * исправлено ошибочное срабатываение плагина на событие типа "печатает" (composing events) и на приглашения (invite) в конференцию + теперь плагин на чаты отвечает чатами, а на сообщения - сообщениями 2009-10-16 v0.0.8 * исправлены некоторые проблемы с опциями 2009-10-15 v0.0.7 + в настройки плагина по умолчанию добавлены juick и конференция psi-dev (Примечание: не забудьте добавить в исключения других ботов!) + добавлена возможность отключения автоответчика для активной закладки * уменьшена вероятность ложных срабатываний 2009-10-13 v0.0.6 + добавлена возможность задавать количество посылок автоответов ПРИМЕЧАНИЕ: в текущей реализации не поддерживается работа с сервером GMail. это происходит из-за того, что статус аккаунта плагин определяет по приходящим ему от сервера презенсам. А GMail(и, возможно, другие серверы, построенные не на ejabberd2) не шлют этого презенса 2009-10-12 v0.0.3 + добавлена поддержка списка исключений. если в список добавить jid конференции, то все приватные сообщения от пользователей конференции также окажутся в списке исключений 2009-10-12 v0.0.1 ! initial версия plugins-1.5/generic/autoreplyplugin/resources.qrc000066400000000000000000000001411336777360500224550ustar00rootroot00000000000000 autoreply.png plugins-1.5/generic/birthdayreminderplugin/000077500000000000000000000000001336777360500212505ustar00rootroot00000000000000plugins-1.5/generic/birthdayreminderplugin/CMakeLists.txt000066400000000000000000000025051336777360500240120ustar00rootroot00000000000000unset(_HDRS) unset(_UIS) unset(_SRCS) unset(_RSCS) unset(PLUGIN) set( PLUGIN birthdayreminderplugin ) project(${PLUGIN}) cmake_minimum_required(VERSION 3.1.0) set( CMAKE_AUTOMOC TRUE ) IF( NOT WIN32 ) set( LIB_SUFFIX "" CACHE STRING "Define suffix of directory name (32/64)" ) set( PLUGINS_PATH "lib${LIB_SUFFIX}/psi-plus/plugins" CACHE STRING "Install suffix for plugins" ) ELSE() set( PLUGINS_PATH "psi-plus/plugins" CACHE STRING "Install suffix for plugins" ) ENDIF() add_definitions( -DQT_PLUGIN -DHAVE_QT5 ) set( _SRCS ${PLUGIN}.cpp ) set( _UIS options.ui ) set( _RSCS ${PLUGIN}.qrc ) include_directories( ${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ../../include . ) find_package( Qt5 COMPONENTS Widgets Xml REQUIRED ) set(QT_DEPLIBS Qt5::Widgets Qt5::Xml ) qt5_wrap_ui(UIS ${_UIS}) qt5_add_resources(RSCS ${_RSCS}) add_library( ${PLUGIN} MODULE ${_SRCS} ${UIS} ${RSCS} ) target_link_libraries( ${PLUGIN} ${QT_DEPLIBS} ) if( UNIX AND NOT( APPLE OR CYGWIN ) ) install( TARGETS ${PLUGIN} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} ) endif() if( WIN32 ) install( TARGETS ${PLUGIN} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} ) endif() plugins-1.5/generic/birthdayreminderplugin/birthday.png000066400000000000000000000015441336777360500235700ustar00rootroot00000000000000PNG  IHDRabKGDԂ pHYsHHFk> vpAg\ƭIDAT8˅MHQ;Ԍ6bEcF ԪVѪvAD jFIMMADD(%TF393||?I:ޗ{KThޜ[-W-S*^{tEVW(=x#A >5V{_纵kW\_.r7:,:, R*{{_eS*h Gjڄakhi{X_/()ßͰ23-ҟ?moZ_?|[7mWz)JDQ*A/@Ci3?|8Q [|4 }PQdtzYiT[46\^.ؖ9~=H!@h #include #include "psiplugin.h" #include "stanzafilter.h" #include "accountinfoaccessor.h" #include "accountinfoaccessinghost.h" #include "applicationinfoaccessor.h" #include "applicationinfoaccessinghost.h" #include "stanzasender.h" #include "stanzasendinghost.h" #include "optionaccessor.h" #include "optionaccessinghost.h" #include "popupaccessor.h" #include "popupaccessinghost.h" #include "iconfactoryaccessinghost.h" #include "iconfactoryaccessor.h" #include "plugininfoprovider.h" #include "soundaccessinghost.h" #include "soundaccessor.h" #include "contactinfoaccessor.h" #include "contactinfoaccessinghost.h" #include "ui_options.h" #define cVer "0.4.1" #define constLastCheck "lstchck" #define constDays "days" #define constInterval "intrvl" #define constTimeout "timeout" #define constStartCheck "strtchck" #define constCheckFromRoster "chckfrmrstr" #define constLastUpdate "lstupdate" #define constUpdateInterval "updtintvl" #define constSoundFile "sndfl" #define POPUP_OPTION_NAME "Birthday Reminder Plugin" static const QString id = "bdreminder_1"; static const QString dirName = "Birthdays"; class Reminder : public QObject, public PsiPlugin, public StanzaFilter, public AccountInfoAccessor, public ApplicationInfoAccessor, public StanzaSender, public OptionAccessor, public PopupAccessor, public IconFactoryAccessor, public PluginInfoProvider, public SoundAccessor, public ContactInfoAccessor { Q_OBJECT #ifdef HAVE_QT5 Q_PLUGIN_METADATA(IID "com.psi-plus.Reminder") #endif Q_INTERFACES(PsiPlugin StanzaFilter AccountInfoAccessor ApplicationInfoAccessor StanzaSender OptionAccessor PopupAccessor IconFactoryAccessor PluginInfoProvider SoundAccessor ContactInfoAccessor) public: Reminder(); virtual QString name() const; virtual QString shortName() const; virtual QString version() const; virtual QWidget* options(); virtual bool enable(); virtual bool disable(); virtual void applyOptions(); virtual void restoreOptions(); virtual bool incomingStanza(int account, const QDomElement& xml); virtual bool outgoingStanza(int account, QDomElement& xml); virtual void setAccountInfoAccessingHost(AccountInfoAccessingHost* host); virtual void setApplicationInfoAccessingHost(ApplicationInfoAccessingHost* host); virtual void setStanzaSendingHost(StanzaSendingHost *host); virtual void setOptionAccessingHost(OptionAccessingHost* host); virtual void optionChanged(const QString& ){} virtual void setPopupAccessingHost(PopupAccessingHost* host); virtual void setIconFactoryAccessingHost(IconFactoryAccessingHost* host); virtual void setSoundAccessingHost(SoundAccessingHost* host); virtual void setContactInfoAccessingHost(ContactInfoAccessingHost *host); virtual QString pluginInfo(); virtual QPixmap icon() const; private: QString checkBirthdays(); QString bdaysDir() const; private slots: void updateVCard(); bool check(); void clearCache(); void getSound(); void checkSound(); void playSound(const QString&); void timeoutStopUpdate(); private: bool enabled; OptionAccessingHost *psiOptions; AccountInfoAccessingHost *accInfoHost; ApplicationInfoAccessingHost *appInfoHost; StanzaSendingHost *stanzaHost; PopupAccessingHost* popup; IconFactoryAccessingHost* icoHost; SoundAccessingHost* sound_; ContactInfoAccessingHost* contactInfo; QString lastCheck; int days_; int interval; //int timeout; bool startCheck; bool checkFromRoster; QString lastUpdate; int updateInterval; QString soundFile; bool updateInProgress; int popupId; QPointer options_; Ui::Options ui_; }; #ifndef HAVE_QT5 Q_EXPORT_PLUGIN(Reminder) #endif Reminder::Reminder() : enabled(false) , psiOptions(0) , accInfoHost(0) , appInfoHost(0) , stanzaHost(0) , popup(0) , icoHost(0) , lastCheck("1901010101") , days_(5) , interval(24) //, timeout(15) , startCheck(true) , checkFromRoster(true) , lastUpdate("19010101") , updateInterval(30) , soundFile("sound/reminder.wav") , updateInProgress(false) , popupId(0) { } QString Reminder::name() const { return "Birthday Reminder Plugin"; } QString Reminder::shortName() const { return "reminder"; } QString Reminder::version() const { return cVer; } bool Reminder::enable() { if(!psiOptions) return enabled; QFile file(":/reminder/birthday.png"); if ( file.open(QIODevice::ReadOnly) ) { QByteArray image = file.readAll(); icoHost->addIcon("reminder/birthdayicon",image); file.close(); } else { return enabled; } enabled = true; lastCheck = psiOptions->getPluginOption(constLastCheck, lastCheck).toString(); days_ = psiOptions->getPluginOption(constDays, days_).toInt(); interval = psiOptions->getPluginOption(constInterval, interval).toInt(); startCheck = psiOptions->getPluginOption(constStartCheck, startCheck).toBool(); checkFromRoster = psiOptions->getPluginOption(constCheckFromRoster, checkFromRoster).toBool(); updateInterval = psiOptions->getPluginOption(constUpdateInterval, updateInterval).toInt(); lastUpdate = psiOptions->getPluginOption(constLastUpdate, lastUpdate).toString(); soundFile = psiOptions->getPluginOption(constSoundFile, QVariant(soundFile)).toString(); int timeout = psiOptions->getPluginOption(constTimeout, QVariant(15000)).toInt()/1000; popupId = popup->registerOption(POPUP_OPTION_NAME, timeout, "plugins.options."+shortName()+"."+constTimeout); QDir dir(bdaysDir()); if(!dir.exists()) { dir.cdUp(); dir.mkdir(dirName); return enabled; } if(startCheck) { lastCheck = QDateTime::currentDateTime().toString("yyyyMMddhh"); psiOptions->setPluginOption(constLastCheck, QVariant(lastCheck)); QTimer::singleShot(4000, this, SLOT(check())); //необходимо для инициализации приложения } return enabled; } bool Reminder::disable() { enabled = false; popup->unregisterOption(POPUP_OPTION_NAME); return true; } QString Reminder::bdaysDir() const { static QString dir(appInfoHost->appVCardDir() + QDir::separator() + dirName); return dir; } QWidget* Reminder::options() { if(!enabled) return 0; options_ = new QWidget(); ui_.setupUi(options_); ui_.tb_get->setIcon(icoHost->getIcon("psi/browse")); ui_.tb_check->setIcon(icoHost->getIcon("psi/play")); connect(ui_.pb_update, SIGNAL(clicked()), SLOT(updateVCard())); connect(ui_.pb_check, SIGNAL(clicked()), SLOT(check())); connect(ui_.pb_clear_cache, SIGNAL(clicked()), SLOT(clearCache())); connect(ui_.tb_check, SIGNAL(clicked()), SLOT(checkSound())); connect(ui_.tb_get, SIGNAL(clicked()), SLOT(getSound())); restoreOptions(); return options_; } bool Reminder::incomingStanza(int account, const QDomElement& stanza) { if (enabled) { if(stanza.tagName() == "iq" && stanza.attribute("id") == id) { QDomNode VCard = stanza.firstChild(); QDomElement BDay = VCard.firstChildElement("BDAY"); if(!BDay.isNull()) { QString Jid = stanza.attribute("from"); QString Nick = contactInfo->name(account, Jid); if(Nick == Jid) Nick = VCard.firstChildElement("NICKNAME").text(); QString Date = BDay.text(); if(!Date.isEmpty()) { Jid.replace("@", "_at_"); QFile file(bdaysDir() + QDir::separator() + Jid); if(file.open(QIODevice::WriteOnly | QIODevice::Truncate)) { QTextStream out(&file); out.setCodec("UTF-8"); out.setGenerateByteOrderMark(false); out << Date << "__" << Nick << endl; } } } return true; } if(stanza.tagName() == "presence") { QDateTime cur = QDateTime::currentDateTime(); if((lastCheck.toLong() + interval) <= cur.toString("yyyyMMddhh").toLong()) { lastCheck = QDateTime::currentDateTime().toString("yyyyMMddhh"); psiOptions->setPluginOption(constLastCheck, QVariant(lastCheck)); check(); } if(updateInterval) { if((lastUpdate.toLong() + updateInterval) <= cur.toString("yyyyMMdd").toLong()) { lastUpdate = QDateTime::currentDateTime().toString("yyyyMMdd"); psiOptions->setPluginOption(constLastUpdate, QVariant(lastUpdate)); updateVCard(); } } } } return false; } bool Reminder::outgoingStanza(int /*account*/, QDomElement& /*xml*/) { return false; } void Reminder::setAccountInfoAccessingHost(AccountInfoAccessingHost* host) { accInfoHost = host; } void Reminder::setApplicationInfoAccessingHost(ApplicationInfoAccessingHost* host) { appInfoHost = host; } void Reminder::applyOptions() { if(!options_) return; days_ = ui_.sb_start->value(); psiOptions->setPluginOption(constDays, QVariant(days_)); interval = ui_.sb_check_interval->value(); psiOptions->setPluginOption(constInterval, QVariant(interval)); startCheck = ui_.cb_startupcheck->isChecked(); psiOptions->setPluginOption(constStartCheck, QVariant(startCheck)); checkFromRoster = ui_.cb_active_accounts->isChecked(); psiOptions->setPluginOption(constCheckFromRoster, QVariant(checkFromRoster)); updateInterval = ui_.sb_update_interval->value(); psiOptions->setPluginOption(constUpdateInterval, QVariant(updateInterval)); soundFile = ui_.le_sound->text(); psiOptions->setPluginOption(constSoundFile, QVariant(soundFile)); } void Reminder::restoreOptions() { if(!options_) return; ui_.sb_start->setValue(days_); ui_.sb_check_interval->setValue(interval); ui_.cb_startupcheck->setChecked(startCheck); ui_.cb_active_accounts->setChecked(checkFromRoster); ui_.sb_update_interval->setValue(updateInterval); ui_.le_sound->setText(soundFile); } void Reminder::setStanzaSendingHost(StanzaSendingHost *host) { stanzaHost = host; } void Reminder::updateVCard() { if(enabled && !updateInProgress) { updateInProgress = true; const QString path = appInfoHost->appVCardDir(); QDir dir(path); foreach (QString filename, dir.entryList(QDir::Files)) { QFile file(path + QDir::separator() + filename); if(file.open(QIODevice::ReadOnly)) { QTextStream in(&file); in.setCodec("UTF-8"); QDomDocument doc; doc.setContent(in.readAll()); QDomElement vCard = doc.documentElement(); QDomElement BDay = vCard.firstChildElement("BDAY"); if(!BDay.isNull()) { QString Nick = vCard.firstChildElement("NICKNAME").text(); QString Date = BDay.text(); if(!Date.isEmpty()) { filename.replace("%5f", "_"); filename.replace("%2d", "-"); filename.replace("%25", "%"); filename.remove(".xml"); QFile file(bdaysDir() + QDir::separator() + filename); if(file.open(QIODevice::WriteOnly | QIODevice::Truncate)) { QTextStream out(&file); out.setCodec("UTF-8"); out.setGenerateByteOrderMark(false); out << Date << "__" << Nick << endl; } } } } } int accs = -1; while(1) { QStringList Jids = accInfoHost->getRoster(++accs); if(!Jids.isEmpty()) { if(Jids.first() == "-1") { break; } else if(accInfoHost->getStatus(accs) != "offline") { QString text = "" ""; foreach(const QString& Jid, Jids) { stanzaHost->sendStanza(accs, text.arg(Jid, id)); } } } } QTimer::singleShot(30000, this, SLOT(timeoutStopUpdate())); //30 секунд дольжно хватить, чтобы получить все vCard'ы } } void Reminder::timeoutStopUpdate() { updateInProgress = false; } QString Reminder::checkBirthdays() { if(!enabled) return QString(); QSet Roster_; if(checkFromRoster) { int accs = -1; while(1) { QStringList Jids = accInfoHost->getRoster(++accs); if(!Jids.isEmpty()) { if(Jids.first() == "-1") { break; } else { Roster_ += Jids.toSet(); } } } } QString CheckResult; foreach(QString jid, QDir(bdaysDir()).entryList(QDir::Files)) { if(jid.contains("_at_")) { QFile file(bdaysDir() + QDir::separator() + jid); if(file.open(QIODevice::ReadOnly)) { QTextStream in(&file); in.setCodec("UTF-8"); QString line = in.readLine(); QStringList fields = line.split("__"); QString Date = fields.takeFirst(); QString Nick = ""; if(!fields.isEmpty()) { Nick = fields.takeFirst(); } QDate Birthday = QDate::currentDate(); if(Date.contains("-")) { Birthday = QDate::fromString(Date, "yyyy-MM-dd"); } else if(Date.contains(".")) { Birthday = QDate::fromString(Date, "d.MM.yyyy"); } else if(Date.contains("/")) { Birthday = QDate::fromString(Date, "d/MM/yyyy"); } QDate current = QDate::currentDate(); if(current != Birthday) { int years = current.year() - Birthday.year(); Birthday = Birthday.addYears(years); int daysTo = current.daysTo(Birthday); QString days; days.setNum(daysTo); jid.replace("_at_", "@"); if(!checkFromRoster || Roster_.contains(jid)) { if(daysTo == 0) { CheckResult += Nick + " (" + jid + ") " + tr("celebrates birthday today!""\n"); } else if(daysTo <= days_ && daysTo > 0) { CheckResult += Nick + " (" + jid + ") " + tr("celebrates birthday in %n day(s)\n", "", daysTo); } else if(daysTo == -1) { CheckResult += Nick + " (" + jid + ") " + tr("celebrates birthday yesterday.\n"); } } } } } } return CheckResult; } void Reminder::setOptionAccessingHost(OptionAccessingHost *host) { psiOptions = host; } void Reminder::setIconFactoryAccessingHost(IconFactoryAccessingHost* host) { icoHost = host; } void Reminder::setSoundAccessingHost(SoundAccessingHost *host) { sound_ = host; } void Reminder::setContactInfoAccessingHost(ContactInfoAccessingHost *host) { contactInfo = host; } bool Reminder::check() { QString text = checkBirthdays(); if(text.isEmpty()) return false; text.chop(1); if(psiOptions->getGlobalOption("options.ui.notifications.sounds.enable").toBool()) playSound(soundFile); text = text.replace("\n", "
"); popup->initPopup(text, tr("Birthday Reminder"), "reminder/birthdayicon", popupId); return true; } void Reminder::clearCache() { QDir dir(bdaysDir()); foreach(const QString& file, dir.entryList(QDir::Files)) { QFile File(bdaysDir() + QDir::separator() + file); if(File.open(QIODevice::ReadWrite)) { File.remove(); } } lastUpdate = "19010101"; psiOptions->setPluginOption(constLastUpdate, QVariant(lastUpdate)); } void Reminder::setPopupAccessingHost(PopupAccessingHost* host) { popup = host; } void Reminder::playSound(const QString& f) { sound_->playSound(f); } void Reminder::getSound() { QString fileName = QFileDialog::getOpenFileName(0,tr("Choose a sound file"),"", tr("Sound (*.wav)")); if(fileName.isEmpty()) return; ui_.le_sound->setText(fileName); } void Reminder::checkSound() { playSound(ui_.le_sound->text()); } QString Reminder::pluginInfo() { return tr("Author: ") + "Dealer_WeARE\n" + tr("Email: ") + "wadealer@gmail.com\n\n" + trUtf8("This plugin is designed to show reminders of upcoming birthdays.\n" "The first time you install this plugin, you need to log on to all of your accounts, go to the plugin settings and click \"Update Birthdays\"." "The plugin will then collect the information about the birthdays of all the users in your roster, but when the 'Use vCards cache' option is" "selected, the users' vCards that are cached on your hard disk will be used. "); } QPixmap Reminder::icon() const { return QPixmap(":/reminder/birthday.png"); } #include "birthdayreminderplugin.moc" plugins-1.5/generic/birthdayreminderplugin/birthdayreminderplugin.pro000066400000000000000000000003131336777360500265420ustar00rootroot00000000000000isEmpty(PSISDK) { include(../../psiplugin.pri) } else { include($$PSISDK/plugins/psiplugin.pri) } RESOURCES = birthdayreminderplugin.qrc SOURCES += birthdayreminderplugin.cpp FORMS += options.ui plugins-1.5/generic/birthdayreminderplugin/birthdayreminderplugin.qrc000066400000000000000000000001441336777360500265310ustar00rootroot00000000000000 birthday.png plugins-1.5/generic/birthdayreminderplugin/changelog.txt000066400000000000000000000243541336777360500237500ustar00rootroot000000000000002013-08-13 v0.4.1 - taurus + Иконка плагина 2012-04-17 v0.4.0 + теперь в качестве ника используется имя контакта ростера (если не задано - берется из vCard) * различные оптимизации кода 2011-02-20 v0.3.4 * исправления для обновленного попап-интерфейса 2011-02-08 v0.3.3 * опции переведены на ui * настройки всплывающих уведомлений перенесены в основные настройки приложения * для проигрывания звука используется новый интерфейс 2011-01-16 v0.3.2 * некоторые улучшения 2010-12-17 v0.3.1 * небольшие исправления 2010-11-10 v0.3.0 * переработаны опции, удалены избыточные опции - удалено оповещение с помощью диалога * большое количество различных исправлений и улучшений 2010-09-11 v0.2.6 * обновлена ссылка на wiki ( http://psi-plus.com/wiki/plugins#birthday_reminder_plugin ) 2010-05-22 v0.2.5 * исправлена опечатка в опциях плагина 2010-05-17 v0.2.4 + добавлена информация о плагине 2010-05-04 v0.2.3 * исправлена ссылка на wiki 2010-04-13 v0.2.2 + в настройки по умолчанию добавлен звуковой файл reminder.wav 2010-02-09 v0.2.1 * по-умолчанию отключено использование кэша сохранённых vCard 2010-01-26 v0.2.0 + добавлены иконки на некоторые кнопки в настройках плагина 2010-01-16 v0.1.9 * удалена лишняя пустая строка во всплывающем сообщении 2010-01-05 v0.1.8 + воспроизведение звука теперь зависит от глобальных настроек (глобальное отключение звука отключит звуковые уведомления в плагине) 2010-01-04 v0.1.7 + добавлена возможность задать звуковое оповещение(в настройках плагина необходимо выбрать звуковой файл) + добавлена собственная иконка во всплывающем окне * редизайнинг опций 2009-12-26 v0.1.6 + включение/выключение всплывающих окон больше не зависит от глобальных настроек 2009-12-25 v0.1.5 + добавлено уведомление с помощью всплывающих окон + в настройках можно выбрать, с помощью чего уведомлять - всплывающими окнами или информационным окном + в настройка можно задать время, в течение которого будет показываться всплывающее окно * исправлена ошибка, связанная с отключением автообновления информации 2009-12-24 v0.1.4 + добавлено автоматическое обновление информации о днях рождения для аккаунтов, находящихся в онлайн + добавлена возможность задать интервал автоматического обновления информации о днях рождения + после нажатия на кнопку очистки кэша информации о днях рождения плагин автоматически обновит информацию для аккаунтов, находящихся в онлайн 2009-12-23 v0.1.3 + добавлена возможность выбрать, использовать или нет кэш vCard'ов на диске при обновлении дней рождения + добавлена возможность очитить кэш дней рождения (после очистки не забудьте заново обновить информацию о днях рождения) 2009-12-08 v0.1.2 + в настройках плагина добавлена ссылка на wiki * добавлен пробел между ником и джидом в окне уведомления 2009-12-02 v0.1.1 * переименованы опции 2009-12-02 v0.1.0 + добавлена возможность включить напоминания только для контактов, находящихся в ростере активных аккаунтов ВНИМАНИЕ! Для правильной работы этой версии необходимо использовать Psi+ версии старше, чем r1415 2009-11-30 v0.0.9 + добавлена возможность отключить счётчик в окне уведомления + добавлена возможность отключить проверку дней рождения при старте приложения. проверка будет осуществляться при выходе в онлайн * исправлена ошибка, связанная с неверным отображением русских имён на ОС семейства Windows (необходимо обновить данные о днях рождения) * различные исправления кода 2009-11-18 v0.0.8 + добавлена возможность задать время, в течение которого будет показываться окно уведомления 2009-11-17 v0.0.7 * fixes 2009-11-13 v0.0.6 * отключено напоминаение о днях рождения сервисов и серверов 2009-11-11 v0.0.5 + в окне уведомления о днях рождения добавлена кнопка, отключающая проверку дней рождения в течение текущего дня 2009-11-10 v0.0.4 + добавлена возможность задать интервал между автоматическими проверками дней рождения + теперь проверка происходит не только при старте приложения, но и во время работы 2009-11-09 v0.0.3 + добавлена возможность задать, за сколько дней до дня рождения будут показываться уведомления 2009-11-05 v0.0.2 + в опциях плагина добавлена кнопка "Check Birthdays". прежде чем нажимать на неё, не забудьте обновить данные о днях рождения (в случае, если вы используете плагин впервые) * изменён способ уведомления. теперь появляющееся окошко не блокирует работу приложения 2009-11-04 v0.0.1 !Initial version Этот плагин предназначен для показа напоминаний о предстоящих днях рождения пользователей в вашем ростере. После первого запуска Вам необходимо выйти в онлайн всеми вашими аккаунтами, зайти в настройки данного плагина и нажать на большую кнопку "Update Birthdays". В результате будет собрана информация о днях рождения всех пользователей со всех аккаунтов (результат выполнения можно наблюдать, зайдя в PsiData\profiles\yourProfile\vcard\Birthdays). Сначала просматриваются сохранённые vCrad'ы, а затем запрашиваются vCard'ы у сервера. Учтите, что при большом количестве контактов в ростере данная операция займёт некоторое время (получение vCard'ов всех контактов). Далее, при каждом запуске Psi+ (но не чаще одного раза в день) будет происходить проверка дней рождений, и если у кого-то день рождения наступит в ближайшие 5 дней или уже состоялся вчера - то будет показано уведомление в виде MessageBox. Существующие трудности: ! Разные клиенты сохраняют дату в различном формате. В данный момент плагин умеет парсить все типы записей даты, которые обнаружились у контактов в ростере автора. Возможно, существуют другие формы записи даты, которые не будут распознаны, или будут распознаны неверно. В подобных случаях просьба сообщать об этом автору плагина в багтрекер проекта (http://code.google.com/p/psi-dev/issues/detail?id=176) с примером нераспознаваемого формата даты. ! Если вы используете транспорты, то нажав на кнопку "Update Birthdays" вы получите дни рождения только тех контактов, которые в данный момент находятся в онлайне (справедливо для PyICQt, возможно и для других транспортов тоже). Это проблемы реализации самого транспорта. plugins-1.5/generic/birthdayreminderplugin/options.ui000066400000000000000000000133571336777360500233130ustar00rootroot00000000000000 Options 0 0 528 312 Form If you use this plugin at first time, make sure that all your accounts is online and then press "Update Birthdays" button. It takes some time. Update Birthdays Clear Birthdays Cache Qt::Horizontal 40 20 Check Birthdays Start notifying 2 60 days in advance Check birthdays every 24 hours Update birthdays every days (0 - automatic update disabled) Qt::Horizontal 40 20 Remind for contacts from active accounts only Check birthdays on startup Play sound: Qt::Vertical 0 0 Qt::Vertical 0 0 <a href="http://psi-plus.com/wiki/plugins#birthday_reminder_plugin">Wiki (Online)</a> true plugins-1.5/generic/chessplugin/000077500000000000000000000000001336777360500170215ustar00rootroot00000000000000plugins-1.5/generic/chessplugin/CMakeLists.txt000066400000000000000000000030771336777360500215700ustar00rootroot00000000000000unset(_HDRS) unset(_UIS) unset(_SRCS) unset(_RSCS) unset(PLUGIN) set( PLUGIN chessplugin ) project(${PLUGIN}) cmake_minimum_required(VERSION 3.1.0) set( CMAKE_AUTOMOC TRUE ) IF( NOT WIN32 ) set( LIB_SUFFIX "" CACHE STRING "Define suffix of directory name (32/64)" ) set( PLUGINS_PATH "lib${LIB_SUFFIX}/psi-plus/plugins" CACHE STRING "Install suffix for plugins" ) ELSE() set( PLUGINS_PATH "psi-plus/plugins" CACHE STRING "Install suffix for plugins" ) ENDIF() add_definitions( -DQT_PLUGIN -DHAVE_QT5 ) include_directories( ${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ../../include . ) set ( _HDRS figure.h boardmodel.h mainwindow.h boardview.h boarddelegate.h invitedialog.h request.h ) set ( _SRCS ${PLUGIN}.cpp figure.cpp boardmodel.cpp mainwindow.cpp boardview.cpp boarddelegate.cpp invitedialog.cpp ) set ( _UIS mainwindow.ui options.ui invitedialog.ui invitationdialog.ui ) set ( _RSCS ${PLUGIN}.qrc ) find_package( Qt5 COMPONENTS Widgets Xml REQUIRED ) set(QT_DEPLIBS Qt5::Widgets Qt5::Xml ) qt5_wrap_ui(UIS ${_UIS}) qt5_add_resources(RSCS ${_RSCS}) add_library( ${PLUGIN} MODULE ${_SRCS} ${UIS} ${RSCS} ) target_link_libraries( ${PLUGIN} ${QT_DEPLIBS} ) if( UNIX AND NOT( APPLE OR CYGWIN ) ) install( TARGETS ${PLUGIN} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} ) endif() if( WIN32 ) install( TARGETS ${PLUGIN} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} ) endif() plugins-1.5/generic/chessplugin/boarddelegate.cpp000066400000000000000000000025621336777360500223140ustar00rootroot00000000000000/* * boarddelegate.cpp - plugin * Copyright (C) 2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "boarddelegate.h" #include "boardmodel.h" #include using namespace Chess; void BoardDelegate::paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const { BoardModel *model = (BoardModel*)index.model(); QRect r = option.rect; QColor color = ((option.state & QStyle::State_Selected) && model->myMove && !model->gameState_) ? QColor("#b5e3ff") : index.data(Qt::BackgroundColorRole).value(); painter->fillRect(r, color); QPixmap pix = index.data(Qt::DisplayRole).value(); painter->drawPixmap(r, pix); } plugins-1.5/generic/chessplugin/boarddelegate.h000066400000000000000000000022131336777360500217520ustar00rootroot00000000000000/* * boarddelegate.h - plugin * Copyright (C) 2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef BOARDDELEGATE_H #define BOARDDELEGATE_H #include namespace Chess { class BoardDelegate : public QItemDelegate { Q_OBJECT public: BoardDelegate(QObject *parent) : QItemDelegate(parent) {}; virtual void paint ( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const; }; } #endif // BOARDDELEGATE_H plugins-1.5/generic/chessplugin/boardmodel.cpp000066400000000000000000000746221336777360500216500ustar00rootroot00000000000000/* * boardmodel.cpp - plugin * Copyright (C) 2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "boardmodel.h" using namespace Chess; BoardModel::BoardModel(Figure::GameType type, QObject *parent) : QAbstractTableModel(parent) , myMove(false) , waitForFigure(false) , check(false) , gameType_(Figure::NoGame) , gameState_(-1) { setGameType(type); setHeaders(); } void BoardModel::setHeaders() { vHeader.clear(); hHeader.clear(); if(gameType_ == Figure::WhitePlayer) { vHeader << "8" << "7" << "6" << "5" << "4" << "3" << "2" << "1"; hHeader << "A" << "B" << "C" << "D" << "E" << "F" << "G" << "H"; } else { vHeader << "1" << "2" << "3" << "4" << "5" << "6" << "7" << "8"; hHeader << "H" << "G" << "F" << "E" << "D" << "C" << "B" << "A"; } } QVariant BoardModel::headerData ( int section, Qt::Orientation orientation, int role) const { if (role == Qt::DisplayRole) { if (orientation == Qt::Horizontal) { return hHeader.at(section); } else { return vHeader.at(section); } } else return QVariant(); } void BoardModel::setGameType(Figure::GameType type) { gameType_ = type; if(type == Figure::WhitePlayer) { myMove = true; } else { myMove = false; } } Qt::ItemFlags BoardModel::flags ( const QModelIndex & /*index*/ ) const { Qt::ItemFlags flags = Qt::NoItemFlags; flags |= Qt::ItemIsSelectable | Qt::ItemIsEnabled; return flags; } int BoardModel::columnCount(const QModelIndex & /*parent*/) const { return hHeader.size(); } int BoardModel::rowCount(const QModelIndex &/* parent*/) const { return vHeader.size(); } QVariant BoardModel::data(const QModelIndex & i, int role) const { QModelIndex index = i; if(!index.isValid()) return QVariant(); if(gameType_ == Figure::BlackPlayer) index = invert(index); if(role == Qt::BackgroundColorRole) { if(index == kingIndex() && isCheck()) return QVariant(QColor("#9a0000")); int i = index.column() + index.row(); if(i&1) { switch (gameState_) { case 1: return QVariant(QColor("green")); case 2: return QVariant(QColor("#b4ccff")); case 3: return QVariant(QColor("#9a0000")); default: return QVariant(QColor("#74440e")); } } else return QVariant(QColor("#ffedc2")); } else if(role == Qt::DisplayRole) { int x = index.column(); int y = index.row(); foreach(Figure *figure, whiteFigures_) { if(x == figure->positionX() && y == figure->positionY()) return figure->getPixmap(); } foreach(Figure *figure, blackFigures_) { if(x == figure->positionX() && y == figure->positionY()) return figure->getPixmap(); } return QVariant(); } return QVariant(); } void BoardModel::reset() { gameState_ = 0; qDeleteAll(whiteFigures_); whiteFigures_.clear(); qDeleteAll(blackFigures_); blackFigures_.clear(); for(int i = 0; i < 8; i++) { Figure *whitePawn = new Figure(Figure::WhitePlayer, Figure::White_Pawn, i, 6, this); whiteFigures_.append(whitePawn); } Figure *whiteKing = new Figure(Figure::WhitePlayer, Figure::White_King, 4, 7, this); Figure *whiteQueen = new Figure(Figure::WhitePlayer, Figure::White_Queen, 3, 7, this); Figure *whiteBishop = new Figure(Figure::WhitePlayer, Figure::White_Bishop, 2, 7, this); Figure *whiteBishop2 = new Figure(Figure::WhitePlayer, Figure::White_Bishop, 5, 7, this); Figure *whiteKnight = new Figure(Figure::WhitePlayer, Figure::White_Knight, 1, 7, this); Figure *whiteKnight2 = new Figure(Figure::WhitePlayer, Figure::White_Knight, 6, 7, this); Figure *whiteCastle = new Figure(Figure::WhitePlayer, Figure::White_Castle, 0, 7, this); Figure *whiteCastle2 = new Figure(Figure::WhitePlayer, Figure::White_Castle, 7, 7, this); whiteFigures_.append(whiteKing); whiteFigures_.append(whiteQueen); whiteFigures_.append(whiteBishop); whiteFigures_.append(whiteBishop2); whiteFigures_.append(whiteKnight); whiteFigures_.append(whiteKnight2); whiteFigures_.append(whiteCastle); whiteFigures_.append(whiteCastle2); for(int i = 0; i < 8; i++) { Figure *blackPawn = new Figure(Figure::BlackPlayer, Figure::Black_Pawn, i, 1, this); blackFigures_.append(blackPawn); } Figure *blackKing = new Figure(Figure::BlackPlayer, Figure::Black_King, 4, 0, this); Figure *blackQueen = new Figure(Figure::BlackPlayer, Figure::Black_Queen, 3, 0, this); Figure *blackBishop = new Figure(Figure::BlackPlayer, Figure::Black_Bishop, 2, 0, this); Figure *blackBishop2 = new Figure(Figure::BlackPlayer, Figure::Black_Bishop, 5, 0, this); Figure *blackKnight = new Figure(Figure::BlackPlayer, Figure::Black_Knight, 1, 0, this); Figure *blackKnight2 = new Figure(Figure::BlackPlayer, Figure::Black_Knight, 6, 0, this); Figure *blackCastle = new Figure(Figure::BlackPlayer, Figure::Black_Castle, 0, 0, this); Figure *blackCastle2 = new Figure(Figure::BlackPlayer, Figure::Black_Castle, 7, 0, this); blackFigures_.append(blackKing); blackFigures_.append(blackQueen); blackFigures_.append(blackBishop); blackFigures_.append(blackBishop2); blackFigures_.append(blackKnight); blackFigures_.append(blackKnight2); blackFigures_.append(blackCastle); blackFigures_.append(blackCastle2); beginResetModel(); endResetModel(); } bool BoardModel::moveRequested(QModelIndex oldIndex, QModelIndex newIndex) { if(!oldIndex.isValid() || !newIndex.isValid()) return false; check = isCheck(); Figure *figure = findFigure(oldIndex); if(figure) { if(figure->gameType() != gameType_ && myMove) return false; int x = newIndex.column(); int y = newIndex.row(); int move_ = canMove(figure, x, y); if(!move_) return false; Figure *newFigure = 0; if(move_ == 2) { //kill figure newFigure = findFigure(newIndex); if(newFigure) { int tmpX = newFigure->positionX(); int tmpY = newFigure->positionY(); newFigure->setPosition(-1,-1); figure->setPosition(x, y); if(isCheck()) { figure->setPosition(oldIndex.column(), oldIndex.row()); newFigure->setPosition(tmpX, tmpY); return false; } emit figureKilled(newFigure); } } else if(move_ == 3) { //kill with pawn int tmpX = lastMove.figure->positionX(); int tmpY = lastMove.figure->positionY(); lastMove.figure->setPosition(-1,-1); figure->setPosition(x, y); if(isCheck()) { figure->setPosition(oldIndex.column(), oldIndex.row()); lastMove.figure->setPosition(tmpX, tmpY); return false; } emit figureKilled(lastMove.figure); } else if(move_ == 4) { //roc figure->setPosition(x, y); if(isCheck()) { figure->setPosition(oldIndex.column(), oldIndex.row()); return false; } if(x == 6) { QModelIndex tmpIndex = createIndex(y,7); newFigure = findFigure(tmpIndex); newFigure->setPosition(5,y); } else if(x == 2) { QModelIndex tmpIndex = createIndex(y,0); newFigure = findFigure(tmpIndex); newFigure->setPosition(3,y); } } else { //move figure->setPosition(x, y); if(isCheck()) { figure->setPosition(oldIndex.column(), oldIndex.row()); return false; } } figure->isMoved = true; lastMove.oldIndex = oldIndex; lastMove.newIndex = newIndex; lastMove.figure = figure; lastMove.killedFigure = newFigure; emit layoutChanged(); if((figure->type() == Figure::White_Pawn && y == 0) || (figure->type() == Figure::Black_Pawn && y == 7) ) { if(myMove) emit needNewFigure(newIndex, figure->type() == Figure::White_Pawn ? "white" : "black"); waitForFigure = true; tempIndex_ = oldIndex; return true; } else if(myMove) emit move(oldIndex.column(), 7-oldIndex.row(), newIndex.column(), 7-newIndex.row(), ""); //7- - for compatibility with tkabber moveTransfer(); return true; } return false; } bool BoardModel::moveRequested(int oldX, int oldY, int newX, int newY) { return moveRequested(createIndex(7-oldY, oldX), createIndex(7-newY, newX));//7- - for compatibility with tkabber } bool BoardModel::isYourFigure(const QModelIndex &index) const { Figure *figure = findFigure(index); if(!figure) return false; return gameType_ == figure->gameType(); } Figure *BoardModel::findFigure(QModelIndex index) const { Figure *figure_ = 0; int x = index.column(); int y = index.row(); foreach(Figure *figure, whiteFigures_) { if(x == figure->positionX() && y == figure->positionY()) { figure_ = figure; break; } } if(!figure_) { foreach(Figure *figure, blackFigures_) { if(x == figure->positionX() && y == figure->positionY()) { figure_ = figure; break; } } } return figure_; } QModelIndex BoardModel::kingIndex() const { if(gameType_ == Figure::WhitePlayer) return findFigure(Figure::White_King, gameType_); return findFigure(Figure::Black_King, gameType_); } QModelIndex BoardModel::findFigure(Figure::FigureType type, Figure::GameType game) const { QModelIndex index; if(game == Figure::WhitePlayer) { foreach(Figure *figure, whiteFigures_) { if(type == figure->type()) { index = createIndex(figure->positionY(), figure->positionX()); } } } else { foreach(Figure *figure, blackFigures_) { if(type == figure->type()) { index = createIndex(figure->positionY(), figure->positionX()); } } } return index; } //return 0 - can't move; //return 1 - can move; //return 2 - kill someone; //return 3 - strange pawn kill :) //return 4 - roc int BoardModel::canMove(Figure *figure, int newX, int newY) const { int positionX_ = figure->positionX(); int positionY_ = figure->positionY(); bool isMoved = figure->isMoved; switch(figure->type()) { case Figure::White_Pawn: if(qAbs(newX - positionX_) > 1) return 0; if((positionY_ - newY) == 2 && !isMoved && newX == positionX_) { QModelIndex index = createIndex(positionY_-1, positionX_); if(findFigure(index)) return 0; index = createIndex(newY,newX); if(findFigure(index)) return 0; return 1; } if(positionY_ - newY == 1) { QModelIndex index = createIndex(newY, newX); Figure *f = findFigure(index); if(newX == positionX_) { if(!f) return 1; else return 0; } if(f && f->gameType() == Figure::BlackPlayer) return 2; if(lastMove.figure->type() == Figure::Black_Pawn && qAbs(lastMove.oldIndex.row() - lastMove.newIndex.row()) == 2 && lastMove.oldIndex.row()+1 == newY && lastMove.oldIndex.column() == newX) return 3; return 0; } return 0; case Figure::Black_Pawn: if(qAbs(newX - positionX_) > 1) return 0; if((positionY_ - newY) == -2 && !isMoved && newX == positionX_) { QModelIndex index = createIndex(positionY_+1, positionX_); if(findFigure(index)) return 0; index = createIndex(newY,newX); if(findFigure(index)) return 0; return 1; } if(positionY_ - newY == -1) { QModelIndex index = createIndex(newY, newX); Figure *f = findFigure(index); if(newX == positionX_) { if(!f) return 1; else return 0; } if(f && f->gameType() == Figure::WhitePlayer) return 2; if(lastMove.figure->type() == Figure::White_Pawn && qAbs(lastMove.oldIndex.row() - lastMove.newIndex.row()) == 2 && lastMove.oldIndex.row()-1 == newY && lastMove.oldIndex.column() == newX) return 3; return 0; } return 0; case Figure::White_Castle: if((newX == positionX_ && newY != positionY_) || (newX != positionX_ && newY == positionY_)) { if(positionX_-newX > 0) { for(int i = positionX_-newX-1; i > 0; --i) { QModelIndex index = createIndex(positionY_, positionX_-i); if(findFigure(index)) return 0; } } else if(newX-positionX_ > 0) { for(int i = newX-positionX_-1; i > 0; --i) { QModelIndex index = createIndex(positionY_, positionX_+i); if(findFigure(index)) return 0; } } else if(positionY_-newY > 0) { for(int i = positionY_-newY-1; i > 0; --i) { QModelIndex index = createIndex(positionY_-i, positionX_); if(findFigure(index)) return 0; } } else if(newY-positionY_ > 0) { for(int i = newY-positionY_-1; i > 0; --i) { QModelIndex index = createIndex(positionY_+i, positionX_); if(findFigure(index)) return 0; } } Figure *figure_ = findFigure(createIndex(newY, newX)); if(!figure_) return 1; else return 2; } return 0; case Figure::Black_Castle: if((newX == positionX_ && newY != positionY_) || (newX != positionX_ && newY == positionY_)) { if(positionX_-newX > 0) { for(int i = positionX_-newX-1; i > 0; --i) { QModelIndex index = createIndex(positionY_, positionX_-i); if(findFigure(index)) return 0; } } else if(newX-positionX_ > 0) { for(int i = newX-positionX_-1; i > 0; --i) { QModelIndex index = createIndex(positionY_, positionX_+i); if(findFigure(index)) return 0; } } else if(positionY_-newY > 0) { for(int i = positionY_-newY-1; i > 0; --i) { QModelIndex index = createIndex(positionY_-i, positionX_); if(findFigure(index)) return 0; } } else if(newY-positionY_ > 0) { for(int i = newY-positionY_-1; i > 0; --i) { QModelIndex index = createIndex(positionY_+i, positionX_); if(findFigure(index)) return 0; } } Figure *figure_ = findFigure(createIndex(newY, newX)); if(!figure_) return 1; else return 2; } return 0; case Figure::White_King: if(qAbs(newX - positionX_) < 2 && qAbs(newY - positionY_) < 2) { Figure *figure_ = findFigure(createIndex(newY, newX)); if(!figure_) return 1; else return 2; } if(check) { return 0; } if(!isMoved && newX == 6 && newY == 7) { Figure *figure_ = findFigure(createIndex(7, 7)); if(!figure_) { return 0; } if(figure_->isMoved) { return 0; } figure_ = findFigure(createIndex(7,5)); if(figure_) { return 0; } figure_ = findFigure(createIndex(7,6)); if(figure_) { return 0; } figure->setPosition(5,7); foreach(Figure *figure_, blackFigures_) { if(figure_->positionX() != -1) { if(canMove(figure_, 5,7)){ figure->setPosition(positionX_, positionY_); return 0; } } } return 4; } if(!isMoved && newX == 2 && newY == 7) { Figure *figure_ = findFigure(createIndex(7, 0)); if(!figure_) return 0; if(figure_->isMoved) return 0; figure_ = findFigure(createIndex(7,3)); if(figure_) return 0; figure_ = findFigure(createIndex(7,2)); if(figure_) return 0; figure_ = findFigure(createIndex(7,1)); if(figure_) return 0; figure->setPosition(3,7); foreach(Figure *figure_, blackFigures_) { if(figure_->positionX() != -1) { if(canMove(figure_, 3,7)) { figure->setPosition(positionX_, positionY_); return 0; } } } return 4; } return 0; case Figure::Black_King: if(qAbs(newX - positionX_) < 2 && qAbs(newY - positionY_) < 2) { Figure *figure_ = findFigure(createIndex(newY, newX)); if(!figure_) return 1; else return 2; } if(check) return 0; if(!isMoved && newX == 6 && newY == 0) { Figure *figure_ = findFigure(createIndex(0, 7)); if(!figure_) return 0; if(figure_->isMoved) return 0; figure_ = findFigure(createIndex(0,5)); if(figure_) return 0; figure_ = findFigure(createIndex(0,6)); if(figure_) return 0; figure->setPosition(5,0); foreach(Figure *figure_, whiteFigures_) { if(figure_->positionX() != -1) { if(canMove(figure_, 5,0)) { figure->setPosition(positionX_, positionY_); return 0; } } } return 4; } if(!isMoved && newX == 2 && newY == 0) { Figure *figure_ = findFigure(createIndex(0, 0)); if(!figure_) return 0; if(figure_->isMoved) return 0; figure_ = findFigure(createIndex(0,3)); if(figure_) return 0; figure_ = findFigure(createIndex(0,2)); if(figure_) return 0; figure_ = findFigure(createIndex(0,1)); if(figure_) return 0; figure->setPosition(3,0); foreach(Figure *figure_, whiteFigures_) { if(figure_->positionX() != -1) { if(canMove(figure_, 3,0)) { figure->setPosition(positionX_, positionY_); return 0; } } } return 4; } return 0; case Figure::White_Bishop: if(qAbs(newX - positionX_) == qAbs(newY - positionY_)) { if(newX-positionX_ > 0) { if(newY-positionY_ > 0) { for(int i = newX-positionX_-1; i>0; --i){ QModelIndex index = createIndex(positionY_+i, positionX_+i); if(findFigure(index)) return 0; } } else if(positionY_-newY > 0) { for(int i = newX-positionX_-1; i>0; --i){ QModelIndex index = createIndex(positionY_-i, positionX_+i); if(findFigure(index)) return 0; } } } else if(positionX_-newX > 0) { if(newY-positionY_ > 0) { for(int i = positionX_-newX-1; i>0; --i){ QModelIndex index = createIndex(positionY_+i, positionX_-i); if(findFigure(index)) return 0; } } else if(positionY_-newY > 0) { for(int i = positionX_-newX-1; i>0; --i){ QModelIndex index = createIndex(positionY_-i, positionX_-i); if(findFigure(index)) return 0; } } } Figure *figure_ = findFigure(createIndex(newY, newX)); if(!figure_) return 1; else return 2; } return 0; case Figure::Black_Bishop: if(qAbs(newX - positionX_) == qAbs(newY - positionY_)) { if(newX-positionX_ > 0) { if(newY-positionY_ > 0) { for(int i = newX-positionX_-1; i>0; --i){ QModelIndex index = createIndex(positionY_+i, positionX_+i); if(findFigure(index)) return 0; } } else if(positionY_-newY > 0) { for(int i = newX-positionX_-1; i>0; --i){ QModelIndex index = createIndex(positionY_-i, positionX_+i); if(findFigure(index)) return 0; } } } else if(positionX_-newX > 0) { if(newY-positionY_ > 0) { for(int i = positionX_-newX-1; i>0; --i){ QModelIndex index = createIndex(positionY_+i, positionX_-i); if(findFigure(index)) return 0; } } else if(positionY_-newY > 0) { for(int i = positionX_-newX-1; i>0; --i){ QModelIndex index = createIndex(positionY_-i, positionX_-i); if(findFigure(index)) return 0; } } } Figure *figure_ = findFigure(createIndex(newY, newX)); if(!figure_) return 1; else return 2; } return 0; case Figure::White_Knight: if((qAbs(newX - positionX_) == 2 && qAbs(newY - positionY_) == 1) || (qAbs(newX - positionX_) == 1 && qAbs(newY - positionY_) == 2)) { Figure *figure_ = findFigure(createIndex(newY, newX)); if(!figure_) return 1; else return 2; } return 0; case Figure::Black_Knight: if((qAbs(newX - positionX_) == 2 && qAbs(newY - positionY_) == 1) || (qAbs(newX - positionX_) == 1 && qAbs(newY - positionY_) == 2)) { Figure *figure_ = findFigure(createIndex(newY, newX)); if(!figure_) return 1; else return 2; } return 0; case Figure::White_Queen: if((newX == positionX_ && newY != positionY_) || (newX != positionX_ && newY == positionY_)) { if(positionX_-newX > 0) { for(int i = positionX_-newX-1; i > 0; --i) { QModelIndex index = createIndex(positionY_, positionX_-i); if(findFigure(index)) return 0; } } else if(newX-positionX_ > 0) { for(int i = newX-positionX_-1; i > 0; --i) { QModelIndex index = createIndex(positionY_, positionX_+i); if(findFigure(index)) return 0; } } else if(positionY_-newY > 0) { for(int i = positionY_-newY-1; i > 0; --i) { QModelIndex index = createIndex(positionY_-i, positionX_); if(findFigure(index)) return 0; } } else if(newY-positionY_ > 0) { for(int i = newY-positionY_-1; i > 0; --i) { QModelIndex index = createIndex(positionY_+i, positionX_); if(findFigure(index)) return 0; } } Figure *figure_ = findFigure(createIndex(newY, newX)); if(!figure_) return 1; else return 2; } if(qAbs(newX - positionX_) == qAbs(newY - positionY_)) { if(newX-positionX_ > 0) { if(newY-positionY_ > 0) { for(int i = newX-positionX_-1; i>0; --i){ QModelIndex index = createIndex(positionY_+i, positionX_+i); if(findFigure(index)) return 0; } } else if(positionY_-newY > 0) { for(int i = newX-positionX_-1; i>0; --i){ QModelIndex index = createIndex(positionY_-i, positionX_+i); if(findFigure(index)) return 0; } } } else if(positionX_-newX > 0) { if(newY-positionY_ > 0) { for(int i = positionX_-newX-1; i>0; --i){ QModelIndex index = createIndex(positionY_+i, positionX_-i); if(findFigure(index)) return 0; } } else if(positionY_-newY > 0) { for(int i = positionX_-newX-1; i>0; --i){ QModelIndex index = createIndex(positionY_-i, positionX_-i); if(findFigure(index)) return 0; } } } Figure *figure_ = findFigure(createIndex(newY, newX)); if(!figure_) return 1; else return 2; } return 0; case Figure::Black_Queen: if((newX == positionX_ && newY != positionY_) || (newX != positionX_ && newY == positionY_)) { if(positionX_-newX > 0) { for(int i = positionX_-newX-1; i > 0; --i) { QModelIndex index = createIndex(positionY_, positionX_-i); if(findFigure(index)) return 0; } } else if(newX-positionX_ > 0) { for(int i = newX-positionX_-1; i > 0; --i) { QModelIndex index = createIndex(positionY_, positionX_+i); if(findFigure(index)) return 0; } } else if(positionY_-newY > 0) { for(int i = positionY_-newY-1; i > 0; --i) { QModelIndex index = createIndex(positionY_-i, positionX_); if(findFigure(index)) return 0; } } else if(newY-positionY_ > 0) { for(int i = newY-positionY_-1; i > 0; --i) { QModelIndex index = createIndex(positionY_+i, positionX_); if(findFigure(index)) return 0; } } Figure *figure_ = findFigure(createIndex(newY, newX)); if(!figure_) return 1; else return 2; } if(qAbs(newX - positionX_) == qAbs(newY - positionY_)) { if(newX-positionX_ > 0) { if(newY-positionY_ > 0) { for(int i = newX-positionX_-1; i>0; --i){ QModelIndex index = createIndex(positionY_+i, positionX_+i); if(findFigure(index)) return 0; } } else if(positionY_-newY > 0) { for(int i = newX-positionX_-1; i>0; --i){ QModelIndex index = createIndex(positionY_-i, positionX_+i); if(findFigure(index)) return 0; } } } else if(positionX_-newX > 0) { if(newY-positionY_ > 0) { for(int i = positionX_-newX-1; i>0; --i){ QModelIndex index = createIndex(positionY_+i, positionX_-i); if(findFigure(index)) return 0; } } else if(positionY_-newY > 0) { for(int i = positionX_-newX-1; i>0; --i){ QModelIndex index = createIndex(positionY_-i, positionX_-i); if(findFigure(index)) return 0; } } } Figure *figure_ = findFigure(createIndex(newY, newX)); if(!figure_) return 1; else return 2; } return 0; case Figure::None: return 0; } return false; } QMultiMap BoardModel::availableMoves(Figure* figure) const { QMultiMap map; for(int x = 0; x <= 7; x++) { for(int y = 0; y <= 7; y++) { if(isYourFigure(index(y,x))) continue; int move = canMove(figure, x, y); if(move) { map.insert(index(y,x), move); } } } return map; } int BoardModel::checkGameState() { int state = 0; check = isCheck(); if(gameType_ == Figure::WhitePlayer) { foreach(Figure *figure, whiteFigures_) { if(figure->positionX() != -1) { QMultiMap moves = availableMoves(figure); if(!moves.isEmpty()) { QList ml = moves.keys(); foreach(QModelIndex index, ml) { if(doTestMove(figure, index, moves.value(index))) { return state; //in progress } } } } } } else { foreach(Figure *figure, blackFigures_) { if(figure->positionX() != -1) { QMultiMap moves = availableMoves(figure); if(!moves.isEmpty()) { QList ml = moves.keys(); foreach(QModelIndex index, ml) { if(doTestMove(figure, index, moves.value(index))) { return state; //in progress } } } } } } state = isCheck() ? 2 : 1; return state; } bool BoardModel::doTestMove(Figure *figure, QModelIndex newIndex, int move) { int oldX = figure->positionX(); int oldY = figure->positionY(); int x = newIndex.column(); int y = newIndex.row(); int tmpX; int tmpY; bool ch; Figure *newFigure = 0; switch(move) { case 1: figure->setPosition(x, y); ch = isCheck(); figure->setPosition(oldX, oldY); return ch ? false : true; break; case 2: newFigure = findFigure(newIndex); if(newFigure) { tmpX = newFigure->positionX(); tmpY = newFigure->positionY(); newFigure->setPosition(-1,-1); figure->setPosition(x, y); ch = isCheck(); figure->setPosition(oldX, oldY); newFigure->setPosition(tmpX, tmpY); return ch ? false : true; } return false; break; case 3: tmpX = lastMove.figure->positionX(); tmpY = lastMove.figure->positionY(); lastMove.figure->setPosition(-1,-1); figure->setPosition(x, y); ch = isCheck(); figure->setPosition(oldX, oldY); lastMove.figure->setPosition(tmpX, tmpY); return ch ? false : true; break; case 4: figure->setPosition(x, y); ch = isCheck(); figure->setPosition(oldX, oldY); return ch ? false : true; break; } return false; } bool BoardModel::isCheck() const { if(!myMove) return false; bool check_ = false; QModelIndex king = kingIndex(); int kingX = king.column(); int kingY = king.row(); if(gameType_ == Figure::WhitePlayer) { foreach(Figure* figure, blackFigures_) { if(figure->positionX() != -1) { if(canMove(figure, kingX, kingY) == 2) { check_ = true; break; } } } } else if(gameType_ == Figure::BlackPlayer) { foreach(Figure* figure, whiteFigures_) { if(figure->positionX() != -1) { if(canMove(figure, kingX, kingY) == 2) { check_ = true; break; } } } } return check_; } QModelIndex BoardModel::invert(QModelIndex index) const { return createIndex(7 - index.row(), 7 - index.column()); } void BoardModel::updateFigure(QModelIndex index, const QString& figure) { Figure *oldFigure = findFigure(index); if( (gameType_ == Figure::WhitePlayer && myMove) || (gameType_ == Figure::BlackPlayer && !myMove) ) { if(figure == "queen") { oldFigure->setType(Figure::White_Queen); } else if(figure == "rook") { oldFigure->setType(Figure::White_Castle); } else if(figure == "bishop") { oldFigure->setType(Figure::White_Bishop); } else if(figure == "knight") { oldFigure->setType(Figure::White_Knight); } } else { if(figure == "queen") { oldFigure->setType(Figure::Black_Queen); } else if(figure == "rook") { oldFigure->setType(Figure::Black_Castle); } else if(figure == "bishop") { oldFigure->setType(Figure::Black_Bishop); } else if(figure == "knight") { oldFigure->setType(Figure::Black_Knight); } } if(myMove) emit move(tempIndex_.column(), 7-tempIndex_.row(), index.column(), 7-index.row(), figure); //7- - for compatibility with tkabber moveTransfer(); waitForFigure = false; emit layoutChanged(); } void BoardModel::moveTransfer() { myMove = !myMove; } static inline Figure::FigureType rankFigure(int i) { switch (i) { case 1: return Figure::White_Pawn; case 2: return Figure::White_Castle; case 3: return Figure::White_Bishop; case 4: return Figure::White_King; case 5: return Figure::White_Queen; case 6: return Figure::White_Knight; case 7: return Figure::Black_Pawn; case 8: return Figure::Black_Castle; case 9: return Figure::Black_Bishop; case 10: return Figure::Black_King; case 11: return Figure::Black_Queen; case 12: return Figure::Black_Knight; default: return Figure::None; } return Figure::None; } QString BoardModel::saveString() const { QString save; foreach(Figure *figure, whiteFigures_) { save += QString("%1,%2,%3,%4;").arg(QString::number(figure->type())) .arg(QString::number(figure->positionY())).arg(QString::number(figure->positionX())) .arg(figure->isMoved ? QString::number(1) : QString::number(0)); } foreach(Figure *figure, blackFigures_) { save += QString("%1,%2,%3,%4;").arg(QString::number(figure->type())) .arg(QString::number(figure->positionY())).arg(QString::number(figure->positionX())) .arg(figure->isMoved ? QString::number(1) : QString::number(0)); } save += myMove ? QString::number(1) : QString::number(0); save += ";"+QString::number(gameType_)+";"; return save; } void BoardModel::loadSettings(const QString& settings, bool myLoad) { reset(); QStringList figuresSettings = settings.split(";"); foreach(Figure *figure, whiteFigures_) { if(!figuresSettings.isEmpty()) { QStringList set = figuresSettings.takeFirst().split(","); figure->setType(rankFigure(set.takeFirst().toInt())); figure->setPosition(set.takeFirst().toInt(),set.takeFirst().toInt()); figure->isMoved = set.takeFirst().toInt(); } } foreach(Figure *figure, blackFigures_) { if(!figuresSettings.isEmpty()) { QStringList set = figuresSettings.takeFirst().split(","); figure->setType(rankFigure(set.takeFirst().toInt())); figure->setPosition(set.takeFirst().toInt(),set.takeFirst().toInt()); figure->isMoved = set.takeFirst().toInt(); } } if(!figuresSettings.isEmpty()) myMove = myLoad ? figuresSettings.takeFirst().toInt() : !figuresSettings.takeFirst().toInt(); if(!figuresSettings.isEmpty()) { int i = figuresSettings.takeFirst().toInt(); switch (i){ case 1: gameType_ = myLoad ? Figure::WhitePlayer : Figure::BlackPlayer; break; case 2: gameType_ = myLoad ? Figure::BlackPlayer : Figure::WhitePlayer; break; default: gameType_ = Figure::NoGame; break; } setHeaders(); } emit layoutChanged(); } void BoardModel::updateView() { emit layoutChanged(); } plugins-1.5/generic/chessplugin/boardmodel.h000066400000000000000000000061521336777360500213060ustar00rootroot00000000000000/* * boardmodel.h - plugin * Copyright (C) 2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef BOARDMODEL_H #define BOARDMODEL_H #include #include #include "figure.h" namespace Chess { class BoardModel : public QAbstractTableModel { Q_OBJECT public: BoardModel(Figure::GameType type, QObject *parent = 0); ~BoardModel() {}; virtual Qt::ItemFlags flags ( const QModelIndex & index ) const; virtual QVariant headerData ( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const; virtual QVariant data ( const QModelIndex & index, int role = Qt::DisplayRole ) const; virtual int rowCount ( const QModelIndex & parent = QModelIndex() ) const; virtual int columnCount ( const QModelIndex & parent = QModelIndex() ) const; void setGameType(Figure::GameType type); bool isYourFigure(const QModelIndex &index) const; bool moveRequested(QModelIndex oldIndex, QModelIndex newIndex); bool moveRequested(int oldX, int oldY, int newX, int newY); QModelIndex kingIndex() const; QModelIndex invert(QModelIndex index) const; //for black player Figure* findFigure(QModelIndex index) const; void reset(); void updateFigure(QModelIndex index, const QString& newFigure); QString saveString() const; void loadSettings(const QString& settings, bool myLoad = true); void updateView(); int checkGameState(); //0 - in progress; 1 - draw; 2 - lose; bool myMove; bool waitForFigure; bool check; Figure::GameType gameType_; int gameState_; //0 - in progress, 1 - draw, 2 - win, 3 - lose; signals: void move(int, int, int, int, QString); void figureKilled(Figure*); void needNewFigure(QModelIndex index, QString player); private: int canMove(Figure *figure, int newX, int newY) const; QModelIndex findFigure(Figure::FigureType type, Figure::GameType game) const; QMultiMap availableMoves(Figure* figure) const; bool doTestMove(Figure *figure, QModelIndex newIndex, int move); bool isCheck() const; void moveTransfer(); void setHeaders(); QStringList hHeader, vHeader; QList whiteFigures_, blackFigures_; QModelIndex tempIndex_; struct Move { QModelIndex oldIndex; QModelIndex newIndex; Figure *figure; Figure *killedFigure; }; Move lastMove; }; } #endif // BOARDMODEL_H plugins-1.5/generic/chessplugin/boardview.cpp000066400000000000000000000103011336777360500215020ustar00rootroot00000000000000/* * boardview.cpp - plugin * Copyright (C) 2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "boardview.h" #include "boarddelegate.h" #include "boardmodel.h" #include #include using namespace Chess; BoardView::BoardView(QWidget *parent) :QTableView(parent) { QHeaderView *hHeader = horizontalHeader(); #ifdef HAVE_QT5 hHeader->setSectionResizeMode(QHeaderView::Fixed); hHeader->setSectionsMovable(false); hHeader->setSectionsClickable(false); #else hHeader->setMovable(false); hHeader->setResizeMode(QHeaderView::Fixed); hHeader->setClickable(false); #endif hHeader->setDefaultAlignment( Qt::AlignHCenter ); hHeader->setDefaultSectionSize(50); QHeaderView *vHeader = verticalHeader(); #ifdef HAVE_QT5 vHeader->setSectionResizeMode(QHeaderView::Fixed); vHeader->setSectionsClickable(false); vHeader->setSectionsMovable(false); #else vHeader->setResizeMode(QHeaderView::Fixed); vHeader->setClickable(false); vHeader->setMovable(false); #endif vHeader->setDefaultAlignment( Qt::AlignVCenter ); vHeader->setDefaultSectionSize(50); setSelectionMode(QAbstractItemView::SingleSelection); setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); setItemDelegate(new BoardDelegate(this)); setStyleSheet("QHeaderView::section {background-color: #ffffe7; border: 1px solid #74440e; color: black; }" "QTableCornerButton::section { background-color: #ffffe7; border: 1px solid #74440e; color: black; }" "QToolTip { background-color: #ffeeaf; padding: 2px; border: 1px solid #74440e; }"); } void BoardView::mousePressEvent(QMouseEvent *e) { QModelIndex oldIndex = currentIndex(); BoardModel *model_ = (BoardModel*)model(); if(!model_->myMove || model_->waitForFigure || model_->gameState_) { e->ignore(); return; } QTableView::mousePressEvent(e); e->accept(); QModelIndex newIndex = currentIndex(); if(model_->gameType_ == Figure::BlackPlayer) { newIndex = model_->invert(newIndex); } if(!model_->isYourFigure(newIndex)) setCurrentIndex(oldIndex); } void BoardView::mouseReleaseEvent(QMouseEvent *e) { QModelIndex oldIndex = currentIndex(); BoardModel *model_ = (BoardModel*)model(); if(!model_->myMove || model_->waitForFigure || model_->gameState_) { e->ignore(); return; } QTableView::mousePressEvent(e); e->accept(); QModelIndex newIndex = currentIndex(); if(model_->gameType_ == Figure::BlackPlayer) { oldIndex = model_->invert(oldIndex); newIndex = model_->invert(newIndex); } if(!model_->isYourFigure(newIndex)) { if(!model_->moveRequested(oldIndex, newIndex)) { if(model_->gameType_ == Figure::BlackPlayer) setCurrentIndex(model_->invert(oldIndex)); else setCurrentIndex(oldIndex); } else { if(model_->gameType_ == Figure::BlackPlayer) setCurrentIndex(model_->invert(newIndex)); else setCurrentIndex(newIndex); } } } void BoardView::mouseMoveEvent(QMouseEvent *e) { e->ignore(); } void BoardView::keyPressEvent(QKeyEvent *e) { e->ignore(); } bool BoardView::event(QEvent *e) { if(e->type() == QEvent::ToolTip) { QPoint p = ((QHelpEvent *)e)->pos(); p.setX(p.x() - verticalHeader()->width()); p.setY(p.y() - horizontalHeader()->height()); QModelIndex i = indexAt(p); if(i.isValid()) { BoardModel *model_ = (BoardModel*)model(); setToolTip(QString("%1%2").arg(model_->headerData(i.column(), Qt::Horizontal).toString(), model_->headerData(i.row(), Qt::Vertical).toString())); } else setToolTip(""); } return QTableView::event(e); } plugins-1.5/generic/chessplugin/boardview.h000066400000000000000000000023601336777360500211550ustar00rootroot00000000000000/* * boardview.h - plugin * Copyright (C) 2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef BOARDVIEW_H #define BOARDVIEW_H #include #include class BoardView : public QTableView { Q_OBJECT public: BoardView(QWidget *parent = 0); protected: virtual void mousePressEvent(QMouseEvent *e); virtual void mouseReleaseEvent(QMouseEvent *e); virtual void mouseMoveEvent(QMouseEvent *e); virtual void keyPressEvent(QKeyEvent *e); virtual bool event(QEvent *e); }; #endif // BOARDVIEW_H plugins-1.5/generic/chessplugin/changelog.txt000066400000000000000000000125351336777360500215170ustar00rootroot000000000000002017-07-26 v0.2.8 * исправлено падение плагина при закрытии доски через меню 2013-08-13 v0.2.7 - taurus + Иконка плагина 2011-03-15 v0.2.5 * исправлен баг в ходах пешки * исправления для игры в конференции 2011-02-22 v0.2.4 * исправлены опечатки на вкладке с настройками плагина 2011-02-21 v0.2.3 * лучшая поддержка игры через конференцию 2011-02-08 v0.2.2 * для проигрывания звука теперь используется новый плагинный интерфейс * некоторые улучшения 2011-01-31 v0.2.1 + добавлены всплывающие уведомления о некоторых событиях + добавлена нормальная поддержка множественных запросов + теперь обрабатываются входящие события только от контакта, с которым вы в данный момент играете * различные исправления 2011-01-19 v0.2.0 * различные исправления и улучшения 2010-12-17 v0.1.9 * небольшие исправления 2010-09-11 v0.1.8 * обновлена ссылка на wiki ( http://psi-plus.com/wiki/plugins#chess_plugin ) 2010-08-25 v0.1.7 * совместимость с последней версией Psi+ 2010-07-20 v0.1.6 + приглашения поиграть теперь появляются как обычные события * различные исправления 2010-05-25 v0.1.5 * информация о победе/поражении приходит только один раз * исправления для улучшения перевода + в случае победы пункт меню "сдаться" становится неактивным + всплывающие подсказки с координатами над доской 2010-05-17 v0.1.4 + добавлена информация о плагине 2010-05-04 v0.1.3 * исправлена ссылка на wiki 2010-04-23 v0.1.2 + теперь плагин умеет определять мат и пат + в меню game добавлена опция на включение/отключение звука * теперь ход производится при отпускании кнопки мыши * некоторые улучшения в стиле меню * различные исправления 2010-04-21 v0.1.1 + добавлена возможность отключить получение приглашений, если статус DND + добавлена возможность включить игнорирование глобального отключения звука * исправлены стили для темных тем + в истории ходов пишется название фигуры + если во время игры кто-то еще пришлет приглашение автоматически будет послан отказ + в истории ходов включена вертикальная полоса прокрутки + когда оппонент закрывает игру, приходит уведомление. + добавлена возможность сдаться 2010-04-20 v0.1.0 * добавлена совместимость с аналогичным плагином клиента tkabber + возможность выбрать сторону при приглашении + возможность выбрать ресурс игрока, которому отправляется приглашение - убрано контекстное меню + приглашение приходит в виде всплывающего диалога, а не в виде сообщения * различные исправления ВНИМАНИЕ! Эта версия несовместима с предыдущими! 2010-04-17 v0.0.3 * исправлена логика ходов пешек 2010-04-12 v0.0.2 * исправлено определение возможности рокировки + теперь согласиться на игру или отклонить запрос можно из контекстного меню, вызываемого при нажатии на кнопку плагина (из контекстного меню контакта или на тулбаре) + добавлена история ходов 2010-04-12 v0.0.1 ! initial version Данный плагин позволяет вам поиграть с вашими знакомыми в шахматы. Для передачи команд используются обычные сообщения, поэтому плагин будет работать везде, где у вас есть возможность выйти в онлайн. В текущей реализации плагин не умеет определять, что партия завершена (мат или пат) - так что этот момент остаётся на совести игроков. plugins-1.5/generic/chessplugin/chess.png000066400000000000000000000031431336777360500206350ustar00rootroot00000000000000PNG  IHDRaiCCPICC ProfilexTkA6n"Zkx"IYhE6bk Ed3In6&*Ezd/JZE(ޫ(b-nL~7}ov r4 Ril|Bj A4%UN$As{z[V{wwҶ@G*q Y<ߡ)t9Nyx+=Y"|@5-MS%@H8qR>׋infObN~N>! ?F?aĆ=5`5_M'Tq. VJp8dasZHOLn}&wVQygE0  HPEaP@<14r?#{2u$jtbDA{6=Q<("qCA*Oy\V;噹sM^|vWGyz?W15s-_̗)UKuZ17ߟl;=..s7VgjHUO^gc)1&v!.K `m)m$``/]?[xF QT*d4o(/lșmSqens}nk~8X<R5 vz)Ӗ9R,bRPCRR%eKUbvؙn9BħJeRR~NցoEx pHYs  IDAT8MSKa?w&6?1fL(HECd!$teW]x߿Š12 l.`͹ϷyIs9,˄OtMLLt222b ",| htt4><<|P(iiiy؝}9V r8aH$X,~T*Z[[KFzfinnn<sltww{wrrRp8f5^\\OOO?cToGPpiimnnvvgxЍz>NNN^-,,1;ܷR@Jʼn꽸1?[(A2ZvA؈)FKNV`0kllj""hzzz]]]e#Y-N>;;IPPJ%BU/ X,! YX [YYYd2@ z=1\.\o2'D*9;لP | T@XDSWWW'~,TC|鴢WU@V8%Vڶ.!Wt\~/AzUfr:mD(vO7ܔh@`CmJAz- 7iKhA^OEx*+|[{tG[Sw@6q0g9>>d2Is\xGºp P6('䵢P$i_IIENDB`plugins-1.5/generic/chessplugin/chessplugin.cpp000066400000000000000000000670121336777360500220570ustar00rootroot00000000000000/* * chessplugin.cpp - plugin * Copyright (C) 2010-2011 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include #include #include #include "psiplugin.h" #include "accountinfoaccessor.h" #include "accountinfoaccessinghost.h" #include "optionaccessor.h" #include "optionaccessinghost.h" #include "activetabaccessinghost.h" #include "activetabaccessor.h" #include "stanzasender.h" #include "stanzasendinghost.h" #include "iconfactoryaccessor.h" #include "iconfactoryaccessinghost.h" #include "toolbariconaccessor.h" #include "menuaccessor.h" #include "applicationinfoaccessor.h" #include "applicationinfoaccessinghost.h" #include "stanzafilter.h" #include "plugininfoprovider.h" #include "eventcreatinghost.h" #include "eventcreator.h" #include "contactinfoaccessinghost.h" #include "contactinfoaccessor.h" #include "popupaccessinghost.h" #include "popupaccessor.h" #include "soundaccessinghost.h" #include "soundaccessor.h" #include "mainwindow.h" #include "figure.h" #include "ui_options.h" #include "invitedialog.h" #include "request.h" #define cVer "0.2.8" #define soundStartConst "soundstart" #define soundFinishConst "soundfinish" #define soundMoveConst "soundmove" #define soundErrorConst "sounderror" #define constDndDisable "dnddsbl" #define constDefSoundSettings "defsndstngs" using namespace Chess; class ChessPlugin: public QObject, public PsiPlugin, public OptionAccessor, public ActiveTabAccessor, public MenuAccessor, public ApplicationInfoAccessor, public ToolbarIconAccessor, public IconFactoryAccessor, public StanzaSender, public AccountInfoAccessor, public StanzaFilter, public PluginInfoProvider, public EventCreator, public ContactInfoAccessor, public PopupAccessor, public SoundAccessor { Q_OBJECT #ifdef HAVE_QT5 Q_PLUGIN_METADATA(IID "com.psi-plus.ChessPlugin") #endif Q_INTERFACES(PsiPlugin AccountInfoAccessor OptionAccessor ActiveTabAccessor MenuAccessor StanzaFilter ContactInfoAccessor SoundAccessor ToolbarIconAccessor IconFactoryAccessor StanzaSender ApplicationInfoAccessor PluginInfoProvider EventCreator PopupAccessor) public: ChessPlugin(); virtual QString name() const; virtual QString shortName() const; virtual QString version() const; virtual QWidget* options(); virtual bool enable(); virtual bool disable(); virtual void applyOptions(); virtual void restoreOptions(); virtual void optionChanged(const QString& /*option*/){}; virtual void setAccountInfoAccessingHost(AccountInfoAccessingHost* host); virtual void setOptionAccessingHost(OptionAccessingHost* host); virtual void setActiveTabAccessingHost(ActiveTabAccessingHost* host); virtual void setIconFactoryAccessingHost(IconFactoryAccessingHost* host); virtual void setStanzaSendingHost(StanzaSendingHost *host); virtual QList < QVariantHash > getButtonParam(); virtual QAction* getAction(QObject* , int , const QString& ) { return 0; }; virtual QList < QVariantHash > getAccountMenuParam(); virtual QList < QVariantHash > getContactMenuParam(); virtual QAction* getContactAction(QObject* , int , const QString& ) { return 0; }; virtual QAction* getAccountAction(QObject* , int ) { return 0; }; virtual void setApplicationInfoAccessingHost(ApplicationInfoAccessingHost* host); virtual bool incomingStanza(int account, const QDomElement& xml); virtual bool outgoingStanza(int account, QDomElement& xml); virtual void setEventCreatingHost(EventCreatingHost *host); virtual void setContactInfoAccessingHost(ContactInfoAccessingHost* host); virtual QString pluginInfo(); virtual void setPopupAccessingHost(PopupAccessingHost* host); virtual void setSoundAccessingHost(SoundAccessingHost* host); virtual QPixmap icon() const; public slots: void closeBoardEvent(); void move(int oldX, int oldY, int newX, int newY, const QString& figure); void moveAccepted(); void error(); void load(const QString& settings); private slots: void toolButtonPressed(); void menuActivated(); void invite(Request& r); void sendInvite(const Request&, const QString& resource, const QString& color); void accept(); void reject(); void youWin(); void youLose(); void draw(); void getSound(); void testSound(); void toggleEnableSound(bool enable); void doInviteDialog(const QString& jid); private: const QString newId(); int checkId(const QString& id); void acceptGame(); void rejectGame(); void stopGame(); void playSound(const QString& filename); void boardClosed(); int findRequest(const QString& jid); void doPopup(const QString& text); private: bool enabled; OptionAccessingHost* psiOptions; AccountInfoAccessingHost *accInfoHost; ActiveTabAccessingHost* activeTab; IconFactoryAccessingHost *icoHost; ApplicationInfoAccessingHost* appInfo; StanzaSendingHost *stanzaSender; EventCreatingHost *psiEvent; ContactInfoAccessingHost* contactInfo; PopupAccessingHost* popup; SoundAccessingHost* sound_; ChessWindow *board; bool game_, theEnd_; bool waitFor; int id; QString tmpId; QString soundStart, soundFinish, soundMove, soundError; bool DndDisable, DefSoundSettings, enableSound; Ui::options ui_; QList requests; QList invites; Request currentGame_; }; #ifndef HAVE_QT5 Q_EXPORT_PLUGIN(ChessPlugin); #endif ChessPlugin::ChessPlugin() : enabled(false) , psiOptions(0) , accInfoHost(0) , activeTab(0) , icoHost(0) , appInfo(0) , stanzaSender(0) , psiEvent(0) , contactInfo(0) , popup(0) , sound_(0) , board(0) , game_(false) , theEnd_(false) , waitFor(false) , id(111) , soundStart("sound/chess_start.wav") , soundFinish("sound/chess_finish.wav") , soundMove("sound/chess_move.wav") , soundError("sound/chess_error.wav") , DndDisable(true) , DefSoundSettings(false) , enableSound(true) { } QString ChessPlugin::name() const { return "Chess Plugin"; } QString ChessPlugin::shortName() const { return "chessplugin"; } QString ChessPlugin::version() const { return cVer; } bool ChessPlugin::enable() { if(!psiOptions) { return false; } game_ = false; theEnd_ = false; waitFor = false; id = 111; requests.clear(); invites.clear(); enabled = true; QFile file(":/chessplugin/figures/Black queen 2d.png"); if(file.open(QIODevice::ReadOnly)) { QByteArray ico = file.readAll(); icoHost->addIcon("chessplugin/chess", ico); file.close(); } soundStart = psiOptions->getPluginOption(soundStartConst, QVariant(soundStart)).toString(); soundFinish = psiOptions->getPluginOption(soundFinishConst, QVariant(soundFinish)).toString(); soundMove = psiOptions->getPluginOption(soundMoveConst, QVariant(soundMove)).toString(); soundError = psiOptions->getPluginOption(soundErrorConst, QVariant(soundError)).toString(); DndDisable = psiOptions->getPluginOption(constDndDisable, QVariant(DndDisable)).toBool(); DefSoundSettings = psiOptions->getPluginOption(constDefSoundSettings, QVariant(DefSoundSettings)).toBool(); return enabled; } bool ChessPlugin::disable() { if(board) { delete (board); board = 0; game_ = false; } requests.clear(); invites.clear(); enabled = false; return true; } QWidget* ChessPlugin::options() { if(!enabled) return 0; QWidget *options = new QWidget; ui_.setupUi(options); ui_.wiki->setText(tr("Wiki (Online)")); ui_.wiki->setOpenExternalLinks(true); ui_.play_error->setIcon(icoHost->getIcon("psi/play")); ui_.play_finish->setIcon(icoHost->getIcon("psi/play")); ui_.play_move->setIcon(icoHost->getIcon("psi/play"));; ui_.play_start->setIcon(icoHost->getIcon("psi/play")); ui_.select_error->setIcon(icoHost->getIcon("psi/browse")); ui_.select_finish->setIcon(icoHost->getIcon("psi/browse")); ui_.select_move->setIcon(icoHost->getIcon("psi/browse")); ui_.select_start->setIcon(icoHost->getIcon("psi/browse")); restoreOptions(); connect(ui_.play_error, SIGNAL(pressed()), this, SLOT(testSound())); connect(ui_.play_finish, SIGNAL(pressed()), this, SLOT(testSound())); connect(ui_.play_move, SIGNAL(pressed()), this, SLOT(testSound())); connect(ui_.play_start, SIGNAL(pressed()), this, SLOT(testSound())); connect(ui_.select_error, SIGNAL(pressed()), this, SLOT(getSound())); connect(ui_.select_finish, SIGNAL(pressed()), this, SLOT(getSound())); connect(ui_.select_start, SIGNAL(pressed()), this, SLOT(getSound())); connect(ui_.select_move, SIGNAL(pressed()), this, SLOT(getSound())); return options; } void ChessPlugin::applyOptions(){ soundError = ui_.le_error->text(); psiOptions->setPluginOption(soundErrorConst, QVariant(soundError)); soundFinish = ui_.le_finish->text(); psiOptions->setPluginOption(soundFinishConst, QVariant(soundFinish)); soundMove = ui_.le_move->text(); psiOptions->setPluginOption(soundMoveConst, QVariant(soundMove)); soundStart = ui_.le_start->text(); psiOptions->setPluginOption(soundStartConst, QVariant(soundStart)); DndDisable = ui_.cb_disable_dnd->isChecked(); psiOptions->setPluginOption(constDndDisable, QVariant(DndDisable)); DefSoundSettings = ui_.cb_sound_override->isChecked(); psiOptions->setPluginOption(constDefSoundSettings, QVariant(DefSoundSettings)); } void ChessPlugin::restoreOptions(){ ui_.le_error->setText(soundError); ui_.le_finish->setText(soundFinish); ui_.le_move->setText(soundMove); ui_.le_start->setText(soundStart); ui_.cb_disable_dnd->setChecked(DndDisable); ui_.cb_sound_override->setChecked(DefSoundSettings); } void ChessPlugin::setAccountInfoAccessingHost(AccountInfoAccessingHost* host) { accInfoHost = host; } void ChessPlugin::setOptionAccessingHost(OptionAccessingHost* host) { psiOptions = host; } void ChessPlugin::setActiveTabAccessingHost(ActiveTabAccessingHost* host) { activeTab = host; } void ChessPlugin::setIconFactoryAccessingHost(IconFactoryAccessingHost *host) { icoHost = host; } void ChessPlugin::setStanzaSendingHost(StanzaSendingHost *host) { stanzaSender = host; } void ChessPlugin::setApplicationInfoAccessingHost(ApplicationInfoAccessingHost* host) { appInfo = host; } void ChessPlugin::setContactInfoAccessingHost(ContactInfoAccessingHost *host) { contactInfo = host; } void ChessPlugin::setEventCreatingHost(EventCreatingHost *host) { psiEvent = host; } void ChessPlugin::setPopupAccessingHost(PopupAccessingHost *host) { popup = host; } void ChessPlugin::setSoundAccessingHost(SoundAccessingHost *host) { sound_ = host; } void ChessPlugin::doPopup(const QString &text) { popup->initPopup(text, tr("Chess Plugin"), "chessplugin/chess"); } QList < QVariantHash > ChessPlugin::getButtonParam() { QList< QVariantHash > l; QVariantHash hash; hash["tooltip"] = QVariant(tr("Chess!")); hash["icon"] = QVariant(QString("chessplugin/chess")); hash["reciver"] = qVariantFromValue(qobject_cast(this)); hash["slot"] = QVariant(SLOT(toolButtonPressed())); l.push_back(hash); return l; } QList < QVariantHash > ChessPlugin::getAccountMenuParam() { return QList < QVariantHash >(); } QList < QVariantHash > ChessPlugin::getContactMenuParam() { QList< QVariantHash > l; QVariantHash hash; hash["name"] = QVariant(tr("Chess!")); hash["icon"] = QVariant(QString("chessplugin/chess")); hash["reciver"] = qVariantFromValue(qobject_cast(this)); hash["slot"] = QVariant(SLOT(menuActivated())); l.push_back(hash); return l; } void ChessPlugin::toolButtonPressed() { if(!enabled) return; if(game_) { if((DefSoundSettings || psiOptions->getGlobalOption("options.ui.notifications.sounds.enable").toBool()) && enableSound) playSound(soundError); doPopup(tr("You are already playing!")); return; } QString yourJid_ = activeTab->getYourJid();; QString tmpJid(""); int account_ = 0; while (yourJid_ != (tmpJid = accInfoHost->getJid(account_))){ ++account_; if (tmpJid == "-1") return; } if(accInfoHost->getStatus(account_) == "offline") return; Request r; r.yourJid = yourJid_; r.jid = activeTab->getJid(); r.account = account_; invite(r); } void ChessPlugin::menuActivated() { if(!enabled) { return; } if(game_) { if((DefSoundSettings || psiOptions->getGlobalOption("options.ui.notifications.sounds.enable").toBool()) && enableSound) playSound(soundError); doPopup(tr("You are already playing!")); return; } int account_ = sender()->property("account").toInt(); if(accInfoHost->getStatus(account_) == "offline") { return; } Request r; r.jid = sender()->property("jid").toString(); r.yourJid = accInfoHost->getJid(account_); r.account = account_; invite(r); } // В этом методе создается диалог, с помощью которого Вы выбираете цвет фигур, // и на какой ресурс отправить приглашение void ChessPlugin::invite(Request &r) { QStringList resList; QStringList tmp = r.jid.split("/"); if(contactInfo->isPrivate(r.account, r.jid) && r.jid.contains("/")) { r.jid = tmp.takeFirst(); resList.append(tmp.join("/")); } else { r.jid = tmp.first(); resList = contactInfo->resources(r.account, r.jid); } InviteDialog *id = new InviteDialog(r, resList); connect(id, SIGNAL(play(const Request&, const QString&, const QString&)), this, SLOT(sendInvite(const Request&, const QString&, const QString&))); id->show(); } //В этом методе отправляется приглашение void ChessPlugin::sendInvite(const Request& req, const QString& resource, const QString& color) { Request r = req; r.chessId = "ch_111"; r.jid += "/" + stanzaSender->escape(resource); r.requestId = newId(); stanzaSender->sendStanza(r.account, QString("") .arg(r.jid) .arg(r.requestId) .arg(color) .arg(r.chessId)); if(color == "white") r.type = Figure::WhitePlayer; else r.type = Figure::BlackPlayer; waitFor = true; invites.push_back(r); } //Этот метод вызывается, когда вы принимаете приглашение void ChessPlugin::accept() { stanzaSender->sendStanza(currentGame_.account, QString("") .arg(currentGame_.jid) .arg(currentGame_.requestId) .arg(currentGame_.chessId)); acceptGame(); } //Этот метод вызывается, когда вы отказываетесь от игры void ChessPlugin::reject() { stanzaSender->sendStanza(currentGame_.account, QString("") .arg(currentGame_.jid) .arg(currentGame_.requestId)); rejectGame(); } // Этот метод вызывается, когда вы закрыли доску. void ChessPlugin::closeBoardEvent() { stanzaSender->sendStanza(currentGame_.account, QString("") .arg(currentGame_.jid) .arg(newId()) .arg(currentGame_.chessId)); if((DefSoundSettings || psiOptions->getGlobalOption("options.ui.notifications.sounds.enable").toBool()) && enableSound) playSound(soundFinish); stopGame(); } // Этот метод вызывается, когда ваш опонент закрыл доску. void ChessPlugin::boardClosed() { if(theEnd_) return; QMessageBox::warning(board, tr("Chess Plugin"), tr("Your opponent has closed the board!\n You can still save the game."), QMessageBox::Ok); } // Окончание игры void ChessPlugin::stopGame() { delete (board); board = 0; game_ = false; theEnd_ = false; } // Начало игры void ChessPlugin::acceptGame() { if(game_) return; game_ = true; waitFor = false; theEnd_ = false; board = new ChessWindow(currentGame_.type, enableSound); connect(board, SIGNAL(closeBoard()), this, SLOT(closeBoardEvent()), Qt::QueuedConnection); connect(board, SIGNAL(move(int,int,int,int, QString)), this, SLOT(move(int,int,int,int, QString))); connect(board, SIGNAL(moveAccepted()), this, SLOT(moveAccepted())); connect(board, SIGNAL(error()), this, SLOT(error())); connect(board, SIGNAL(load(QString)), this, SLOT(load(QString))); connect(board, SIGNAL(draw()), this, SLOT(draw())); connect(board, SIGNAL(lose()), this, SLOT(youLose())); connect(board, SIGNAL(toggleEnableSound(bool)), this, SLOT(toggleEnableSound(bool))); board->show(); if((DefSoundSettings || psiOptions->getGlobalOption("options.ui.notifications.sounds.enable").toBool()) && enableSound) playSound(soundStart); } // Отказ от игры void ChessPlugin::rejectGame() { game_ = false; waitFor = false; theEnd_ = false; if((DefSoundSettings || psiOptions->getGlobalOption("options.ui.notifications.sounds.enable").toBool()) && enableSound) playSound(soundFinish); doPopup(tr("The game was rejected")); } // Вы отправляете вашему сопернику сохраненную партию void ChessPlugin::load(const QString& settings) { stanzaSender->sendStanza(currentGame_.account, QString("%4") .arg(currentGame_.jid) .arg(newId()) .arg(currentGame_.chessId) .arg(settings)); } // Вы походили void ChessPlugin::move(int oldX, int oldY, int newX, int newY, const QString& figure) { QString stanza = QString("") .arg(currentGame_.jid) .arg(newId()) .arg(QString::number(oldX)) .arg(QString::number(oldY)) .arg(QString::number(newX)) .arg(QString::number(newY)) .arg(currentGame_.chessId); if(!figure.isEmpty()) stanza += QString("%1").arg(figure); stanza += ""; stanzaSender->sendStanza(currentGame_.account, stanza); if((DefSoundSettings || psiOptions->getGlobalOption("options.ui.notifications.sounds.enable").toBool()) && enableSound) playSound(soundMove); } // Вы согласились с ходом void ChessPlugin::moveAccepted() { stanzaSender->sendStanza(currentGame_.account, QString("") .arg(currentGame_.jid) .arg(tmpId) .arg(currentGame_.chessId)); } void ChessPlugin::youLose() { if(theEnd_) return; stanzaSender->sendStanza(currentGame_.account, QString("") .arg(currentGame_.jid) .arg(newId()) .arg(currentGame_.chessId)); board->youLose(); theEnd_ = true; QMessageBox::information(board, tr("Chess Plugin"), tr("You Lose."), QMessageBox::Ok); } void ChessPlugin::youWin() { if(theEnd_) return; if((DefSoundSettings || psiOptions->getGlobalOption("options.ui.notifications.sounds.enable").toBool()) && enableSound) playSound(soundStart); board->youWin(); theEnd_ = true; QMessageBox::information(board, tr("Chess Plugin"), tr("You Win!"), QMessageBox::Ok); } void ChessPlugin::draw() { if(!theEnd_) { stanzaSender->sendStanza(currentGame_.account, QString("") .arg(currentGame_.jid) .arg(newId()) .arg(currentGame_.chessId)); if((DefSoundSettings || psiOptions->getGlobalOption("options.ui.notifications.sounds.enable").toBool()) && enableSound) playSound(soundStart); board->youDraw(); theEnd_ = true; QMessageBox::information(board, tr("Chess Plugin"), tr("Draw!"), QMessageBox::Ok); } } void ChessPlugin::error() { if((DefSoundSettings || psiOptions->getGlobalOption("options.ui.notifications.sounds.enable").toBool()) && enableSound) playSound(soundError); QMessageBox::warning(board, tr("Chess Plugin"), tr("Unknown error!"), QMessageBox::Ok); board->close(); } bool ChessPlugin::incomingStanza(int account, const QDomElement& xml) { if(!enabled) { return false; } if(xml.tagName() == "iq") { const QString xmlType = xml.attribute("type"); if(xmlType == "set") { QDomElement createElem = xml.firstChildElement("create"); if(!createElem.isNull() && createElem.attribute("xmlns") == "games:board" && createElem.attribute("type") == "chess") { const QString xmlId = stanzaSender->escape(xml.attribute("id")); const QString xmlFrom = stanzaSender->escape(xml.attribute("from")); if((DndDisable && accInfoHost->getStatus(account) == "dnd") || game_) { stanzaSender->sendStanza(account, QString("") .arg(xmlFrom) .arg(xmlId)); return true; } const QString color = stanzaSender->escape(createElem.attribute("color")); Request r; r.requestId = xmlId; r.chessId = stanzaSender->escape(createElem.attribute("id")); r.account = account; r.jid = xmlFrom; r.yourJid = accInfoHost->getJid(account); r.type = Figure::WhitePlayer; if(color == "white") r.type = Figure::BlackPlayer; requests.append(r); psiEvent->createNewEvent(account, r.jid, tr("Chess Plugin: Invitation from %1").arg(r.jid), this, SLOT(doInviteDialog(QString))); return true; } QDomElement turn = xml.firstChildElement("turn"); if(!turn.isNull() && turn.attribute("xmlns") == "games:board" && turn.attribute("type") == "chess" && game_) { const QString xmlId = stanzaSender->escape(xml.attribute("id")); const QString xmlFrom = stanzaSender->escape(xml.attribute("from")); if(xmlFrom.toLower() != currentGame_.jid.toLower()) { return true; // Игнорируем станзы от "левых" джидов } tmpId = xmlId; QDomNode node = turn.firstChild(); while(!node.isNull()) { QDomElement childElem = node.toElement(); if(childElem.tagName() == "move") { QStringList tmpMove = childElem.attribute("pos").split(";"); int oldX = tmpMove.first().split(",").first().toInt(); int oldY = tmpMove.first().split(",").last().toInt(); int newX = tmpMove.last().split(",").first().toInt(); int newY = tmpMove.last().split(",").last().toInt(); QDomElement promElem = childElem.firstChildElement("promotion"); QString figure = ""; if(!promElem.isNull()) figure = promElem.text(); board->moveRequest(oldX,oldY,newX,newY,figure); if((DefSoundSettings || psiOptions->getGlobalOption("options.ui.notifications.sounds.enable").toBool()) && enableSound) playSound(soundMove); } else if(childElem.tagName() == "draw") { draw(); return true; } else if(childElem.tagName() == "resign") { youWin(); return true; } node = node.nextSibling(); } return true; } QDomElement closeElem = xml.firstChildElement("close"); if(!closeElem.isNull() && closeElem.attribute("xmlns") == "games:board" && closeElem.attribute("type") == "chess" && game_) { const QString xmlFrom = stanzaSender->escape(xml.attribute("from")); if(xmlFrom.toLower() != currentGame_.jid.toLower()) { return true; // Игнорируем станзы от "левых" джидов } boardClosed(); return true; } QDomElement loadElem = xml.firstChildElement("load"); if(!loadElem.isNull() && loadElem.attribute("xmlns") == "games:board" && loadElem.attribute("type") == "chess" && game_) { const QString xmlFrom = stanzaSender->escape(xml.attribute("from")); if(xmlFrom.toLower() != currentGame_.jid.toLower()) { return true; // Игнорируем станзы от "левых" джидов } board->loadRequest(loadElem.text()); return true; } } else if(xmlType == "result") { const QString xmlId = stanzaSender->escape(xml.attribute("id")); if(waitFor) { int ind = checkId(xmlId); if(ind != -1) { currentGame_ = invites.at(ind); invites.clear(); acceptGame(); return true; } } } else if(xmlType == "error") { const QString xmlId = stanzaSender->escape(xml.attribute("id")); if(waitFor) { int ind = checkId(xmlId); if(ind != -1) { invites.removeAt(ind); rejectGame(); return true; } } } } return false; } bool ChessPlugin::outgoingStanza(int /*account*/, QDomElement& /*xml*/) { return false; } void ChessPlugin::doInviteDialog(const QString& jid) { if(!enabled || requests.isEmpty()) return; int index = findRequest(jid); if(index == -1) return; Request rec = requests.takeAt(index); if(game_) { QMessageBox::information(0, tr("Chess Plugin"), tr("You are already playing!")); stanzaSender->sendStanza(rec.account, QString("") .arg(rec.jid) .arg(rec.requestId)); return; } currentGame_ = rec; QString color = "black"; if(currentGame_.type == Figure::BlackPlayer) color = "white"; InvitationDialog *id = new InvitationDialog(currentGame_.jid, color); connect(id, SIGNAL(accept()), this, SLOT(accept())); connect(id, SIGNAL(reject()), this, SLOT(reject())); id->show(); } int ChessPlugin::findRequest(const QString& jid) { int index = -1; for(int i = requests.size(); i != 0;) { if(requests.at(--i).jid == jid) { index = i; break; } } return index; } void ChessPlugin::testSound() { if(ui_.play_error->isDown()) { playSound(ui_.le_error->text()); } else if(ui_.play_finish->isDown()) { playSound(ui_.le_finish->text()); } else if(ui_.play_move->isDown()) { playSound(ui_.le_move->text()); } else if(ui_.play_start->isDown()) { playSound(ui_.le_start->text()); } } void ChessPlugin::getSound() { QLineEdit *le = 0; if(ui_.select_error->isDown()) le = ui_.le_error; if(ui_.select_finish->isDown()) le = ui_.le_finish; if(ui_.select_move->isDown()) le = ui_.le_move; if(ui_.select_start->isDown()) le = ui_.le_start; if(!le) return; QString fileName = QFileDialog::getOpenFileName(0,tr("Choose a sound file"),"", tr("Sound (*.wav)")); if(fileName.isEmpty()) return; le->setText(fileName); } void ChessPlugin::playSound(const QString& f) { sound_->playSound(f); } const QString ChessPlugin::newId() { ++id; const QString newid = "cp_"+QString::number(id); return newid; } int ChessPlugin::checkId(const QString& checkId) { int index = -1; for(int i = invites.size(); i != 0;) { if(invites.at(--i).requestId == checkId) { index = i; break; } } return index; } void ChessPlugin::toggleEnableSound(bool enable) { enableSound = enable; } QString ChessPlugin::pluginInfo() { return tr("Author: ") + "Dealer_WeARE\n" + tr("Email: ") + "wadealer@gmail.com\n\n" + trUtf8("This plugin allows you to play chess with your friends.\n" "The plugin is compatible with a similar plugin for Tkabber.\n" "For sending commands, normal messages are used, so this plugin will always work wherever you are able to log in." "To invite a friend for a game, you can use contact menu item or the button on the toolbar in a chat window."); } QPixmap ChessPlugin::icon() const { return QPixmap(":/chessplugin/chess.png"); } #include "chessplugin.moc" plugins-1.5/generic/chessplugin/chessplugin.pro000066400000000000000000000010511336777360500220640ustar00rootroot00000000000000isEmpty(PSISDK) { include(../../psiplugin.pri) } else { include($$PSISDK/plugins/psiplugin.pri) } RESOURCES = chessplugin.qrc INCLUDEPATH += $$PWD DEPENDPATH += $$PWD SOURCES += chessplugin.cpp \ figure.cpp \ boardmodel.cpp \ mainwindow.cpp \ boardview.cpp \ boarddelegate.cpp \ invitedialog.cpp HEADERS += figure.h \ boardmodel.h \ mainwindow.h \ boardview.h \ boarddelegate.h \ invitedialog.h \ request.h FORMS += mainwindow.ui \ options.ui \ invitedialog.ui \ invitationdialog.ui plugins-1.5/generic/chessplugin/chessplugin.qrc000066400000000000000000000014651336777360500220620ustar00rootroot00000000000000 figures/black_bishop.png figures/black_castle.png figures/black_king.png figures/Black king 2d.png figures/black_knight.png figures/black_pawn.png figures/black_queen.png figures/Black queen 2d.png figures/Chess.png figures/Chess board.png figures/white_bishop.png figures/white_castle.png figures/white_king.png figures/white_knight.png figures/white_pawn.png figures/white_queen.png chess.png plugins-1.5/generic/chessplugin/figure.cpp000066400000000000000000000061331336777360500210110ustar00rootroot00000000000000/* * figure.cpp - plugin * Copyright (C) 2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "figure.h" Figure::Figure(GameType game, FigureType type, int x, int y, QObject * /*parent*/) : isMoved(false) , positionX_(x) , positionY_(y) , type_(type) , gameType_(game) { } QPixmap Figure::getPixmap() const { switch(type_) { case White_Pawn: return QPixmap(":/chessplugin/figures/white_pawn.png"); case White_King: return QPixmap(":/chessplugin/figures/white_king.png"); case White_Queen: return QPixmap(":/chessplugin/figures/white_queen.png"); case White_Bishop: return QPixmap(":/chessplugin/figures/white_bishop.png"); case White_Knight: return QPixmap(":/chessplugin/figures/white_knight.png"); case White_Castle: return QPixmap(":/chessplugin/figures/white_castle.png"); case Black_Pawn: return QPixmap(":/chessplugin/figures/black_pawn.png"); case Black_King: return QPixmap(":/chessplugin/figures/black_king.png"); case Black_Queen: return QPixmap(":/chessplugin/figures/black_queen.png"); case Black_Bishop: return QPixmap(":/chessplugin/figures/black_bishop.png"); case Black_Knight: return QPixmap(":/chessplugin/figures/black_knight.png"); case Black_Castle: return QPixmap(":/chessplugin/figures/black_castle.png"); case None: return QPixmap(); } return QPixmap(); } QString Figure::typeString() const { switch(type_) { case White_Pawn: return "Pawn"; case White_King: return "King"; case White_Queen: return "Queen"; case White_Bishop: return "Bishop"; case White_Knight: return "Knight"; case White_Castle: return "Rook"; case Black_Pawn: return "Pawn"; case Black_King: return "King"; case Black_Queen: return "Queen"; case Black_Bishop: return "Bishop"; case Black_Knight: return "Knight"; case Black_Castle: return "Rook"; case None: return QString(); } return QString(); } int Figure::positionX() const { return positionX_; } int Figure::positionY() const { return positionY_; } void Figure::setPosition(int x, int y) { positionX_ = x; positionY_ = y; } Figure::FigureType Figure::type() const { return type_; } Figure::GameType Figure::gameType() const { return gameType_; } void Figure::setType(FigureType type) { type_ = type; } plugins-1.5/generic/chessplugin/figure.h000066400000000000000000000034751336777360500204640ustar00rootroot00000000000000/* * figure.h - plugin * Copyright (C) 2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef FIGURE_H #define FIGURE_H #include class Figure { public: enum GameType { NoGame = 0, WhitePlayer = 1, BlackPlayer = 2 }; enum FigureType { None = 0, White_Pawn = 1, White_Castle = 2, White_Bishop = 3, White_King = 4, White_Queen = 5, White_Knight = 6, Black_Pawn = 7, Black_Castle = 8, Black_Bishop = 9, Black_King = 10, Black_Queen = 11, Black_Knight = 12 }; Figure(GameType game = NoGame, FigureType type = Figure::None, int x = 0, int y = 0, QObject *parent = 0); QPixmap getPixmap() const; void setPosition(int x, int y); void setType(FigureType type); int positionX() const; int positionY() const; FigureType type() const; GameType gameType() const; QString typeString() const; bool isMoved; private: int positionX_, positionY_; FigureType type_; GameType gameType_; }; #endif // FIGURE_H plugins-1.5/generic/chessplugin/figures/000077500000000000000000000000001336777360500204655ustar00rootroot00000000000000plugins-1.5/generic/chessplugin/figures/Black king 2d.png000066400000000000000000001234011336777360500234070ustar00rootroot00000000000000PNG  IHDR\rfIDATx^*]bEj%"jL-[_&jKDQc?M,DFc,(Ŋrg~//3{Ȟ9ΜsST[UloڪھVjVjVjVjV___ٳg'fJ>[U_|@p 6mZךUjkk[Yx<d޼y:tePo0/HfΜYeU`o+rw#3o`ks ۶m;y喫3p7c `WL| px㍗W~kluoХKg|oN8{sSMzmߛkuIVe;pܹd#Fjoϴϭϰ>;i: *,íwޛ? /p;ޟr)~_:)}¿`Ӥ$UX&Z7nSO=5O~j*MLo. .H~_ &˭OMm[֧O-O;FtD~/GKԀwO>m[ |W/1>3Ǎ4>$s=7=oG[?>=2Ѫ޺棏>_bD :G?Q#i^袋y/hA TKy2W3uԁoÇ''tR&/g?YzBG^zӒ*, hvmkoF#}~FPe]?Mϟvi+<]v>*, Hmҹ9sf*wС78f̘G5!w@+I tݻ3I^Ry/rVm5'O^[n]SW3o޼۴iS駟n%wJW]uUj,`/+5Kmv?uL>T* , KQp [;v]1yԹsp'GuTJYp&gqFO'Rp`y$nr뭷&/o15\3Y_zIC RAb&- KWx]vzѣG'>h}ywH1[ zжr˴?Sz衧%I!jتvک#oo#iݺucx?]^cqMP E{왬Z%ITV 6fԨQc=@ݣD9q( @=s3 :oZ/iK`Rvmڑ#G{~_O$ƍKu=0'|:'N#[)iH "PU;֪4HO>d ]t_>vLـs?8ySP4h`u8ߓ!bH#@V2`ͧz*N: Ĉϙ3'2e ՂR6pL ֟=$X"[6lذVFj?)tq!q6,# !>,?0`H!ܪ4#V<@ |gRXuU <@iӒO>$:uB^_~)aUX[۶=zt#MC ><1@4}9bj:lfiJK_R駟Ȉ/gM^uƒ޺E|eчXRw g}&nib_,e KI3}饗1q{8`w8|@ ~;C]W.,[o=f~`hUXJ_k^ݱm۶)׿۾{]z:7k֬nȑ )"RX Zֳg}Iҁ;Y_z;mi/ ;KCo:,z}=iCKARL$1m=eʔ7zwY_r @̀_t]wUo ߇x?K2 ]^ _X Z֡CSNCHݬwIiMpaWRL-6lXz~pmJ@ p r>8G ~&lU`)jયom}y{$!i,uvGl p}|_OӣǏMIA^ _zy=D_*,]˗rɗ^7~?? yvq"?: 4pu8mRUs_VIoͬ K@0K-?O!`CǗNﹺ@.՚Kpj"=m+LӦM L"T@Taw 3v8}j[[8/<5jO>pwy)B3cUK}>fկR֪7޸?8a "c@'g}`tvJ[-3 x__\Ӌ_s5K,ߟA?/ D-ph[o]|/6(=4vĉYVgK >(.ҮI<-GB.)={kjs9{֧n9s9cƌW-ٖyE\bczO4CpLV]u6Jvڵ^iZA -xN]7mڴԥ5uy_|k=zL֭۬;5|n=}9{7pܸq6c~<'}=sb6@m}i;iҤO<yA+rVXՊ+تm۶%ۑga>Sz@O<|Nyt-`#1VMYf@a3<8*[na6-Fmn.Zk#{wb`4ۢ,f33fTB3'O<۶޽Ν;z٢o@Xlh #҇w6T 0Z6mڤ:묓/I=LX;̵k~5/*FCW_} h7_Um|` rPsHipwSsLRO~ls@iI L>0`̧Xc=T2P2ooao[_uj;v6bX8b'̵,*>>E0*Of"(kljH[LtiBg­$of-^L!ih?pi$ @TT 7<@?T&連d3@`vhcih޽\wu{0we%üO􀙯gUS8 |xG>1uOJ?j5xa- v$~_&-]]wݵN;7.jC6k1-TLcvo1W^^߼` w-:#:uјD9?}we b(mߝZC@ Y}1TOMzΟrC*h&17xk#Ld:j6_` UW]u-0tE^4t5"aNc99*"ڵkJ8 l*{@T~oq 柈SfkhkuofF웛8l785S 84jf|lWp>\7̽?[>$*򾤡l\[R xWx X`Ȑ!Lg=M}I'9tP,!}z"$a @`\}-qҦxL#n@qv˞o֧rfۚ*nܱ۳xJ+}il_*?5MJl'&E҂Inᆉ듬O5HAr[M4i3#Cm.{ B! e{vHۧy9=5j/c%tMjkkv=OPi "U 2LKո}j\J=/,{0^E~47s^ ^PUu6FxoKxNژ5u/LZ"!xojzꩾ&~mĈk6MTzaT[HX8p;[-=bN­$ʳe/r (a}bQ#ClS qA#}'noۃ>Kɮ? %#8TZXĘ<ӍhsiW$ c1Wo`u4`[ZBs*M&W,]|SOC0ACAgoCe8TEOjbg~${6?'  9HxH% ,7t&;>S{mǧP @Db"c_0Zx% -8]` ; d;o#<4/Knf̱kàHtyS)y8r]1>2F_.QҐ5I栧gwkf߾}X1%]EHdsN )M?cLMR V58Ac I}pWLsw% 1DtgD 'pB͝w޹噃 |Ek}ץpuTfANeU qTEM: )@n-l7ɓ0bT~-u#tM_3Yޮ.=3?jWO?l1GTF4=q/B|ޕW^I@.ҋJ>C}^7E{RkC'.u|Qʹq}@S"~OwǯG-0n<'NH$؆*ptfr){9\xOY޹s9.GT{Os%o2&;nÇc6$pBi,8<" |"Ey 0 HH*`iݒROL޷|.yuڞnđZ߿[{F컞}Huv]\zY 8(^Hǝ뮻>{ "D-a=^|6y뭷>bv=`iL$'zcD}e9' GST*&(w^}ΖTY]v[6Dq0B9𪫮`С.? <;՚x Cek؋|G"'` 廤ߕ*of7ucGl\|u _„ d \rIbbuZӏ?rc=Bpp~l#FAl H&!̻4 s?Έh}wc#ʗ5$v'q^Gr߉}/l8@6f(0+zSɾ8餓&s A4`ߩ3FƱ:{gZ_}}Bx^?jԨ8gw-ȳ:k˱Zpz#S_oMO{3P LD7<ԣn:PC %X+q ~2Zb,ՂfSR)ԀO ,,#aw7b/{Rﭶڪ5sKW9A69rBxL!S[@֏T&-?ࢤ4ـAa$4m ;G9@anFcSogC==$^I^gjAcרhc@Gĸ3mld$G֌3£:jO[XkĔ/ ;D=ȲwrAp~Ip`ƙTlRLG' ۀR='S;5x5>迸>C+ǝZZ 3,FB)I,ѿo6:1vHM~ƍc.HT/Lzew|b[tv&lfFG;z%$}+Cc<:քUJY\'+ܔbu du^~O2baѐG㵿fziN;-M1A('toR L3O-ϻ[ lBt igo|kݑ+V>,cwb3"s΋'X`x.&!Hoy Sڳy_2HNۜͲ%*Y@J #_bD84fŏw ȇ{*ܗW21zY,t MKdB%OQxX/Ln}lѝla\O&!*JNrtPoճȺN!P[[o4.j ~CI; {6<(J*:1 )KP`rx=o†ctm5 :4cI;ZWg7x(>ge82-XkơVc7tS_Rt5>) _LfPbp_-|.D'']]N,h X͉}=ƸH^ʢX@܃Rse0"wO4t]XQ/Ywuu%i"\dϫո]wu칵 8)+*X T1Io\:R)}?ewQ.*LS:o;Ju(1&ٺF"J[s5gUVJ8^[ȿٳFlR[k5Lt&'ɍ"2,tbc0cc\ ]h|ʁ 7GYbboH \plcQ$O<V[m5kY]䤓NJT}1Ix~R u9@(:SOfx,暮6lә="8>@µxc(r1q93DbJ9':ǒb!1w vWꀭ{DC$@WL\2-.hc@`~묳N-B ( 8[2~t(+\~YҙЗBl6i'(:eKU/mPk ֐ߵ xgS &AT,t|pX'L+]r%k92ɒL~Ar-;]RA8<]٦bb'{Z\ M1 m1 \To'M4߮|)B޾34z'#뵼֚$AZkL'K"cP<+ƌSxI"QwQ*iAX`?~ ^xa?X)} ?) +)G &Z&GjުPyKV #l3m&~?<luk9[nӧOV,$\dB 8 "`j³[`Ww-|ך e]s1i?E4dڇë~x;{^EScxp:$7f csK\͉̓_H%+:]Ӛ-[mkkPYX?J%[0kQc\) -4?Lʝ_zuRQȴ`o8F$|O:7<ú(]Qq"~t&!]<|3Dw7\ 6?Y%@Hv%9Uri'5׾vm z! R RWZP66uq|/~10Ϸ y2({zpCũ3 [EH &R }8>y <+W^y^sR~ߴRQoEƜ4lu4EC].XH&AL22&Ht$q%s4 S#+ W]u S ˒02-1 "Ӳ@`}M $l)BRO qg> 1Hhp*3 p:z5 W]cWIHИ|oyҭq5Ŧeع?;nGyx^ EI"e.YL;c-i@@!tkoC2PLZ,@T|q$ q7^Wi<1!;@¹d @i3I2$ :cEi䩮^ @!zN{RH”mE,si!ިf4Ƈ5&}:2 vCƂ1bԧ~&6}~9zT3& Z鸕6@0P(ڌO8@h+ojmy뭷^qc' (S,Nxb`'$?AA=tnb@+$/ ś΀ʍ]O!okN@|Ǹ=u62RGW;=8"&=w;$Aᑴ0cٙ_2 f/5!ʁ*)e &LK2D?kvsJR@@AĞin?%$xWWR 8beɕGd4 #(RZ%"ȓ 'oIPWSHD5X:w6lX>} bIhTbx1x6J uQ3tA)Y_*C*t4ъ{3v|.0dB jTrL׿EQMwhGJUS[3bJ!u s_ ۫+<ގ$)JF<WI]cd gTsF^!@@cup Q/T)vLEi-FL?Obmx|{428y"?)z2XI3L< B> tٔ;)csiԶbQ"ݔ4T,+ m}Lloo\" A*oJ\C@_ByV>}2b -ޣ`ƀz|c0,֩xN{o't_* 3,R@@Ƈ5Z@E)+ O٫(R]w55IC{14,- !قa'  1=cPUȬh-Z(2[cM!XNa\\ƂQv|D@ߵ+iUy HPmj:k֌"6yb' }vaIxr)xY .㝏诨= $GYtBY#.WvT1DK~i_> 1Qַ` U Ih3/"7A+tNh'IOa<e)@6 擺 T?OغEb@0=3hBgrYS`X>b[_C PX= *#n*0c&vIO #!bl?߲gۯb*ӊ\o~K^wu)c7E@|V ݣOcq0>۳*O*Wt~3A( u] :&u}1지hbՃ_%l9sj|QF~1' *ɂ]Eh1X{;СC}];P4Ps|;@a(CDFrS gY:> U&ۃtH B$Ozr嵐6g; 7.aևh =c'"5[zgqqOW_}uczV $],]t0 PGp_G#vb>_wFba68k'c )I\D"v_`|NcoXئ0J1Qc1F;cw>^Kc Eh2dHL>DAP9%`tfY+qT 9ҁ%nkhPC;6Eх.Pz1P<"9 \k#3㯷kW(BPpoawc=VU.\|Cկ~.)0ʰIqCXXvBng+<;(c'P^",xԕB &'lY?F{@Nr2ԉE%^em=@1 JHİxfX lT\G2|K3Ƕc>z$i(2 i) $ ђ6ak¹r`;7XEߐ1p~,H W\qEO?0 GWQ.Ah T 24>C u9^@Ipd{>I0_T._z=#RĢb /plrC^G÷o,$ D}:sOęv0fBD4 ^D!C`a B(B:R|Saf*}+<(og5bXDDy衇f8R"?%6hEkhwN=ԁfiUA Y|qL0?ߗ҉Ui'\avaQ8"Yť"0Z~Zзo$X! _Z `6bZ"eS760, ]x3Zdo>(@@::Fx\ܛU.1?(woy`1ZzڅH 5f]s (w 5EQRPxUwNŸ $4;[x߾+Mj\G4R W\Awd!wK Nh#~Eka0F-fJ"_^ҥL.~o$ 4,M$/ۘh !݀5׿Q""#yi^8p~,%bDK1^`<WUɉ\Y~y,, U>PGPKP8BԦʥk ` E ]O?,">(1aH$4+l6lyMA{5Ta"+Op"dXn)<87pQ N?y@({C!qa(xM}6T$ ouR oں& @˛H'~E O% =7Cw,؇EWp};;Yzp~Y%PZo;G`Y06㎷/Ыo1UT%$|c k Kx?P3i # T>g SOl^1! Rj"I l ~> vmW1`5$,1џ" ~)NB[/s慅g\~5p2f>˔&q%iͯS$MLb1fw2%$JR p\eϺY uE_)$B 191{-+U0 3)cwxflAM?`H;&M3XilS?X;[nG|Ƀ?O\E&s?-L(c@   c0P' A.E=$fsM! $68D5Lr CܥZT3{Kry1y0A_qo:^Wڜ²=26Ćza{_I8g Yvp 40=հ8(qĻkq%J0&M\?Sxa*lY - /vذa_7) P81XN` , ʈ yꀈW- k`k "4"q3s 'u!~o z~ `Ja% ݗT@"ܮuo x|,C wbV뉥{C<ƭ™2NJy6bȒaIͻ%512*)ɨʵpHȌm"[{P!').CH[:FQ,`ܸ'Dٵ/B?fXIq`f5cn|QAcb0T4zH"6#c:t ~\<=SMoEK\_`srˬ >08I `)ow=af@2I'~\K\ uTsyfScq!>~Ş-P91j2a$zu#G$KcMUͥ|{G?1J_`C 5he-jŦ//,&iyy6qr=r * $_@8lu73-~D:p(ČPY?p gpǖ^VYe^r0"k4c׏m PT ^i40"2)HzJ-!Šh;PR@{i%S^ldt]v^Da@L b"T xgީ<&`X+g%OSJ҃}2p+Ժ g??%SZaFaN D~w~Ot+b˄ޠP `^e!8c4Oa,H[H &6dO[+ǐ {q'5ryk0JॄXOkŶ CP U z)sG. `' +%np^(4U08,*ěs RNšGϴ_MROj}}_f,|!5b@7VcC2$Dya^]Gu206I h`79-BRj-"Rˎ%rM>F_a_(o!D4=Pl|g< ` &zun=<;W @lcvp'%R@/`LyOCͣi{Db.TwwLSPL@EހEۮGy~}Am"!GE8 tƪm&@{/P ( BbcY">sT4b8`p@|g0y@<hsPﳖ]w5$@b!f2w8' CgVfg|5:r9ņjBGVpyg'%W?@jYw },T#00yl#YC5T9PnI ^QPP_{'ŶTѤ(zs6IeePD\k^XW}GǶ7& xFeypJ a\X\`0iacg}{_gF$@?@PG[|1KJ[oErzQȓb!>0Kt!|\H;Dž݁>hͻY| ~7Cf %6P6a6>-yk&$/Bih,Xα|$5Hpd/,?#d@LL,,&?tj\^xe1=#!6Nމ'+c!1Iޘ7 * Z|"l/ 9²yR]Kzyn<)ZӼ2VMtpoHcA5j ׆kXtڿy睟yd4Dc4L1M6dC9dc- dp 0 R]P X3< $XV`( bR,^H {=hIM\cx} @Vt@E+$zj5gns1xy?$~{k./&>b- cvXdb0@`tqWY=h}h+ѣGxQdh2ׯxn{؃hz=4Nj{ ppryx!%9 BsHY % _=&,Æ6pګz[EFzyW٬"zfU 1tT:- H?º~^SgV,L+uYs 3~^ӎ{@ހx4E;vR`1B[L\߽{$٢ϋKZh* A0bzE,(l?`^Q`Q;@H^ h(\ y<?Uρ(O? 7ܰkPX #0@:["d[}yKH 4Hy>Lr 9-$Nn [@{pOX,,XR!Y5 ~> ǧJ&Zk{8d%ւnͫ"U60(]pci|Cg%d V.V@E`V p0o{c9&U WRaGve*@+0uO{ P=a9c_zP<AAosR4 %0C I9gJl&|M0(T*`-6<vmKc%d-XWiƇz/O#@8b\ ¯r! @ަ(1^8}ޞݐ0xʒr0Ds=1܋S@8aTȾ5?onxH({ $]x8W% Y`>ce \$`dTВFaqHRgDIbU.@H`X@+%IJ=l62^Z"X垰\rb@^XwVWLϚr_h^DVUBL k-_o Bdx!O@S :C YwP /2,A F@,&xX2]ڡHp9QQ)RcOz<\Lt#Lm\{U M8³%T!R{ ]H z1Ld1D++r̸ OzW\W^y?\x 7 zaÆNJN8 t{jIV$|T}(\Y@j\*ba!d|/@ JqoPCcEA<ѕg/͗+Ԫ1B :Ẹ!jX`(s+L [}PHks_~eo% $+IЫWyߙ?t5wFjAxϏ/r~ П-JctfqRAu=Y*TU ݀2І{PB`Ii/щ؄FD Yƿy*U20/ ԬXN@ PȻ0gK+P3b=e-\ DЏI Cy#= ;&f(\$`tѬV4.@ Gsz0I%AT' bq&,r)cUVkU:<J Tv%cs1?+B1 .O T]LOqx@>1@gG0F@6e flͺ+%앆nsu~,2H(pVPLyᢱ,@=RtF$ 1^li U+7mAWF^Tw! p,7:X1vxU2M>nCE3,81URJ4 zOz&t>Յ\!0CMF! *)cb뫒`xu\.Qi H crIGE ]ɳ @82j9s+%fyBœ%Z0 8F'ʝ@>r x3DZE  #ii L C߿;i胁Z xG2sU C-ԋaÆy1a*H_>'8R4\D`O@@ȓb&YLS#Çt4ZUh+cMzXd[hOA04 Gye)oXY,5fRgjI҂F6 ZknoG}tU拈@"csn+ =6/BCSrj@ vJcUE:bl<4q6PJZ@6W24uQiJl/~c}욱V@+0W%xb@ ]$X?^*G- rqmfz`n)G0< ?^3 fa% j-+,o,*Z"-* #F2N$ {ㅜ1vܖ h)P>6ëBb@:ˍ[pc2Ba,@F򻰲5fHG7?Gv4|#*DrV ET 䍀,1$+i$БPN e@  | E@Db?*JAl1|n@}e #{HpX Յ(J܏<w+ )YJ ʕ?*$Lw P@td VOkCЬp{Q1% 3\8X@+cmX\`,$dITK<9ZkvƼ,c PD Ȼn9[N+*#Ÿ~,=8-JB/J d ࣏>B@7YX5XvxᇧF@j b#h0cT0UȪ_$[+O%(rb* DXyf8rd#q>8K~w0afO9 <N!4+ +;Pk^B>K {TF@;x<_@@G?tA["n@Ԃ6^ S ˓B ~E bk}y@lcYcDG"Toņ"-()Bxv}/JYnVCXRYl|GT84BAE7yE <krϊȪm<D ߼65{gܗ4bd?@ jr[S aA5q2RH*5[y ..uK1p"gI8:܃Jiґc෻'B.9X/r<) ~F齡/2PϘ@|qDJ~!G=D1 -oٳg;cr &/—i|:jK \y?Yaڠ25_d1쏳@v!xQ#-4#~cQ j·/B@ 1bq[ ojY9), 0@,%YctK+`X]*\ @c+B@.$Z\s6&\>tL(1F,Cـ??\/s~y"9jZΘhL YBO6@>I"ʲhaZa]P @7~I"r)W/kxf8(4 DHN\7 0t3O *837vXdah8ɗ8qoMLӁI" (D+1/Kz)䀹[gy*Dh%X-dθ#곈31)Sd+އF@,de%jCznYDZqo21 &n?gE<3gyB f @e '~qr $hҳ$?? =ꫯ[6 [׿t=oyyxBHY0|o >W}/mb? c #(?v<54`OvªQL#0wc,78/ h!:qZ,d^rL^bE7ƪ<{/O<@оU^XoIl++&Pt^{ z%sl[-}< ૤8W0T |G @>F ߋ ol]Ap/(#$1‰{ hGҀs<skX)A < |0Qll6 /C - E]:Ɨ KP ꨅ*_ꩧPVd- $0ݯkw38͹:}.~:&v'H-r C ?ﳳ{Ή˔#r4l(0@vOV尢ٻO;p 'l WD@ě=>"7Qc>JYKW$8~+r{+%84=*crβx_&~ni i÷! F/5*{6]E5aDD{)(ԁ0 /BP4bXal9dLō @ p臨Y8GX'2;14 j<"/yb}VOL( ۨF^%ae|qz7戹D{gDpI0*LI0/kL4\D?~{۬[n+y)zZ(cEnTT?1nrIYR@[0>ԩ} _Q6!6z衩 0^HL=L3,߿|v* ;1Ā̡|T,X{>^$\ߢHEaX$ī)<IU}VU/Ief StRҒEAMDc ԕ>Cyc'.i2n@X(s-K` (g eEŬE @C!cNU`&L% x _sS|PI0ORt@9$,is1yOYyJS$$%͓SYyP*c懱'~W/Cl \ * 5v3M407k%_<Lim&vc!?`a yw O5\~ Eʌ'tTAϲ"R@x>bbA%$#G3^=Xs1fw% aF5@ļ E@ /*4>EY@ zy?} cI-싁Uhə=ǀ}Zfk0 LO?}h- Dނ!,v.F'|`O  D\yğf+B]Fb*X< aQ_KgA@~k\ nEY_,>$R0A_(DTєHP<a 0wO}7^KWAЖZwzآ 6`5 1\pƿy?#ň=5Ax\ @dIHSC/6he< ?VWQW|%|΅ۑDD[H}bEoęaBX z4|ww~ r=ʖ_$ٳg-v|l;Ӛ$P"5xLjO-R4AUz|aSNH#*3R +6{_4H+ BtZ96,!.;HVm kƍkB:!"(KfdP6Yk0a*vx;l)n:\HH"@GYU.)*@@˝@%O+"}FB l"87@FDC)bqSwѴϞE`n*/t ͱO\7noAbB@׮]kN:utq nNH@xXL<襗^Py" >FJlJ6`%6<;@d~Fc*,2cke 9_sGyw l7"?2_}/\%j@;Ћ!ϋb* jD|GgCX6Y@rx4q~4!,>zx8D.%ƵMrV0"0OY{9#,-b(J:f1a|"O~=! <(;ʻ'DD >FEՂE{~;<@ @\I#{ ko.]?CB&'DGRf7kLm5i$m;Z[5p#("Ԟwe_eWi4Z0*.$cqok@x HB Bz_>u.xYgzHI40cR:>\{/ֹs? vG` _K/xe`X|+l,9}S1PŨxJҹ5s1dCĞ=?@?lK\Z?DXYK ^y iU{[q0>{[?wpzB"rW:;S@T ώj6DG]}MbD&}9u@葸N(VfƍX8 Ҝx ~~[+5(n(P G¸Y@ϵع+bxP?ݿ\o>_*?JHo6~t=;n#Z\S4X/Ǹ)( IY="[ih._b'ނ2`A‚s\wM>0gZ\sE v>ԂP"("6EZb^0w>31eW=z4H3!YS*1t={vm]:<5@ω/وugmwUA_1B%@1 (X@5 xF[l-0`op/ꔥc%,`8~Q" ha OHTF&I4Bv~Ct ܃?iVӾ}{s1``cހpPiI Rc., ÍiYف q{ igqF<= ,}\Fmc?}l9Xʜy V$9"oZ/?>Y_߬@C 0}->w}M7t5jՀ,]P`C@z@` b/ޜ7.b X#SinmPga_9_S |+tlZ`}ꩧּĉ~JDJl&Z0OA?#ZiZYBuҀ*P"lQ{y=FBկ~M9\/p<AH##8YbzS <90g{ݟ%W{ L-b *"?L $OlZEf:g+[$.y71Qz"Z!чRMc&<؇KV*4%ϳ, cyg>;bK EP g,r #ئwQ_T0(4f]bJ׶_Yp_+[2 8)`%{{J+tGD .cpMwܑ1@h no4^Q$|B60k- .I[mHZ 뛋BS ~<0p$Cۋ[qa?uj $_}LlA .߾oQ[ni|<D0><`ABnN?  /rj,#R))oGQѰ jyPb* 8?uO7nRG[ ۧRqlG٢8ε"- \(0x`mmE܀E3ZR/ E;s=7u/xsb( ʶ,^Wki*11`'/yD5gU% Xp!80cu®=100(։"_ Dя HٮlO?/SO+.)?B|@3E hccǎ]A5F<4V(Y+Bo @aԈ'#i(7>5"n.h*7 倀*XwyI i@KGP̿6\dжmӧO4l <PpBa4xƍ%&T/*PWB:f= A0ʂW @ B$Y8yTo*טjJ1 H/ٌmX#tHo6?{|CM[@k׮]=xV߱9[Cmr@ð"FJE^MU$y;7S_sL+fb`ѣpMWB".RnhȌu9"o|qě?uvbo^xTB2hRVkq"l.ooZ?8Z,$Dz"駸Wܿ/ΕM=6 ĨX1?VȇDx0`N0BB*ly5DƁ (BaN1!U{g,,Sf=5;G LmI /vi>&2Ɩi+R/NP@Rj@\(JYI %HÔ` @G|ŀ !Ε؃ ?`>| J&LPoK~qKٸ3 + È٢l`᧸Pl,(r(?{yq9\PDDgJ &` }* dd@(k{@PggũhlCџi14Рb0dAo¶U/0gmݶHOdl q{m/Rq_5+'* "ܿNI\`U(Tb:T@5ɴ|w(>YJkN38Hɚb=8l/vy6tUPoU- &C@_bB.B?]* \o.ίWE Q[< p22x!ND"PJ@-% 9Xc!OJ&Z "W_Iy& D"Gj@I`yD69T}M_wWl,h߲d5 @`GᄑYd~{74/tb EY\? g-%WBzEd#v)yҔJlyPDF 0ܺ赈~ EJՂ yjƈq`,W_&0V 8oQgq,HEG ]~[5RkxMI+pqmpV^@&l,dQ@cDP ~10H>Ys}s&8- ݳ5MA> &;ג@'b>KP ! wBWI % ˢc+#FUU@[tA DP <@nFQuC_Tl3}pHqhfyގmM[sq%R@D:P2bzXJ 4+k%/ .*@m4nғAòxBV5HwXUs7 @XnbD ȑ#*4g6lXV“y[T;@\%P.W\:\B1Y UR1(ʎ7^V2 eR8H< _ "o| 9<վRJUJ֏+ЩSAY5 ,DT-/4?+SPrkgOD IV5 _* Pcalc)eUza0@GFhsHه4ߧ~Ƚ_SZל*娋3۷o4Cy :48#i~jgw~R4uU]U`'GFF6{+h@ϭ!tc(g)5fmI ~~]h`L +DF@ qH6^?+#㟦fSmR>˂"/ hгl0Wc ͔u)u]7mڴ'>H !Ԁ@AM{}z(w4ȧzm@ `m9hb!%+`i,`0@&S@ֺPmEkdX0`f&?ڦ%( ]`& 02)@478ߏmezf=, fQ XuK80里j uiJJO9iһlk#P1D 1ȅ_~uqѿ|ki$ D7޽$'5XJ<"mFȟ+e Pd,D m^v?UXc RgEA"*^z%\z0>>~M~*+M(H.?`T&[eΝ;WIwF/"jW)29? jWR*mEw@%{ڻT7_D imנ4:T|Ry#Rh6xˈǥW(& Ю]`B j `-߹ =@{+ Sq}˜I=ZaoB}-sH "г(?qqE4aUҠhM[ef7l۶m1LL|zgŽ; ޥ='{@ECe['Q^ -O,ip) 7v$\x+Թ5 >_%ˏP߃^40v$ ~;:'C)5@Q/K JEz?㎥>ÈZ?Q~4)fuC;c0B~FPa~?[%V̯覈XQi-S[&z5b0szO<4ԯ(ԄSb ; = 5.aP_D|;χu_-M  H=Y>:wG׊^HX6@ʊz?ua/IOM>hBWKn޳gj\!2K <lWJѣ~Xm%#j&[uc 42]x}VD\~MIv[/Z'^!_ ̭q*kNFko&@&Ts7HkS?\~*AM"jٯa,fWK@MKGu'!9>;E0 zfl!ufFP_[')_]~>縅h R,"#ŋg#׎'%6jDS}K sKem)yX߫ ])xIW̏qC_i,6Rys!㝱ahݨo_kHGCWV'߸h\d߾wuҨ S..ª~m6an5P*HE9r7jPeR@)k%YX2ݎlo|Gg}#_# C|`W_φNH} J&TU|Fĺw~VkT{iHA:Z9z z| `|bɼR|RmzP3h;wi*p̸[è25^4@#>XgA@t^I k}`ݱltkDV\XsM|Mv`9kh" @) RcPJ7X5pџwI'$ _&W_&/I ff},\`MׯE] p BDoEEjMܝx;<_dSaG*@4LdR@~)0xnG}n2) UMۂ"߆uA™3g='/I Rݹ7۷SD%Xxq4cU̸&vtL?;6 ePSJ(Mӥ9߳GS6@if %w`fD(6M#(h6YVC.?bЭ8L } H M(W1 2j;+ *DqJ`^> # +_JY07Ah09߫ ܛlŀ w X6^#_D~4R @!$_'P_*Oh_Dxhٲe?kv-gchAuлלGh- *|vQ_*3f,ި_`)1wi]`*6C>Aޟ2~Q }} xP:^ ]E_cg0˾}3rhpkqӋQ'vX@`C80`Lk:V۽8?VWß>[IO,.Wsy޽{77@t {˽5@pȿ߄v=UWva~?>zMrX DmT^)~ouvTA5};yS0>=?`-րIG t FOvܹY%"ۡ,zqmґzaxOC$^ %qړ+xiK VzTt~xGPôM<5@I9J-l%j巤M]&F=zG?0.+4cUW]zh+ Qy׷|>3b,,e_WJ2'.,Rb?V ,L]߃Il^@IY<5RD)7{j c:6yv}0=v:wb3ϖFp7nڶmr L^؀e:{ UT8VFXݎD`uf ]U wASIZywۏw$?nH脚kRH:dzT}(LRˏ}϶e m(XɿG9R(Hu ꈾ (*2@49hYЩ1kS`#OeM ?wXuJOOPkk?i, `mذa4_A|#`m@zB\EP!I8H` SB[}D}])[![>@=/]* ;lYIo'?(R ӭ>.[Xp!6]~܂Hcݽ{n`1P{\*Do[FcQM~CPqѠ=[b/g~UR6T& 5Yوo5!<FT4 冷s3FCv/$N!:{v] Dw&ʣGΔ:);v,eZ*:0"z4< 4l(EA6~X_pe"+K> l U`qjIg=rt߯?RwuNCe7o&li ̗8[fv ѸCD`t 69{1&"ɹOfBJ ̏?-?/ ^MQ`b & j}[>F Q-h@ ¤+Wkʢ!ž-V& CE|uŷ.U׸[y~0#L/:߲g>L.vBKOK6v4櫖/_@z<f0Fxȵ4MAB:ߝKltI@ъ, E qah P4S߶ JkhJEAGO-%AꞐ|y>{JHT^yפ p@E,<K}sI +L-Z4WzϮ]o˅&ЎoLhtMS[]؎SH$xR^ )TܒH"h2.59 RUZ$ZY{{FQ]rJ8^/XEc Ey0|5 /,H{:( &MxBDћD0摑cTL 2JӸLoh)[bC׸6"/ Ήb-G@yӚg&۞zOu3-WFKe$kӒEq jTw%vߏuTmk:OTNA]GE{`i>%S)~D .~B6_z;vʟ͏ EgPe" vtgх2T2{.{ł-Dqm(dMQ_f"ZRӖ}g| UR9zme@_䟴:4ءq&$_/iԑ=7  y&<@% DŽj`S+uH/Z?\P,lCS~}er\:So='ԿHEJ}̙3?&u4ж \FtT&oT w}f,ߧDSS7 ^H1}J̟̗צI~.ڃ@ |T2̤Fɚzk@Ȼ\طo@0,ߓ3p9^OP ̳Vk׮t7-Q_D:s xFx@3nTkԺq/DL /2$nNJ@^X[&FcǏGcYSN0 ̿Bs+WoH_zK~Z=b%Wj@Sȹ9)AdD̩ @/k"Ѿa`7zi|T޴pyGN啘/gKA2er/ 5Nxj ef^MMJ $rc&JQD8O?/scuഔ uBqwmٰa;ՒXKvm٠ uDP9mK)>:X5@)= Љl>3sSUJf :^{aW)Ňdtyэ}wHEiڭHͭKؔi%A0&>32j]j@ %猁)7`{0$0ZD=h]}W_% NO.:.@| 2>lGOPKx oR})<Pʍi=#o5 eg,)kzX[``Q48)ʬa ]{3k?:Hbd† Ï~a׮][֭[w(# z&ܯkRAू_cψIm)FR%_T>. %P`R@k%o`8viB/evf QN-%*WT#۲@*P#T"@g%{2ʩ&Z%KsD8!a<*0!'>s^E|??)ku-z]/P M.vn?uzh~{TycRVzz^t_yrjCNPUD"\x*%9o*0G -Zp/nܸm۶c{?]o%M~M/]{f 86A-2(2ymo>'D$RH Zne$sRc HÇ_{=WZoW%84Xfʹ|H>]LfaΜZȽ.)/@gּ##_jh[sR0eH/#@H=(LA)=?@+u]3)d"ߐCA`'04Xpҗ_~o߾cddd%?f5C9O_ JO݁)O1{I. kz[z~dI<ӫXJI2%H#1 O>r=_:Y0=s)ٳSz_Y}J4bHݏSύD3c(Zf[=N1_)@ϕ%C\Hr#J6gb?V'%9AF"7o/^ĉ{[5Tϕ\/+?w^5>hSO=ן5Euq095@4)u{jTWJU`_cyT]ꚡäm)D|Bi_oWU` >znY~o;HI4Ǣ{i 5vOn~w 6|_h;ukݿBA`M7ݴݟ9j_G.?^ύ,/[=5=~ۣ^Rw45V+ c Ç:vn@`)˾3g .7yށr ,Y2y8fa'w(KeCE 5K &;F侵u-ɭZK:޹K gϞ(*s;GC}ԩSy/Kg{3?l!.dtЍ5Wlݺu+ ~D>RwnR^[SE]2> Gijץr@4 yJ!a:PIdOS:W䂞j΍=᯾/ @`d"8@@VCOlٲe0_me:$.:NƐgKᶞIs2_kr75;OL"۞c9$iy.-EyTfvf ]xw]u?:?DLez8SB#DBځ D]w,ʱ3ةjC`ٝ;ws>l{fVQ0~)v2|)@x@sDH1|\^*@C$D)u@ӌM%f]jվCZI7%I($)&uxȑ# 3Pta$3t|nժUwzo~-\|.2Wf$rH =$" };B@\oHϋ~;e#S⹞~>b_rPb\ϝrFRI:5)'"iGcl4EL/9Hܽ{ιsw;:iG ^@q,֨!sJ1)%zWT^=4Ԉ!K̚V%L1H #,WɔK5*V r OG/(awY^0 PZ'qv0G#Ok 5?ym_ʸV&=x#)Fn7e^m@m5QPr*K޻F)1m('E `)#U3~_?@@"-rիeJK)Lܽ2x Z߮3=çr wJ-ȕG*Jsv?)sj@>/eK,iOA&|xСC-:sڡY[@O _{ݳgϻqгR[xt.b^ԏxÿ !".˧ ^1GHZmWR% P)$oFh;jx%qK_#^P) S"tNeȚgɝ+CpСCD~&A;z,[lƱc>-/-ܲk׿Kt^הcwXtr7x=LMՙ{u~;6eޚ9{jE7\9~;"8/|O:Ç+V /+'-қF D9.mث%{ށO5ϯht7^t/=/ ;w]_zߑg5=i/Rӥgy!0+WW @+#T>Զu٥c^ornz(]E^VoN>}>}֭[8p@;70Bۏ5y^鸺h3hߤ>K[qx=qm}( pȑ#B?x7UW]5Mh믿~>!ˇ7nR>$ k4Xytg:M{JAbZX.zY6:T9̐E/Ϟ)% P &7뉸c@df >R륷R! X"˲V\])˝T,,?06ufGG Đ25 # ,.0?JS?ESTGZoIp+$\-~1"!S ?qܫS4EST&zvLwy[fIDɌڳ+2L5#+o9 ɯp)柢).vݳ c 9-)ft)M1M/1MM/1?D14IENDB`plugins-1.5/generic/chessplugin/figures/Black queen 2d.png000066400000000000000000001345751336777360500236120ustar00rootroot00000000000000PNG  IHDR\rfDIDATx }CiP*)BiBED6nsv{A $iҀJQ$I!E 8δ{u<3y>{}>gW*[eö}U߯U@elV [%TnP*U@elV [%TnP*U9X~~7k֬}- uֱmҥ4-Ya0ԫg3<\5jgeeQV- ;;j>Z%$!ZiׯYBDZ0Oгveիgh1cZL4|/bf/Uy| Q0(.oذ!ʕ9\+cz*U Om׭[w^:N}צM>بQZPD;u ,XW_ ^-I7{rшz^OӀ-[L0VYlRjժyyءI&vmiii1 .\Gs WĔ6] 3~9oi qv7-SRWi:Gyd;&-a/_6t1SZ^z椚 +Vș={YfcLq%ӥ04Dž\Jʆ"wuџO8=۵kWG8 o;wnƼyЫX OwrL`a{עE͛JcV?w;ֿ・rl-MZJw}?{4nܸ.#v?~ޓ7E^ t X wuSH{;u3f~wV귟RV Q+A@ 7h>P ru͞u`(/ӧ{Oa60-_sB6K?Y+|~5*Ezo>{_ٴ;s^{ D&߳gOO˫[װab-'.`,UVyӦMLI"c=@=3K/XwWD16hoD,j@ NПk{wi*ɓ'rbz{J~'zN @ Es94>Ԯ]@삹M/bݛo60J}ZUz/l[J@k۶-¿i*yF*\tiU{n>i!9 |gN{w@6&&7a„k`|%b%l*Yf]+DoJ7g3Ooc4`^[9~@ )^?MNOO½7_OƗ,YR1Vw'zիW7o{ mNLp`Lbb>(<sXQA t=@;_DCooPF҂;ym˞:ujK/ @}6B nj<\EςgaCskЀ6=|uօguVq?/?3?D} ozd* sq `~«:ȷ{4b 3Ϣl|g{UWu:`'Ov`9`s!E>>h߼o1:,gE˗/?o{Ea8I9W C5hРh}z1ӟK04YDDТa"Gf @{={;v6m_;+ZxYf O?ؠk@OX<ƄC _Ei)p{_GՉXVJ_kiarAZDE%ϙ3XuG`&- <E϶&b'35duDTU@񺾞qefP!B.X/ڡL^*6N:3XPf|0ˆ&i{V :(6)MfK)BV@]I?[}ڷo&( 8hʕ%PZl>.}-@Es5̙3K8~9O<#,IIS믿cֹs=?Ӎ/"ܚb؍nk wܹσ5-RuBqKa!W&RqàJh{Guكe/!oa~t<2^c;8[8mqcy;/W_9WtR-^xP.]:⢋.:q;>#ٚ#<7lDDJ.E90 `@2?}'-ۄ 6̞=k4+ ";$V &˂ohѢ'V).ĴN+[wyi/Ͷ`mz3!)9Fw뭷/+DA'Amws5~>0CO\1m@;\$ v\w[0#t s9'&s!^ ZP 1Zݏ}ɇv5AgwY>|LG6`tG >.&{+:'0+zv~YE=⋍ƍ#_؎ +T {P{ D eCt?NAb&\ ɼ{WuN fVEWZ%ZN%XJ_q7֢0dȐu6+Ž:0t_ \Zʊۻ,v;g ރ'2]r|M8 n@,E$'{{L6-ުx 0D'+lE}g6lZY`~b$!w* Ԏ:(B}oo]z=ztsbmǂwL@`t<,vW;Fx/ ڋ@ڢՏvi{ϝ;& ̅bqQfP"SL\`;%c׮]}رc/\gQP<v=O>Fx9/]7jmDzP`wXM6_x>cW{_LD­a1 [ŋ?}緕S{ek00K$;vX6\`ͶQitG|XD ;/O{E^#汍UU=ztiodO4:sE/(>oZ_p7 8@3°m1]l>"+X` Y~g.䒖; [jnJX'!}Ӌ/W >Zϴ{&>D@h}C ` 0𷄐0X0`V.w_|4> LKV2x$lNoOwQGm܌OW]p`K؈( a`l7oB?+ 6V2G@%8M3ָqfiwϜ93g[lQ[le5ϖf ̦]mh `1b |'ζߋ^B ;v駟ӧ-[uرQN@ID$~DO{ͧ; j "9p[;m5(i7n\… 1*9䐌O><ٲx㍭!Cd6 `-xwnd`` UZt4@罖tʔ)2aC}U`LlٲE5:uj;3i ~HP;x]8BmR|wvꩧŊb#F ;*``y~; 0L{7 .TJ:]v>'N؃>qD(79˵ I:}_ ~guV3Л^z饪9pNbCv?ۀX|+\߿A#6PP%T6;oiO\wu6lذ0R.60"˫y EI[yn$s'{ YIޤЋ2fIk5jۨt7߆.X,Vji55i)B]ϓ\xW7@g5*/(>vڝG0@ԹxñnLx'_/AjOXF/9/r߇{1|pQ G6t/ ,aiMsaÆQ|XZmʖ\V#*(JŤ]e4ˇ7PG)E:ܫ^щE*GkYYYn+$|JDKwwK'-^uޱI&6lX]\U u*bi_`z TNQ<^V|-|07MMa˪6mPd+ v ܠwе݅O+O\~K.A`ĉ3f73C7`royĊ-#Os0onVp:t3qVD$\%<$:wN0!޼y'`N(0__MP>ZYu֭k)R +&BVd(W^lz{EleN (}&_@}+AoR& {_κR y:YRps}>Z`k5)cs/ M|3!7L}7I@W۷~f͚U3<6#09D㻇cX*?#G񇳋`_hnZ}.&O\@ @wlQ]"(N9>zḣ^9*ObtZӦMw2E첦8*,ῥQkefb^ s *ŭvńP(]:uTGi0PZJI7;MJl*b Zb1^5\!/V7NpX9 JS An"M .vk7[lkV 80(p}@Tt\TDB@%לY9ÜBkع ]XI D͛اO-ʴ|Q%. '1cƠMς̇KIZ0eۗ.]ɗڵkv+]U-ZI̧<=~1WL:@l7q|D1{Lg_V@H=kL[$_!?@_/ST݉qPn,Ђw;B [n]pańr+Ν_#/yEWN>D2A@&S _#.b o} Ð5o_}̶`(rQv,0Y1W8ٽX 9A)~:}ߪ%K 2p 5ߛy@< P!`o/ͪꩧ6хA2&iƘ& )ȘKt[']7|n|>wc[+Zty0BƆEbPߓ/Ѹt}?vB0p{"Dp~_$$A D7  m|a0Y2P36 yOLbZRTM LT4 H~hNL5;ߙoplty{HHby3g=p?gUf:G(Lr|H5=JkN qBkfP0u\|eCe Nџj( kAV۷?(hDo t6.LB$t`Z\ZЫW41 J=]WJ?ݠ'a+%) zuj9b;{cgBW8qDbb@,-*п!Ur]Mv >jԨQBA_ Gt<4/خ*갢ϗqg!%@݄".a(aлc| a~a^0'6?9󑿭 K>,/Gkdb=$ț3۟(_|1/wXi<㥒ypOKr);^v'%fF e]# aŦ9?m{QyڴiMUx&j,S;o3&A9M9 kE_Gź{vip6ԪE %Zt /_+۶-#l"i6] S Vz~\e ?Eh0HNډ| x`>o?Wk ,F"=yB^-4;mF c#dsM:HB]CU)I&-\,G "A\ЦMtQ&6' 'K1Zߎq `8jG3(tCQs-Ԅz!3x~;@@=W, =L@[wi=4hGyZsK;! V 8 YyEneؓBu'#Ku G~b/|JKK8tKXFl?cO>)O5,`>MxU?gϞ\bE@(k `YT$e oN4#g'&L@k > -Ȧ*OYvzl!Cª|Be¨>u Ol򚨜, 7}7 oٲe&"РA?s8B*\vY 4@s?رc>&Qsů?]-> $/iŦ=cw[\[{YŞԭR@@  (/9su*$ñ<b#4DJ|  /ƏĪ2$5+{BZxG^zzo9 עTf?'SǓ*(iݏ1b< ůNi@T{xUWlTE˞k&' d1a#y`ERBW^yKvVs= ν c0@d-~lZcL`5E7gXMQt=JX9p= <  n .틉͘1qsŜ]OK-4]OݟN8`-]~o1>S`ab?suljB;[:D8wе#_k@>|dߏPC # eI-J>,}~-{9,wʗY.0 ]' >}uAWzmvyjwLRCZا?tf 4C[XIl!6 MlW^Y+>+ zYȉBmhl #OGDz!HcUիW<> AQIonȑ#}@#̜93Ofq-ʮE@Sv\~9Z^T}'s9q lg3֡Ozi;~ A}f|$I~$Zk|w4ۇ-cp43[5Aa k2a.&c-|X`qGyyP`]"F@|72G$jrW`1cƤh[#`Ja 3_?GT;CߩfXmt-z衽:w웆birE: /ZL]+>}:`=54@hۼ$դO̳La7$9~Kw|9e@hυ`>6tPfڴ~V/^f8$XVO(!H _z; FE]{Q6 -*5shٕ o SEϓez3jdH : I6!@@`pA~wlԉ't "ϹPtG U/fp?V뽘@6GmdZ.)/Jָq^ݻwߟ5QB#?v~:۹vJԮ<ē <<7Ջ Q lHHMӍ*;{M7mذ J0hDNDMge{9!3n8ITgT}"^@Q*̀_}U[!(\'pΜqs~i_0\\ Hz"In& ߡnD=9˖-^bf|10x lzIhzRS=gŸonb#4m~wulͮ368d).֟@i)P]@5d|e1M_ʕ+qB"@Ȝ9o޼$ʹ/5zh.3.iaU5c3(I[dq@{Nu҇jժ!8D7;3#zhy(*to7z~pT9ÇR'-[˽P^mb ]vY;aÆ 3:Q5:ls+ bM$ Z Gy[ВZwh;{pN92e z%3V(4QtQ;uK1^q1&C 5i ~4x2I pc6׼OyKҥ/]thb{]8Аf?u 峅ϊX۟_9cNS kWg<^?s̚}p;/7nܸp5קf\X }A `n0qZb MmyP vm> T/"Y zbƴ=o&r]xtc2W>lac#ZrޖvQGO:upΝO⨬#F԰<Q-iO<ĸe <(Nu[0BLxI&HqT+ qߍA0`-hcr]d$KSZME۷okB~5l}@w%ǤQ>|?Q95LɊ\tqVLleW(Wd}ڶmsm/6wyE [4ٺLH0JkUW]8p 9 ]?|ʜ={Cdžb~e(G VS¨7.9iK< [?9zRxtPheg믿)ʗTr##o<УG8џ/EvjzB^~tw$k!D#Y}o:n7P~<(`yјO#KNk ^cZ3Q>ˏsZ:P^+ ^̰ 5,ap ~ĀVsyE6b bnmCK+9RVǼiӦe&#n33.|0WҠyW8>>^-]V[.JC"u8O> ,`|A{@5>ec~zĄz!wy晌!V# !Kjeky7CIvipI7lG_+FP8_؎!1Ldo.'$JuN"(7ʓ2Q5ucKSmϫMu-J h-njig d5D!Wsf?%Hx%U$JÜرcdžҐeg (`s0>6֭[Ǐ<ȘXV)cJY_<Ζ9s`U>#.0d |i&BG&''$x'&E|ûỳ|E@`h޽{6pT,b_t,wn ļ*1]w5ZT!Iv!@k{w$PZap VeaPs+]FM["z뭍hޖ%)f!CȓN:4L)Sdϙ3KgÀ:9rй8?@Z5ߌ͛7/oh? u^ N6xg@#v\XĠ7gPV+"̬ |v#'Ȅ$ ~<,5ݻtҀmP8魴 Xjsùpn0ey꽇ċT0]_lkpz`gJCM5um.{(iU2EB tpn.N@Q@vw|N0%ԈI(4MkCW_}u{?suMH8"H]0 f]>2.v,h='sAn0 GJY  "06|1n˚A]cMi 3R &(oǷѳ4S:u:O>] _%"UY_`Du, &ׂE׿q6QJc;3f$1Zy?38CQXdQE9rG bbSÆ c|8y8 DRD-[?iԨQi:H.Cd qׅ)h8ad"fĹs裛EN߿~z } %t[a~wTNp>$R"2[X8O8?42x9`M6ёCAE`WǠAHx(Ig=z˳>J@9o; hfc6d СC 4ّ?=yHp0EmƏ#*볖+JG ז;i2)$ tLX1o4?qMd(Eի,^l @YU_]G!tGay4C\elĉ8]z.h@S(wVv44lpCP޽{CHJ_~b-'HtZiEhc G 0 bo[63k~M`[OI T{W/lj<>K[>Z 47ƍA#T|ؘ-H9z h)˒M'a,Ay8Yv S=G(Oo(^_˝w޹Qh%D3)[iXd#珑T_?+jXX00 vp!%lm<&wy>1Xm4i$c…;^t|n/~/>l a/$pt& D08dCA6$G"[PPIsQ^?O w©Ic:^L &7Hc޶D+ƿA5jyƟ'P&GdZy9ؙ%`;"6EmD q3W~ś.Q`pntEl4о47u(3 `C+J#G抽ls ^jGcFwmGcGCIJ;*,6JhƧ /$S2 Z{xRpNm8g͚uhjQNPdwaۂFY6 Y6D3fȑb)%>F ty1L'JyyH:Q2'd:j{llmҵ378đ De(.2M뷪-r@:uw}yOn>lw[V!7Fy) /QGXG믿^=D[uVuMs> K}p6Ym}p ۷ok 79 pV K1Wbۏ$"Z(|!KX41UA{;i5/h\04n.8k /p4n7|b Ԫ N08{/SG;80@k 9Dǩъ$@L>BdKz6 [hGIvwKXk@ 9Ђ f2MHtz-ztr:%Rrۗ2i ;Ψw1=4gƖ2>gANuL5E&,S6f a&b C_?`\T.u EAKp*Zҏߑyo qȐ!9 }Np[p[{ׯw#< 2[ +**ԠA駟NҊ_|6 JA(vXB+(uVw`Vؓrf!'aI0V( K"&HhdÜžHm.@5 ]vy I&S r 8 r+MF !EO=(B+m/gl~Ǐ_,-V0-;A}C8WM1`EI[eC5I;ԛF{1"'OĂpp.HNo1M~<ܵ;SR-8 @n @gĻaal r )8B`Mfo5$tbҘg,WUȃ2aͤD|L /r-֓b^*d$tlz!a2)id%a̐Q¶R05+sk `>AvOT[t=u e™#@"ի rԨQk`dC `7@EU(_) XV Bd6愰_oi`C8a#k",8pjq.K/m(Kn[nOrfk!,lߔCd 0?#dH𭛷&c@&H4$']x8:'H"@Gj' vI'Ԟ zfTR(SYfs7V].{uطncA T$}S*toP6wa-uH@BT)  ?-gj-o[6_@wH|(]0tPlfJEeM:MtH ? dP jY&0 H3aS-g̘1 +,!H jժB!;(SṐ&B 0T`[jO>&npNDO-ќ.Յhpc9?-O?xN҃e>_bjb~-TsMlq$oydɷ)krD^VuNԯiڴi?7@@h3r9 wXd#GM7CK‰+hziDQ~PKY{PpbU^mS!C"z%fn\H{ϙ3T-./,T9m74 Ԥ#Sg/яnZ.yy;~ 8)BvWUu])SmmQV|BoXИڨ_)n;8d{nwׯ&/APbnB~x9K[g?]~Ym9QO,A%\?~Ĉ ~nu6mp@?x'6RZOҚN:vMp@ I0}~9s' ` Zpz:=r93>b]%jRa^7_5o_tbTd X<;qU,v KEwyuUXǿ['o7 `K.a뮕N=(O1ࠈ=J=;w諯~'kf6`pUb\?A q`T8AYq%5-[6TԻK֭J @QT-@%4ŕn<Cc&?ߓnbYjԨQCs 7.U<ɇ34Bb?49̅sR^A%&@^fgEЭ[ZuwDuErGhTQ 8cd<9x&p W 1N8-Sj9[}Gm@z\[1'’s~Š~ʇm9H 3W { F۷wG|u,% [4j7( >i)}8@I;ٸqյ=ޣG;sM~57揈>vPH2$S}] mO璠/C~4?oQMͮE0SxIt-FE/'ŵREJQ'`qw}+epGncҝoՖxϞ=99AW,dV"H.&C(Jjp5x!|~W_}5_l3x v`uu ϟOA`9x=;׮揜Ru :^S慨97o^M%SNx1f1K5^xa4iQT_\d$?4aS>#%xիWsԨQrlZU7BC1oZpZq> B/^anhs/HZƚ:$rtsڻ@.#(Zr]?rgxV/ӦMK'•5Ac+W,ԜJ p:cCQl+eA_cWOA:f  (lV!d>}zh[cj1~e MX$%U 4i,M6i .$=3:4OZyL=$bӤ#8\guM#8"yWDN*%Stn]پMD9|! i,c #1N%yB@G]$4m4m]Իwov7|3<)*ژ7?~a<_ ge#ô]ÆX瀼RjⴠCa!@@ۅ&Ao+[7޸ )v:|g "-'[,^pؤvڥ͜9_ڃrQۀ$Д n {/ЪiS2uY1ϸq2NCµlǻuvoAUQuyeA@nMȰM.]@2zIMF!EhhF _Y,`ٳ>=Z3>Z+wmu@`r}ϼ馛̸ twTد_4-=C#2n]9DW\zmH* G s<L#MhB;8Bm2kFk^#Ŷʗ M @" K\fvI-(&mtA 0V& ԩoL8 #0M HGߥ tSB IlɛX=kyfW.% 36jՂM`7ӧE۶mw;vlh^ңȎC~!)9 "8"n]oߞ ʷշo{dÚ?l9h83a@7eߚy˗/Gs.XU@;SgE]t0)Es斶NT@7l@v,)h`@19b{n0P8V7) :ˬjj*TJIBȗ@ ʖܻ߂4bɢ11o3#gLMB.vZC٧xQSrHtO1o޼\ lE$sO?D1n:tqm2eJ(?>nJ0 f%! uw47'7Y4 QJںu  @?is4jvEc564r>w= h;nVDb1 Kp0RBL9?L ,5WVc~iSNݤ{[9Lo[KcߗL/r.%sW _-E` 9[`s|DpHyLM7ϿX# nlN]Bϧ2(2ZQh1MV%KJ=p饗J&PJ 1N7@dqv0a?G5k> }I υ~P}4䰬v@-`f-0WR[pgҜ'69sfY$iݺuDEl b#!m:0"k=Tkԧa'`6 ' uFi`` †Pxܹ'OF<% ώڹs͛7oW3`x \-Nle3p3G}-f~Ŋ g@\nYf7]xiӦ!)vl83eʔ\nNK"$N<#;vX7EO +p>U‚*fU{5GuԞ2i3&<<77Vi2``WN;/̠> G&Lk#5jԸo߾-UnUPZ0-;^E&7}qd %G Zs ~Dva[ofv`1_Taeoz cJISkɅ"?췦e=ztF*3 ~~(M Y&B$c"А5֭1bO4i4WͰл'C9¡aJ#aG DP*1Ӧӧ/ Ǝ,\Z_va]3rW\ pAq( )U&h[%F߈]Sw=믛t_SLKB@EOp~W\0|pD,` u,!lJCk1@|u-A]ǚkF%Bap.-1cXP|} RוzDX w}x-fasB9 X ?cbb}`|Pe?hҥKAm˦ % qʬYpUm7H >?E&MjQKҬ*搐-l^Q:*1`ى#.6KC({Xsn@Ou4:BP~}!C{(J@ )7!L*$HS$JbVe  d@T yd@xMs;HZ?Sj]>kHߐR5k`M6*[ʭ̚->+L. `N@*'?쳥@ -HGYZj]pg&O损5U ﲀ # GE~\ "eewYZװa./AXw*$ 8+&Y(E>ς4mW]6tj1plW <#)ZZ QH_ZYTpp{yg믿dQQ,"k iX,B&S$D5j?jo?ۜ@sƍg){Anil%yr(RӶ*\ v0@#: niF'& /`@hWI2/N)gH G-I&ڹ^s&ZK\G*nl#ieIr߱{&/T~v'pc#h Cltk&pΝw֛2eJA\vhcǎD#tG@SO=V '"l8}?IK!_|1[ŋʳUFxkQi=Lm2$ĉ˼: 4@KN[}-"h,e֘Ob$4qB'CZj۽b4 W׫W 朹οS^_ 8 C$qƭoXv޺ԀK.ѫWp 8ka bKm#q|Fis?~d т,ujx]tQ{}5 }U*_TOpRh`R ktҍQrlԩ!8 d:a0PpbN:餃~Ԕ2rW\ \{۴lD -Q1~l£>:M<'d)E^9 s XHgM&Z`" viLZ6XTB m(}LfOnPH$)0?ywA4݃]vm1Z,oG런 ;]Tq6$#'5XT-ݕR_bct?n4׿5a|Iޒ%Kw| 5ŵ|_~-൧M^nΑKq K]DYR jՊ"mD_s5R ,Т(4M6(-G^rs\ EcG}Z=woӦM EN $bL4E!!J9DZe_k:s9nuǼ" Ƿ: ḵwZ3$HP{;uUR_(kqz }WA" |Bu']㲩o޼yNwb<ל@wYcƌ)^lOdHdQeAc Q(p9@SLY{u͛y>R\y8?qL00U_vG֮]stOuWM,c &"]7˥ Ͼ+[7tyuZ$ ᨰ),aG 8!$L~슘]?@xN@T-k͐NTy/¡YCZդ̹S3QY`$b ;Q@p_||x dt vi'R*5B hۿYP݆d ѢQHS8{`rZ~W͟?fG0͗/_hے)gyZT&aB}T@X\:B&3+.~|Njs7ypj<&Mg\/ ;ˍ0"!H Ύ`FB /[[)C}C^‘0ܔ% 7Ԯ]FZG0/rOe`{ <8N0E[lr篿 $ӷo_5G+NBGuup1ȹÆ ό ( J;a3=zK8q"cGX ߮4  `&@i.D;o&ie~5o{54k6m47Θ1#\b3jƀwˬِMY[QQ7_F`rEL[A`Ȑ!H֋P&o|cim 5X\d }4w}`D/8P b8ϤI>wOݰaC#\y> Dc:+i$~iu @`$,ic9jCŋO#҉9E&j@ rm_ $Bc&yj#:\faFd…Sȼd >|U@BÄԓnM=Xq|k n>>u_SG-EG+(G,޻w/!(l.@b97͙ J~MVWWM?C|8%P`L3#h 70wnX`JȨ:yJp{8?!&-"Y 6o޼$(E ӂviHwā~m 8y'|]6<;&x!o][ow.tkWTlɒ%sh 8rU`Aj6& ZRIW+8@R璞TL:n+yCYm($REb2>@DBOA7| EIzF\^r|cM\({RZ&%LzgBL6n8?L@Zm?86&|X{o"?7nD, jWLG5[,c'~7X(yj#Mp qYsΈ]v!mC*H8a,Tps_f#y~(88 ( sY9sy&\z47矯~6|K_~ݫOHH\84j@  pnoS [6mH#Jό1b… vGiyA/>Igp)̻X?E=˿ѷo|;\ .%) F|,vqO_~SH_re/ `TPO;f9ȝ&@47 B:jZ!֮][4—)0=tW5;4VΝ;EOSP%;IiZf 7raݽ{wqRD_/ f?#Ӄ#jtڽoF(~GyUЖ.]O"]g͚587x套^*.@7 B@u-  } $4Dfm{w ?=S={4Kח?lsk_s JPnNh6 e͛g="^z)t oiyO<1._"nI0iذaǑܸ~r9,H K_0it{y~) pQ8p D< 2j⡿!ď5C1b0gDf ՠ{/b`eHRɓ'!¯]jUϱwx%В4f#q&y G҅\I8q׮]ġhg08=CDbROERN(C+0ȩ A@|G۹?"I<cc] z(vK'.7Ws`5#斔1$=&h h+!K7}FP,NnذaZi;-W1@j@1d\B[ߚ&L1c$ y뭷$€kɴNqcb y+ˈ?Cܛ)Nƍh SOE6KDS.s6g Gk^$H Mz'Q_q^O`R?˻QF$u lt 5k/o=bz0},ϮZiK"x qڼM2 8nOͦMI"(ˇxnt,9ZKI7ʅln DlQUHDn#.Ud!gq~ǵ I6@$sl3I`dTC\GXJIUݶm[&Q O4гCG _z `/<sXTY5D䶥K&`-_|y%|޼y`-'դ\z8s0d||? 8a,Cp8.xgĝiL0i5 lC5)EP+**? XhQ4uY}1e{ʕ {yg"PKy/J+Tk/o=`k)k&!=ܓZCx0БԂX8>۷oG ip!$(ͬ$ӀG^z)!RFACltT[&j+}5&#I*j  s&q˖-͘tCcZ}a7oFϳё? G hA=c[nȚW iӦwyH/"Q &,Z IAPl$ SmA-}PXzPa^I< Noa<5jT1ݯmժU$ h}1$3`ῼ(`v33E{D|y6PUx߾}mÆ Kpdd>Ќ/HJI 0!+9lkߎxN/@em60nܸYhƙ8NK(_Hgѯz@o~k-g}$bz*:|A 1Ho#.S,c. f+`lK# hӦMNNs@H! l#TI/e~\e>IY ^{.Iwo8p^3⿬S?öFbr Qhk~kJܠ*ɧܑ˖--``w}?_n΃c f't~DJAZ,7/|Lh:th'FmjJ.@zm$$$K` Ȍ?۶mCd"p,Ъz 79?)Cfİp̙3P7EMXP" m|lI e՜? \%0\-' (C "y @0T`a$$EjZ>*2G$O&p+KWq.?Μ8q+V4m߾,o/FpꫯFa;@$`M+LI2FVsRm3iR߀ oX`̂'fI@Kk??&A<L=S?$ ?pyj=0 j}gyE}O\s=߇.TrIHpPS1; l `D`V 9,!~! ``5@<yQ1|ܣ{m[v-|h@hkT@! 4vozu]w={Ryp/v @a&W%JA|m@[5i@e!@ .>"m&Pk.˿K䕓 ԸHD2鿘?q^?nk vT 7<;h#0obB4sCG@'M`\}}fjؤC8>Nsq>N䚈/`a*`hxȔ$ x͋'}= uuu;#@k*NHs)}|Te]6k{//\4 2{rtٌ|5\Ͷ  si Xp-c5%$|͚\Sde#6s|6IwdFhʕ rGO^L4 5`u… GРnzb̄%@I5=h<Ϡ u4IJmn6Z>M׈f#nBl#*ruO1[IpaF):[5f_8xwcz0'lq{i"nI]0az- E\8>$ h~~3 hY9H ؈<<dSĨ6lh&u Ď₳9o M mH׿n&`ȹ qx @ h/ |LDOoG8/t\-..'| wGJHEmHnm$1mq*s܁. 1[5 twCY%_~e3?DfA/H8/t|mС%viKaؽ{w+r\期g@|bOݶ:Ml}ؤB2+!tzǎ-8=ʚ_O0 _#dMjhhjaQWW_ s,T/Ƒyz#]D?h$Iq341fx&Pak׮m:x ;߂TqBw`@<ÇπছnK>C5,@4˺lRk6 t 6GlQ6w$|f,4=u߂UqBw`@>`$ .`𫯾HKԀP7I5u@k*l*X|دi…d{FW^y?*?a!mС0w\F}GM ً-3Ụ Ta4)Grbr.ƱCxJ̄K/$`/b5: ?Mۣx! vxsR <Pwܑlhhl@S2\>Ȕ`6@l.wlQ64/@pA'wH߂VqBw >vկ~5kN@\.IB҈KT5q`k  X 3t/` 0 ݁;҄}is=wiӆ_^ȉrP[8]bͭg]HW$1I.k36>hSNE1TqBw H]9s\zYgiY|yTh*u 4BF*\A@I6B֎k!"?MUM۷oo~(co@h>fYUUՍ$v}믟E4IR[[jlFP)h@"@ 4&HT|IH^Io@Ǣ#{D3 vZ!]8Jo-'+k׮V; 8ic+r'-![ـ癃m\Oш?w' 3쿛7oFcGy;i#5D/0kZreiw>OW@#`4b$]*"܇.+tr SL%[&*A 0 ݁L܋sh3ķ~;J l*}nP` S @؈gEٸώOcDZ4p?|I3_:Wy;iCT ܲ:TҥKg=+$RnB/ mj|lhZI/O=v ױe'@ .}dy;M8p`ɡCP!C|+4a(]Ҩ8QDQ ,\]L~o\@؆ɵmnX+-hW@!%CO%"~҈%J;7EBf@p)90!)yTvT*Y@ X|y h7 M "Gm%P \FAۮ %\2jш"@6Qf\ !l_cUO`5 ͠o<;d,\0~׷@0{|o)tip(K? f?~#<ҸgϞNvIᛖ_J%gWh -w1(ТgV$Whqam1 F-1 |  `/VTTmذd @ @6 v}Q\5h̙Kϟ?jYzulp9׾NϦDX/擁 D+v$T DySۖ\54e [9A'S"|פN[Z;=|^lR9 &`_ˎ;?Pd P\UU;P5誫:e޽(8$ 7D)@q="lkl>-;6?K@+8 nޚ"dZ܇-GRiNK]KkkZ4b6YTP(GUqHC`_wu%讻j/<~ND~8'AQgBfq+N O9餓_reΝ;{iݵm)E)Q?&dX{ELH=݀Axq7SSh.xb-XҜ4{m4sk3gNt7B7F7 ?@ v?O s 'Oq~ئK %AeH-PMK/&Mc{v?T?"ojG-P5kwW_=,]Dďc5 vbnAI h5`0&]97\Ӌ]>m?QmV<:xW_}FxiG5D^V[[;vtUW (>\ v.,%KDvд<|6C _K=Th/i}ٞ;Ts$I<ϫcpS QdpQ_!԰/"G1?{_َj(++CXpCg}Rcƶmz&HɀiT+>bMܶP\ҙ5C/vN#v(~ pßhFkt4(r|N88p߾}[l?R!#Q h *Dՠ8q-Z4nǎMV* xJpM+P Dl6y>_c hK76O#n*ޘGMr} w# G@d MMM#i௖-[6(Ye49֑O T!z\%*`Mv4R6k ^Ï]͝;7ٻwիW?&'v> } f ~ai.M;jgb+jLf'4 d_wx4]\F~|m@L$z=K%׬Y.ߣF|;;҄ [<̅SNꫯoڴ4ι!~!]$9F`.BC"=k&q]--ᇔ*\J&K#GwE2G)qvZ:M?~/^<aO rU>>/`>zF.!#c32vJH pr=;]>1҄]J?9-=PF)R8۸tHpcL 0]z} wgОpqLm^33R4i/ֵA7ߣ*O `z0҆iK/t:I5ܹ \ qI56C~@z/ &BtP15ihRxB`ѸqÇ[?fQ'P7}O5wsO>l֭Jovy|L@.`!|)=lN&n@ݧ( 0ܝ՗ hCQ|&?}JÇ۷ѣG#`b}}}+JH(@_`(H9(p`f}$[ⷅ&ԩSoo7} ҘBfVZju p 8QWWH?~[B3\slm>h3 `.w>G6!f,6j-sm]D. WWW@Kf4~@vПZ&o#v+gmI,t :R؈ @ӂ$mi@ lҥaXvm-[J1h̶C[KAyjB*~>,)k}Y#P#lIp>剐R@hx,G6dȐx 0#K]zT4 -z@60G >/%Qlt,C:tIM",& t{P$c\= \ⶁym4afr>D.ďe̘1-p-$m6TWWN5`|"Jhi `ر |):{&O\KE 3@ a~U dQ^1=[qy,Scw .!ic @j555 } wH^RS{L@!A/vU{qass'y|:_2Z%#@0V[nke~ wޱ}(uyJ̯#Ytwsά1yÇ/;ڶ훵!6-J07b')bSkkk&zgH0JRdkׂyƪ]v'x R:m#}4 i_L\6}Лs2ĉp}[n-]*^[Mˆ4Yӣmy@`Gbۨܘ'|x4w 40k׶l!  5y\.RyC|*K Rm^Æ KS*"/1H<@(:A]Dmi3I z@'/ݷoߧik#͛7>ĭ 6 '$Bolu `۷jwY @-HSEB@7JqY^^3 &6{86 (pKEEEme#'}& ZG@K IH=@{hy,Je o@׷@ = Ҝpꩧ6m(۹sgի1kҁ„C݅ )ih*GHiT4chR8qcBt7b]WWkw:Gs8a„$?jm>Hˊ(e0whnC@4&3"e/!wǎIlVs4LbcAVL3ڤq0MMpNk*r)sQRjZ2?nJMN*a+_ "R O.pwB\(B@ߋω.[xTr7=3E$•Ɲ ‘{FpȧOb>gkI~ȶO]0k_y $ٮǜ~o h @̠mʔ)*KA6D)@@-}@ ˈuݹ{2O?t@ B|!\^|6`67hmIhg5 @;n[y+FXN5 SE` o!Duuu֭[SRDcoҔD<@A`̘1c| ԨQA+W5wqÐ [جtDžycIь3fΞ={,!tˣ>fXm.`ׅq %tl?~:DG>.0l6;@hX#@G|*5 v]w^$(b R](/ POߡCu .4zRJ%g . l@-K481B8}siA QLm2eJm'7mtn3qX#r  VJKtw\9*lٲ6 6i l}1?`CԶHu͛MI6DZjP3s6 f 0^ 63]СCƍT7nOA{D"( X -Jy晧tIIjLc]ZoA&E61lm>̻4P2܀dF60o@#V)8FR@رrZRy1h2 T+E$B@ϞJ(CEg8|We >K3q 5~&&l.wI6fRQ>I;Q߶m!0 9U $Sҍz%ӧOs=׸{rʄlS!P@S{%HkOȳKI6Blƿ/OqHF Z.;$ {"R F`@ќyp`NO;YSN"ү=GP42@ߵ H/ހF$;@<rFc600!^۾ 4.5fFwshrҤIɁ۷!8Ohy=Jôb) /0r"z?a?xš|\Nw B!pCKGs$tsb֮>#&Ԍ*Et# 1@EG6nXA yR0v OCwެO<7|᭷Ź!F.A;&TR16~3!xy<vG.)@wȧ;`Sq."фH >< &YUUմm6+lt+`NrH][[۫_FuENFB zQ.%n+^&v qxm@hGklm\2j`3JP|9b) H@CϢՇrs dKm%Kf 4իoމkF6 u۶CAv?}Rf0p~\q~b'HWLWj (x]SSӲe˖ԴUQ atS7nf@WVVsÇ7=% 3ʏiZ# y_ ,$nw,& 0CgmRy wuHB 44V\T{ڞL6mZlI "(ĬIg@Ph ߮]Nu<!ZwmD:u~å}Do;}pßBq`eSи|EFq,lٺu+t^RRA^5ʹFfѸIWt t4F~3lZ2\0 >|A֙pz׹L)p[߇]m?惐Lyڶ\(T`GA}Z]:}$ ݒPU[[A 7QZV~H3n]A̧]֧O^C߻wrv%#GHvڵk 5!g*}6RG!w[׎ |ڈPd;.9B-"I=d"n$._XG)=K-PgM4iɓ08`@+V$(c."~ .XB=@#|zP֡n&dg{L;jh<!\oӷOΚ5 ߦmS;xG `_D)/r $x`i k'A/;eѢES z5޽JtЬ tqsLuiuGv݇l0~gs]M%k 3Dv[pBZ^)9D0}jcc<4ceee%i m70JU!4bZ,]iWة 䫨hZn] FWmm_H\ےsb^I'FJ6$zyNO x[|!$:]g6zzWld |s|@:_ h4ZHF[nACCÖ4숎"4 '|tۇׯ^<6%kR뼋PmqU~䮿g 6 FF{e6A7dT1>$kH@Gs%6IBɱcǶ<Gy=$i1J |(@ d Nu w={0T_,_wQ{srv/$aL0 @a ƥz ]| D#= #$ǗSCByFȻ$}į@DtF*wc]`@jё$0š2 ?n?K.dJGj/.}ۧ`6А$eԨQqɾ 4oI`>|x'T;ZiTЈEd>&#E'o_  tעmH2''JKKK~" ޼ B ‰+jE@2jw0|hw`kw8&jBvQӄEy_$a >=@;w.o$*is ~lٲ3i s=mjy{BA֏ǮAMjqGޅsf5C7% ]D":=x:ߙp~ݺu0!B(-BFd8T[3"Xm@g> !dߴ.!ԧv+&gǵsv qka g@׷ʉRMɾo$QJ0vZ4r?wȐ!}zYG tm@(B9Iqfy$)E׮15}5[@lm?ش>׻ =BhZ1O+l:5hF@k渪>}EܴiS O.w#D} & Zulme :̓\g ;Io"ۈ#b{jFRx@(]F:_.i?z![K8T\.D)A۳ޏO |v+TwyM]=5,IDQahC+S~'L0>h}饗}lgS4;;n72P]!H# IAo=3MϚ~Hd?~< u׮]Hr!f+/b~]]}D ^x$EJ_=Ls5 29ޕ~d[[Lt_ەg 7>>dӷl7> =رccOm޼&C\: U`ŋWTT曨w};t*A{fg͕&dۺ:3&>gx/yOӳc߶m[KCCB~߈Rz?;\DPN(ݏv  H<&gts⾹um>,.DՖ6ǩ°O 8}榦& zcjpn("! e*-79 8qb_^֑kqWcX˶a<&NԦLgqAeE18֎[2 M1eQB; 2b.vu%bݬ3(Dc-|ɺ0vuuakҏ ]IENDB`plugins-1.5/generic/chessplugin/figures/Chess board.png000066400000000000000000001111521336777360500233110ustar00rootroot00000000000000PNG  IHDR\rf1IDATx}xUU^H -{)boʨq)ySguPQ#P.! Hw{ιQpr{9ܳ){ߪI&c]dIWL`I=L`I=L`I=L`I=L`I=L`I=L`I=L`I=L`I=L`I=L`I=L`I=L`I=L`I=L`I=L`I=L`I=L`I=L`I=L`I=L`I=L`I=L`I=L`I=L`I=L`I=L`I=L`I=L`I=L`I=L`I=L`I=L`I=L`I=L`I=L`I=L`I=L`I=L`I=L`I=L`I=L`I=L`I=L`I=L`I=L`I=L`I=L`I=L`I=L`I=L`I=L`I=L`I=L`I=L`I=L`I=L`I=L`I=L`I=L`I=L`I=L`I=L`I=L`I=L`I=LXQQ1gj/Txyy x衟خM=[+*b%'lepѬg~W}Iߜ^~uϥrnc6~  aUUxf!%oI-ߔ?YolluTT8+M6Ww@EA #G2555}ǟ>wǤLoHO}*: nnnqh7( ̙<+ ##yɟ]k3{?jl=a>zro? >>,<<G;y2'Nט<< R[rbu-5u)a25FUU(DgAP'n@ae#N('orrVQq+E8Z[m@ws$M^B惧CNF__ fTTIpBmSyy"aB%S\Cdcޞ8|q_$NgΔ7W$Kpp9ܯ yerr0D, >0C&m sss4Xll/+kkpb-;u*:s.(]a+*[lӧf kLp -~/)'Ђ{:eDpy8y2kI8态:r}AnnVD(@:ΟHB="#9MFESK;45MZŁG '>/,< E8N"P~&9c!!A<55re/%Ou[!iXss/-Ù$ N\ppjMʹi Mp)!:xk7oo=x0F}HM}|9M*%rbahpidEa[;9W*YAA?p`GDD qqqkϿjg425B7}ࡇ4hhCP =&?2BByuu ;v Ξ-5<ءCb}8jڐԏ@ ڟ? _OC ?=}MRW}5ee~2nhKLL඄-US@@m.q|=zUTTr%B}Ybb,7Eц@}^QQ YY,#PSMO{m@]w-6}WLpkPq&&%ţus8Ң~:j^=qݧMϭ;!gĉS@AZa>pB꜋9lw{5}J5T 8/VWW?yWyT2UQuJHH5taҹ+@jjiP~c*X;34caa!y=:^ tzB~x6 ښ&%&l~6=L=џ߬o]]o&&&yR&c)<-@duA8N@f|yee:ƫ.@bb7Uu4: +fBW;"*+/,HB?;sd磢OQsWO!S|_䚚CCCJLL:^+Brr2xyy8k+(]_P Ǐ%jyB^^^ЧO2$%%d6/?P7sxKgtZZ ~۽!..Mw93/,,u~vd ~_$((hqjjh_Aɧ b'N 9bOjO'> ]h`^ﳺ԰'En@SSsaާO KLП}9D;ucc;~4|7 Aԝ> 4OlѬS{ ߙL~UUnnnO/ͧhEfM:dhGE#"v+7C---'NCSSSN<`8$T!8s>*sP׉}2 )FD-AAh$oj%%g -n??7sLЍsD_ٻwJZHH(Ț !7ْKkm{CS%$rJ sA#MM(-a>j\Ϯ~t"#ـ}xhh!I/E hmm%%Ο!ͦ'`D69v?**ٹsxvOQMd n'|x.?C56""Jxuv.'>N*"l྾,>>'&ƃtցGC)sS@A4\F1R `e<6KMM&9?KK?Hc4op%̆q>77+#"Dz7>><\~d +wyrlɈ"#5v(}CWP8 !@C2 (C@\\$rUVR!)(/D߬_8(>_ ZiA8rsOٳhnB$Q4ƫ8Vci|xN Rɯ>W=!).>x)+))PTTKM{xhV:8:m`6?M@QK@,pwwcxRR, 獍͐WN.}H3mh;৕#oD ^,11QAZxT % '"P[s{1^z:^^ސʼGX _~睋/^HD_TTt~~ 64x~p1rZ=%䱎vr‘V&; (t(tPC/r MzǦ!R%JC*8 91Ơ pwu%('3z0D"@ ~dn_ǻ4I)H˗td 4(l,.NT mWPPw>(_tB | 8x0 5̦5>DɆrE֥Oll$jD[I9 UsErF _j|ExAdd$&&ƕk5Acc3F%vVK`H11цk~kEjAF[YY?2C)ڡK_/\TSST>}5LdQξkO(AT9r;4ٔZ䅗H)x"=>}z Y0]r޶PCDS_MǮ.4+j~D~US?ߙ3<;P1́v=맄 $P6|x:j9e /e?XYYILLy\Z%S巳Nm||ѣG ԟ{wR5"=;;?'XNi`FBbRjD}&Gtأ3$Y3B8ݭڻE:)TV\|=W K6-^|j=A>ZqSVboA\h^IEm+]jH~,--BH82G':u}~ҩhA$VB0ve+**<|ccG+ViJ=R#kkkQhZr:jZw1ul1ds봭M5d"cO ϓ'8yGZ(4>\:-jePkïsD BL>fpRtxo}TО_ohnn7ne6}~ekmYCУO.牄DҶ 2b 6rP6to gP-۷7<8ꎷ3 ]@m>MADC A0:R#ZCKH G0dHTQfAM0w OQQaJK]]_[{}RO?c[YRR K+Jtlc awnUMz7q}K ]z hK;#疿l hNߕQ3u<ȼ"}05#!_(RPVa~0th1N=[ K _}H`/aT3TXz1o-zQu>..vHdd…*~yNݥƠ0Xxx(6m!}ת(E{".@]lԨ!{77w[-r0'_]]UpmNXJJu >MC5[j;ޝo#x⡸g[RR"ֱd}f }R}&N#zcr`ϞCAkUh l1xvAOʳ xLvP@ `aZP?3Pa}JU 08(۸rg><&&͂Dkv砉_VV!bliiAZv4i(BA٦TFGH*qtgΜmb+V%R\DC0ۆJ$P@|bچwŜ9S0ڍDžRlYYޮJr%ԕPZ_l +ۨ(gA0l`$EQNGP_3mlJS+@SSDS}Qktq$X}J~m2`U8D{o||0|}A:'-2"kllIh/ڢ#X,7 cb+s! []$I4ww $%ظX'^qC?Xk?/ ~pRNeN `"efǔr"n?f0>`@?Ja;vgQt]kNra}&q H@6AM̓XRRo|D;2NP)<꺶w}Ԯ K'ܴ9<<˿v\poS76:W惓'AvM8kDR]-Fai K&%M7ٶs;w 18jPq7n͛ḧ́YB\\8df{B=Ym_+*bG/԰KK35/1b 4/5شi !CXۨ-vo'5lIC2YF]U\ g`w#R59#IGIΝdDM,Zs hsْK]+!Nz#z޽DC:E/ M W !?Y);h~>r3 cǎU)΀Z?ڇi^/Yۻj 6i0#QtD\ϙ3g'|ŏ+DCazox套u}z5'%37'/|CC|͛w9pQ<4qF gD'بQt*%׉'Qf6 旵n 7~?;"+ϱp Ww ] +M!Q,&N@ԅq}$ '2NnwBA&HV I>zȟda LbA}{]G4ɬJ7\9"E6ل # (㶡8+W~ ˸o K==F՞;5+.3+/?߯7^^󓓓G8Jv/9v۷.F&OG;MD2$V,p6 1y A^< (_Defnk,3i`P 6Iq/*y>pE!i  S"%#^Sar97Qb{xM+ 'JS#'{AMu xy8O(¿.4-]w{:39r04/Idx}vN )$\s 50i^}𤶗pke9eee$@e{֧dpDy\\E(:LV&cȑ"ATkO}H@CXPD C*|m\ss3 oq s@ F +Tه68@7;| Kb)66}\~-<"[z#Ƽ1{ǐ˲kN\S+|HjAaaAZ 96lݺ p2 ',8B qqׯ1 ~yI!do>K 7Tc*/oذ!T5B /qQRW\gu}^PpP6 E#pe`n׊jP|X%9*iswƦXxE;[!\h%ŠC,!!>?_UU8CǎZO>vOٯ 4۾ {ʕP*/V_? z/ݹHiY+d6QҲmzU{|?l7uttt C7z cһߙР qGӀv6cǎcǎ8 2:P[4۱c>>^8̕UH[Xȁ`[ j?~;Y}pJKK%"Ge/*7jë"p{8_g"##FD'6·yi6;v]i.uGDS'@xxGfg_cc~W Юx<j(bcc Z[u])Qx25k)[>gsxϣY5 55/8 āwpoCBB&AE3ŧ)M>Ϝ9Ih"1k`2.߶m(! 8yXhC]t *3Znǎ5p 7n$336Ї&B_JL ۳瀈'%ʼn& ?@gHs ĢC 8w'HBBMB @F2mXnfK|$…C?ms|>9%-[z);4x7o]}Et| )**ҍ"JT-hʮ;wp@7''֭&s؏dL8q4iwJ:\iӰ}P࿖OT;lX:4( ЌCZVV=Sn F'3CP 5#A(uXiFKuZtta'CEtEW_}+B(2uHx;DV}Qe+aʍXs(_"0 &C@@om_pᏍ 7o\sϢލO܅pÝ9[PU <-/))~*Jt8.%D6lss \ȄFB4@uil|ĉBBw*=c-hN5ixOwx>r r|p%r_ \XCغ"+>ѳtCЙQ1L/ }Jy\x_9S6wQ#/(jWfZNӲevs}t.m9sR+oW R&!f.t鴴^l|!P^^& p"Rb~y>8aѸվ20-- ܏S޽ yWmk{}C=w?h@L)cIdB~> OPE "u޽̢.k@}VcΞ=Ge_nMn ׵ԩ#HLɥKWի,ЉoJ3`FБU?^˲eV|oehW;vx#FEEz z4PQ:Kt̛7>BkU#ͷ`eqҼqygTT8L>Ntux|hVy[A]2\l @$Νog Kױr_ OiB>!ȉV?ِƔyG Kp]sfPUU- oYA^avf|8Pjs׀w,d4O!;B GPhYEaݻ+K^m5:s~< \4N1{WRl-h͖vF `s5;_mqA8i~GT'{7?oݺ6p>)qKujk0rJSyzz_(DBۗɋJՖ\".K>Y1hPi$~RlScPoV1Q[4i49) k^ |)uw޼)@h7;~3Xj jLS4jΜK梢b|*gѼi!ɓGM R] 主yxcEvI}_(  퓚' gN/ϟ`w_v?d&iBZ8c̉|ڴ 8I5k6*._zG2\BP/;v80a N?9N8Q^^G/'n;]Q8ZD:Q}B~0j :ROݻ'48r'mvaG|>hH~%6U-Arh7 H'uB=]V ?Pϑ#+fFʬ"+4GL=v'Cǩ!uB>u*1F!?JEx:3Wî,*:{zz?PtPO:Ut/BqG7n(%{di9eL7B蘳|O)n۶=@)ڇ!E) wzua~$$ҟA8Eor$C,~ց?wD{u4JCZje6v '*KpR橽[/7!dGR05>{a0.RG L:<~ܻ!y6~jW9r^y]8[ܼ'Ɛ!rۉС˷*+; 5\le!"9DKOaN@icjFE:i+1ܹx\\rMg):mܸ8NZ# LچƘ5kuhu`e%&ܳ qs[\f 6JK.2&LSL 5P A>,0u}EycEcq;f)9 h56䅅%dH3 p&hQBl٧]Nđ?!!=B~/9 'ʾk% <1؞B祐Ρ ۸R"U&q]"_t%?44/Z4{-{EE"~@?`TԼD •rF._[bW#ȳ?g֌E]D}Sk'#a^ې`ϗY n՞7 ڏM:+6u=))jWj+::#gOѤ|[ڋd)cqv]J6l%XŕFn7m'EOXnnb#i|Ԩg\_{aS*@&dƤڱe>ƛ̞==ʹrNmy,XnohhFƒO>lmֿjQ+V\|'ۄ5L! 1i~ه~W} 1fo϶}kxnmAP+,:dYz7"k[ou +ڧ4 EEg`ծrە s,+b'Ԙ&=aA{\WC4hl͙T'OӧOMfLho3 N|Ӛ 4/H>7u%ْ%"3_w!>Q'WC99'XcK}D6-[ " o.z)>rO…҆Ǽ=p:5` \kJ lذ}&9s&뮛SE#BʺD qK HiI-̰S#J,-O:!&DtD•jmNG^^ۼy(A>Ɉ Ӈ1}F&b7U6$ҪPs-Ϥu݊YN^ů/uܳ0kagϚư7X:p& 9)/b8s\=F2ٓP3MPStħq8Շ!#ZcS:N0R4!/lh{E dQblwAAjͦ:cSEsϧ9C(2rdjA4Bc78#ǓM: wnA+Yi>|/"K/СNqzGYy(Ӯ9oVs{2/*K^lXr,++Wj|'V.1k#XNgN*OJr_tt?HK A~`٢P(3XO^#s*2OtLpp 5I=<Tk!6dXŷo22L@bNcD4ɻooMKНCrth_?h=[Mm<9zv9P*^[z{{{qy\~R O?]o~R]#"!h cղ 7=;Ѿ,<̋@wGIbKkQ_o8ɲM4z>k7w B <<~DŽ ka׮C~17E7z8FPmpөKM'P!ΝOc6>> 3fL9C51G9;w1x,\&Y2RSDNzg۹y ⯺V7׍"Ǐ@~ ⵏ+㒓O|6öZ⋭ ]Y2\%%ES?pJojjj7ԍM_y hu"'+D%_ ( (/eo2HuЬ w| Iq ;)@h.8Ζ{E~AqܬS!JzeEփqš=D`\kVo޼!hp[.=h gva9E֮Pqݹ xV*<6*MKKsgvrSS';{ǎ}BN굽+va%!BBS{iZWٵ;GJ je&΋f4(w|ܸt1fR9PN!˔T5G&a8;GoK~²LegI>}؃.gOv!Lغu7m,NJϟVl\x|Vng,&9om R>)Km1$6ߐ5}j3E[&dL"ȳ[`uBҸR۵נC~JM()[ԩq2΀ {84-rh|>>&QE0ZKnWFΝ_v.#/:C r`Y [8*)[Pye>*BRry/9 DSэn4|)@~F,Bݻ ]c(HK(j~WD)#zRE9>t}Dx# QTȑT6ʝDO8ьd1#P+-tOϳ y)]mCA@1<6o8H L=k83[)F!] (ZJDn^ nz⬹Gz"%Q961j~pЎX,!Jg?~pM1v[lPl_!R5brX|(8Pmذ>Ю96f+ژ*{ayy;$:R3VRR HT$bS : N=E\ 576rLΘ1f\oW=Bko-_6ip !I%tиqD5M]^_s InQZBLLw .[;n@PHiH:X7 Vu]kSIqn5^bD5L@Lhq[omܸߟ`8rRy'>B ^s̀ &0-@QXNvP;}y8a0^RRA!6YG@v\:5gf刞 Q{ğRwk&++Wr%T"6%&h[hh [fZuWdVU|P~,`W?b]|s Eؠ4_'n5C1 7:[dM6hFǠ~<:h,f wps~p8hv"ɆI;/ezE…ea;-1<6&‚aڴ[/AB=YN̷ChU_SWLJ!:lX(ɦ$cȻ*xڃSO~~tCQ5 N3g rtљ]XX˖} ~KtK "#{yU[)G1s =pD̈e\ݭMݍԉ0wN<z"*ovzmy"⿾ ne6 g`j,YpcuuZoV81'ÕQ7: )ӍV]z#rk40 ?43&M&M+g% ~6J/k`4)>&>ڡbZWtٱ?uls١V* .2@Ȉ@4$!&L:}l곓GJ'G)^8 r%BsӦb?| PWeg7Xn=Pv'?|X}n.?z6rX_07EEȥ_Tm~ƨbSÀKi&d7/.k!3\m:-T,hVQ&aյ†o﯀BPs B2;$w;}X 35(5ˤ?Mm۴Ә̙uySccȳߴ[(/?o8aqtHpO8B9 O)Gن[E YnO H9uЕI)SP 9(׍[f*2v:Z Qv~9vț>5ƠNPy T?e2<؝k5Rj u ۶"gxN!p^<$%9 *]jTi89ɒyt$[ҫ`™YvB3Imץj{cPqVqu*hXWXUW SMwYۄ ٢EsxttKSu[M(*aw#Ezz_>,֫W.îεFk>yNѽ80q|ij뮛cb"SQGL'ⴴ4x;E833Ev\{ZYq,L$=#,*.q T*-) I`]?CTR&Á]Ҁ:M=v;d)Z/߼yubbsWK_{Gxu_nӝWo[`YfI;w2N+dU#՗R}ylbuWQ@%[|ƭ"7:5D;ۃ';xpv-sx߾);W_} AZ&KB{g2&%p4|SBdyG !4gOX g+撹 y`[1)Opuiza|)"{qX7s@KL P/$+{%%AE0x`!\Hl 0HjA$f,6Ŏ [C% D$onuf6Ƴ፥oGOaջw[؄ h{K9{'AP$N|>nUtOQukl99y>Sؘ18VS9'-gSċBvLBh%K>ԓϛ~~YXXיPb2Y,*M,l*.*443u1jE* -2i GEEߗ+u9n# |YLիdΜ G5yekEE-[QzNZ3a8w8赽ˡy}83joS-|ۮ&(;Ffyo f?}`:9BB_ 1$}n;  xQNepr/'w7$eVu9 e-R=}4{"H^zGX -SUJU5!v&õ<))1M9/( r`p" E-v׽VqΝWރg] }r"ޔK?~9rƛ  $u\h;N.zvgZaF((nI/0iaNoO͂Pi_  Θ>M):2o XǡPA gFNY'?BXP#ܦ /+Ա##{viwqʾ}|F.11Ѻj{iKW>Ua7«R#u붱eAWG/ґ}B_iU8YhԡyٲYNN6UKaOfz:pkd'N2_x5<[w:UH*.N-)|mTt6wH3fswfev'` .Эtw,mPc-$t+5SvڏPp0/uiasΠ?;GdfMIϜ)zyGLfMAVRa P9DcL@Z{O)FX k'kPhhavb[_dS`۞vt)c=zkْGϟG𰡩hd,B+ߢ!$R\ɑZn@n`q"B1ր[hы@]2D Ƙ.ѹK M ̂AmC.!89wll$̚53oVH(盡rDCRR/vpo )^Mt:x{}Ic+|`/W/y\;EFΦ?_B--Ͱg6,?a6HxE;.~Hm(k6{ꡢq'"u3NKzsȳ%Ah}·yYxDu YJ V^ ̍;Tբ8ܸ0i[1m*E?_Vm4C cuCvR7p`*TN+y鶩ōx> ˩Yj8jՠs*.T?zkMKn!kT"٧ XSS7nyg-?{<K%94^:O>^,8JvZ~;??bevY}wZV~RO vV<-r5Ȕc4>M닓[qofle-(Ym~a|e_qw0p7cp9cP !} =tf~L@w П;60y}ȳ[wesէ*@"O9sPwqԌnee.6*RC*!HSSvhZalذ5@x'{M9~LTCuy&B߾&0v> +Wn XdS/axHP5u.7ٱc hGtL'Mmo":'svgӘT:_jz槚fvw*B+ۉw~ww]_wܤGՊnxIgXnaJQ۞Z:59zXA-28/iRX)lHYQ'ըp~hU4RZ,O#-8УpBz!h>cD(,,f_|]C;ʰ vQx.Bɻ/--TJ[PGEۏ>Zǎh|TWͷ]k%!JN%V gÆ9sF3Ċ7`c"A] 'hKW;3A.uvRSUZ19G0Ok >e$R5]+|Zξ!GVY<-|Zs20RTo;n=̙s+ q[t46v`|xRdXi%:AjPj.7_F?in WCy)@ٷ0Gl8t\3I$<\ 'c0?'X -)%JT '&FnBoi}z*mll!,d.]3Dn"DI PbTT0:u8;"ߺWzQK{ŕߎJ chr!1{잝ٝ6ϙ7g3>gcc M0PRP]ֽU,ꮮO/'{@o{ni3=h !]+A驑7~B]x᎛W7(pd]mtտfwǺ>)j$^xaQ02WζO8pAE0״&&TYBph1p@x{{p1NM$W 4u :thSZGh @Hp=|for]%$'y`n0~zdiisÙ3qק>_nxs:KG#йs9l$kQ4BPQQzHυ4]q[aҙЮA?@ށBީ0wV[@6_lMpSGp7M7m{O^^\V]Ӱ_)<ӷo H bNAdQۯ9lv"ؽN/^ &9{"z5Sߛ(OG~z88WESZ{+|ԟPȣ-:~vim3F(| mJ+tHeuu#a Rtd0!E1܍کS&sd0HKK3K5Dɵk7MɡC(c#DH,Mk;IgC}6x|_^%}y{;ud7 ybP&u9j<77%fT<ܥ9qG?>#Ęٮ__W1<@b9ŕ/3z#vce=9Y` <( _J֤/`jST8~(((;4 j76ۍ=fϞ>}']LT$(+". cO3L9<+!Wۆb1._9h1 aFW Fٯ7++KO3ת=?=؃p—ꫛ`4@F x9r._+ [M4߉XlNҪ+2ƍsL$\cyS6S|yOS!Ϙ1i]s L*3#Yԙo;V;M!;vA>STյ`>i1G&?G9fKpPH w9r^|EߊG' L2p`_p5eB ,Ư8b7?/HB ; ܛbEQCuX} 3m2e"S&:CJ]z}>_2 v~׻R _,co|Zpn||xE0U ,MOo4a83{"IKM 1f@| GcQ\cYQ9;w"ۄz2_\M~ rst)͕xQLQr!HD"b at*Xv*k`/sa74ԑ[ӷz*@h?榽B1b cQˀMnAۀTg۷"o׮[Z?i<6otAd؎tƔ.mFزA5~ #*TW4Ǯ^I }zcݛkN4|;7/VUY;ًꞗ?&M I5iyĽrQhK@'@ewY`}{KN8%|]:O71 l~y0uh!FZQ7hU ㇷ! UXƋrSu{.O{ye%`S*NE5`,]VoG~{sKvRAW $1ܖaÆ]zV]{#lyAvdkddU`b,}nEe_ n쬄?{HUud~NMc g;Pi1%JiEpiE 7`! Wd\Ļ`i-(!ĴZ;6aX3mFpQ>8Ͽi%55'aGj 57迴Z |o>_Vaڴ쳹%Bf4[SUٳ8*n|GQnwAwh_D WM-*7[إw3;T EAsmHKu;'̲ ^x~!URZ v/IKk6u,Y`m*ըsUW |b4 6!츣P`JCt”˗:=volZ1P{idQQDdŞTRXXBwgNYXN%Hjj+]L huZVPRReF?PfInx> 73NA@+S[NN`*bJXkL -5|1QUKoBK³:k}(;T#%)ɶJX~ion17weeiJFF gIcu`{jPcN=N`D0HV"3N.QZ(!E#~Gp ۶Z9[A%-- /=g'gIO=ivWnr<ռjN[[17͛&p$B(聆Sk1[Afx f?wj=L]FE%Ʈ_هײ4 hJZ^j—x 8ǕW}(۹s3q۝6XbdZ~4EK=m wکݎ*(D"9D؁jkڵE}pG n@v˖̀c.rQ~M"۷S^^{]yqe Dӧ ?"3f0K*e?%>sdÆhqqN/HM~->~߭['gYMq~I43S \g'D?e ĔO:vbwuƚT*Xv)ңPU!I(KKu־luq'x( ĪU_+QS[s˞ɥOZTI`Ps83~6dd> l47ڹs?y('71R"V.b?aȊ3٢.<Mrl ,mo $o rxnpdfzPic߾dke$=X2;1=}җ_^LD!O%5gA8%HX >4.V\||o(1YJT*uDMz+QjCF5kOy0P+%%e+~(磃Zcnt(m"?mUkfij%\irLW•+Eߺ ٜ#)9k:n;qXh*+amnhjV};q~5ؤ ItɢI]s[\!T¶f#NWsұsS=pGI8䣑Dj84[w};8S?v"Zс*ZYR.̶ߧ}6^sK ~2aS̒\h> @0k/:1MV["v o~1<*Xn+.b,́/Cq'tӄR2Xػ`Y2;䐒\4L0NkD;v>bMD1=h&[ L R)< !&aT6R4bVɇ a9( iySҎNHOzFٯ!X3(5jnQJ^a>Zj߳׮p| ܹVh߮;?*ѦM[= \Z+F~JYf.J dvLly($oy;v-EzwmS(rl$. /?Gȹ!8~ ^9C\u`cҴiOŋ'lj&m3b u{. ["X@ L2,]2fH4= fQN]Cb:`?}v(_~Z#ݽ\Zz]f_xY7CaϮw2`3vѝ&˖ԩybǢJ6տW4ʖ=8H̎cPĉkEFƏduD oZhUU _8p$ʻq[coA쳳Ǻ$ZG LR D!S׷pe lunn@1#`33Ѯh{zs|}v>$2&Sq3j۝\9T*pt-C1Ob/Yߎ.|䃀c$VsϨ5?F6YP=fW VG 9z*ʛ²T0Cp! G(hu F;M2P\~qۡv`F{KС0Fo@2U̅BaGola#ׯ}Ť_$DK3d[;s?xq} ;"؛]{Kc UQ nSOIv^g6w'hq@ +*+k~(JC39n|b|=t |)"։Mƍb{.o'⻮Qӯ *4+. |XϞq(pԞK?H/Z1aZP!UY:Fx-c+2C(X02>@<0#'jP &%w0;v^8uk$,ڵ+^&& >\6v(>lcQP9pAQ@´RݑɴE gW>7/H:vl˻LՆNM~Y d1=Hu -ׯ16lr@VV5?]k)P{S;r]\Jg)T4=uF7nKYY`钹dʤE<(A 4h]"#&פ T5 =zv+'U! j]w:zo$&g([/*JU9MtD34iەJ/\'[vВZ mڸCv7Foh݋~$Ν=Nje*M^hIٙK`w@MmNg$]jr Nf-R0(F۱E;l >`n|ȑOT9@"Q[G5mFOB:ykFU ybmNׂ6鸩}W**|qlW׻ nbX}>iAA>. k FHVʣ?WjkuMP͚7>^ho4%@E#FK/vvЅ]orB/ݱ.\j p,9_IycO} 2_K;*FܸQ/m+τqㆲ҉1MT;u9an=.w+p*.Ld-R}Oi^wTかWՀ19ȳ M@qS  xfBK"{"jΒŔ EAdŞgE~.)!5 ¶]pd DƤD_;vH{[Tdv`fgf8jfVTC$ң{'l4ǰSδjJyFȰ>M7 bC˘k h)9$wj-\+._BQTki^;pVI4?<,^գzڕ}a2 EȎP(=acᰪ=^`-oessgWoh3lHosi.5_]"ݍȁ1ZWflm */m%8!U{u!wF;)k% {^٭[Gd:iS^}O.{(.|EUGH$z kOjr'*}Q, B>>^I("5X$Dwl*1v~K X[ oʿt8lNFϛ@tΎs6*+/!ʔ;#z/0r&+A}kl۶[TV7iv\" `SK!Cp"5aE" *IL Pճca M-\oИF1"AmbD) Eb*xurFs?=#ԡCž*vT}Pa=?)3?̶⣄M?lFsc=>nŠ^x`| *~vT9|)t5iQ`*6]l(Bp&R1H1Y(}a[;III oi>`<_ۑ]yzi@p lf-${fP%cx/f.@=E?PjKzn/dQB{hnxȺMW+u>_OWݎhrRB֮ =CGTc8վ}{)0An& ̻ >ļk:\bwA@\16nf+7G.lcFvgSu'el. `0FE]0wU,*v8{:~))I0iHXbd"s9W]YO6'pTQq8I13` ?¶Sl!g 3Na~Ll,?21rp=x" 揥]dQ[RL ` -q#B}Dc|&|E`S}G%˗Nvm͞>c0}l׻Avi@ hD!GO}W5bY/ _v[ͦ0O#v{'L0_mijjR`1 FPP0 ]<>$ĊB# b:GN;CII]<>nȐbL?Mdc~ Ͼ 3]'>Wi} ^u.8;K={P8)aLQo-{G%O_QQo𬴴d$wHڊpMg$J?-Y,#Tv 8Ӂ݅v*(9z=tɆhmz\aBFF{|r5&L"zW^Xk9OΜ\~e d ߿=QӁ ?f-x@0a r:u.Z0IrrȺ,*4r(ֱV (㭼1Ê 0hP6sƫ1^r\*UjF#0W|B4zeeP!BJu(^_e+a)v]qB!kװ Y3G$TVO.)F- V,G@3^tCz۱#iU=&"x3Nc!(AD*=0x?Nfi_lz>=@$[ג1c`Io UT6}@=It(m-m\(w~tiy}HdjsqDÍ4*Z._z d ޙSyZPLa}%ؼo[rwnŧ@D JXƜY#ZվXZV2cGC-zu:DsM3$T"wDʌ9 1^D6L¤)ʊŘQϾppx=FmGrRh]}A֢`TRRb'䄌qcg!99mXЂ &Y2;@xrӆ6,M]AkmzR Cx"*ҋA?UnYZpvNS׾]EprPX!OP(ҹopqJ;y조phJo7@\!ˌ)aw$r 3GTVTޥrI?^s.}Vwmxi^<<ǾR@ <3##9 YC!--7pEU}z Ejȶ\#c X;~Iciy)6nxH1}0{mwLii#QeRmm4aM't[-0H.jQx\^k7jN@ RJN|29fjXXX/lصKU`Sᴁ1˔C `s c(⁣%ٚ z]: l~@j넷vi$W'-!e'ȝnQQQ߱uorXnn ׆ ;h0ٺ,]RR[{lt߯|0qŵj|=2jD/Ѵw8plnj'p5u!;FὍ'IaQv?Cf۔vv,=Ť g׼TWYR31+AVvb[S4‘?Vת-۷hOYzCX{ɓwvW ys@~0ҡC&E# 3gV>-E2#nxB:X`'H]o@Yy9m$%zh`}RE۶IS.s~n hA>u?zaOQu4h#m253bSٍɖe--G|/|1SONM$V]-}PF202ȥfSkuC}ήzq`/?y3pf\.ltl|{1~:n8xîvWvoӻw7!R9o=( C05VW x#߾_4ʮ>rMǪ**]; *0I<<@.І&V= n\= Q}gN;iy؉g@WGg8+D)`5k h_!tw!2v{ɕ>ryU3N G+1~fm` uwk>)`?Xq'vɕ>rk/w2aRhs881'cMkGk7>|S9~y&W_\%sM/b ̀` 9339 }ﳞxOfLqM#\|q3*'^⩟0q4L~ |x} !Db`Qf: ѳbu.;C}M 39^]_`j664V@˸~4m:wku k "PY.:2Lt=$3,޷:;R)j(TҌAz*s0sa˂с5﷎i-9>Tl@Ȁ9Fj'PS?nXHr- = To\ |ǂ<^/>LzySo/|ǬsCPz|\vq`עb>w5r>@EddpU@-ȉ?w:ZFײyMh4GSnhNӅבLećBP+.. 9,KwӬr!եTʀTJRr%o)'M9|ĨTԣ2 \!([.4@"UY?>VY Ipڵ=6΃ 禇[yfYy4eknXw0 dMyC-O'^%L9TW{ &dHux#{ ݱs%F0y2{;8bL49G2әl605UPz<ʊ*Ķ+o @ϴa X}foii9*+kg_bx0S,J4I~~yB>cuugO?go/0@\nς[dklDs9CšdMkCş GT)j^Plj<Ӵ,d3N,Ѹ^qe$_A07ױ=\obdo͝٪U?OxwI>4^JAݎ;c@>ɨ, %]`*`&*Y$[Um9&3 Q7n0tםK6~x~,Հ?4nxe֌0z4*q(sʀԑdeY^KsHxP2TjEޕ>8}/""ZgLp`yF(h55-qĉ)Ymm3s8wU6† mƘi9):餛h2΁yz|:[4Ϲ"Ol*O`H7v8w1glMUU9ohh ,ḱO##\Ka!'Ƹ2 :OJ{ q`ɺ7=0O8miPW4+,OJL`޼:iHUUqvy4T('A{]Xv lݽ 1cd)L]^Exsgm\#sYp:AR?.?rL>ʄL!p|: \Z2Z 45 4d8lctDr%7} nv0 dȏW>S[Y}}`"nqR\ em: L9*zᇫ,YR6𴠺'S "er.dhj9`Ҵ1ᰰ9Jd,.ʠ4,Jr]%`zA]M"Kи&tLMY#~LRJ"駟 .3ffBca4734bQ,x<?mm{BPqS4P~@0#X.ok֮>3gW.]|9fd3 ,2^zs` /@Bc`QN~ 89 lJJ4 7}+;~ti 0 d޼)?㷗/?wq'Y#Fp8b \NMb**v g`GA;ok3 "1q2 _UcrӍYao=yɑg@E,n8 P${`IR` ,2DCb\vDLw ycZ6լ&PYǀ({TJGE  " |p$ TM!s"`g3>Ix A6 30$֧AṮtG(; . iiH$p֕W~ 8q ԉ#WdF?T*&r@!J??UՄg"H'= /<̆G8T!(2a1 h }@5d3"3vU$n*ɾՐL,|tB0J8 L1w?d%v=10K Ck_ ̟0:7N@f禙 0d$ .f}E9Xz{{<K Y@1|U[ok̼W~oP[TF"#xx lh2I0, (7Yk=hwA:Ǭ Q/}|1lƌټy$A; a@]fE !]>}}q}PAT{ ne2[c[|Ԍ!-ڝ!f >'`y]@.G!^z@zqCO2) ǘ(+,xVtmL>1z9gu3g9r<% !0/O" @nᇟ>А, @F=7\xpWO O;GAE @be2PjV8%&H$ 3SЦM=P`p|ϦƏ>zΌ 5@8`##q\&~!Xf kk l LezG?!47j@UDTo‚:sό==0b3-/7jk)#' hh\I Av0J=nVڻR/N[}`kY(+ h@=JAE 9 AbՀY3@+$z/PYR~DN@M=b0,Î VWMG0f̘X`>?:,@0L s 䬟T*ǑcP>q5oFoSO*6@-C"H=:52Q)99Aqdd^#I1Mg]8@\&3AH:KYT syf @ݗ[ T`cwVwoi0`ww_:0axhllp8l%#{0 n9 0B0U V0pn/5_wuDS<~ZmY XB@X>5aOIA%p"'Ցsz\pijJ[f Jh^y4iBWVپ?~Luq`J8I>è(h1Qf!s: ݢB3ҾoUwo]RUUq**xOMC}l0LQ~( 3gNѣGBccޔ.[ywZAH &@: P,hsJ Hv(nk" o@O_ fM ~ٙLdR#ey.GY2L㓣<ˣ{X h /`LC}l0LB2~h6ahjjP(,R`riPmI)yh' m rPD۸FOu]%-{F8| H}hУl^H+IT|Y@NWmqsbLlKQƟQPcMv"5d w^q`J8ASS=L4X$*LKQ]?\V4 R~:8 [vP/*7zx06#9~?>.&3fw VDPHʡc pR~{Q;$2GNlp n(,!?X顸'vD\R]]I$҉HY4JͧUp4uZK ,"fdw\.NNiJTD^y}^4NՊ%0";,&_eR(0̜>Gcbh'۞6T~ y]()t^T.U1~6aG-Gc[P90r0esٍh.nb+ۺq_:|[p`a?C@VG˞y<'NIPtt4N*3UB  DMg~G X&gj6@ѣ)μ!ؽΉ XHcƴ*NihӋtGmSk%hQ|YhRAK1/*<Q;]]5- ̞P}>!CNVT3xO<@:5]w0`TWkaFZ.~V$d;@~rغzKM;`@쿽Bo\緖rc@vVa'*^lE}N`I& l))I`{|R!P@pÙ?k1H,w+;}kە*H&lEz0 = 'րd E:%yDXc;G}Ie@öo1L%L~WG3C>eID4m8WN9@K'P*{J(Q(yӐ0T|U-H0=@5pÏZW؝(7U֑a;v^srJw?ގch)ܾi?er5.cy}z+NS:ж7 jft>/9[C s14q`TYU*wM酝*֦Xi%cJ!EDۯ=RK 4cEqP%2pN[)*Z7v!/c֩6;-w`8Dd@䢲'O,K1~X6#Gb {P*t~o>?n!VYYq?E90u&گ(dd.|Q"P8Np9@Bj%FDD S'!:ȕn imٮWF}䊮sNjG0sd;P g`` 9dȜpÏY=2&^|>*Ub$̎Y9cӝ-Qɥϴgn’S6J `UG!]Z*{?_ VD$ٟVPd&9+ yє :Q\(TXP\%6 @!,d|a {L2؏?^C @?``{QJ].}-; @dQOR"|!Hfn1gДإpJj«~+/g}FCcٙI, aDb,jϼwq`?—^֋DBG[T굩GxeWQx SUK7?QO-Aܦcv×bs^j JY¡}b&\ /?yvY\䡟:'vɏ?tdӦ.7 |ѧb;O)R@һHsXhrAL ²`[:ϣZh3`0qcNA BDA*XᵖV徟&. qǭ6mj)%55Ցycw '|#z9!@%PDMGB3Y.gr y'S `lhfKSHx[[!WGh .Ҡ WױDn ?n;ˬ;Dk/GtJq`G?RUTFΝ;yT3+mntK/<K2@ 1GD>8)ujީQ!O/݋w>s%-) =WGWvDxGᮮ㻻= Ϡrɒ`)%ƕ)}-w3*v(v|Mpu׉3|*,OQn5`=go2YGsϗ|u׹BV `K:&m2[ ԝ 8q`=ܮtvv.K&ף`„ŋɭ} 譒r;^Z TdQʰSG?'h坷߀3gcQ*lh_ҳB:FW9&VK;8ט3Ǖ>k?U䑇LKq׶qHٗ46.]fΚϽbͺB6f;M)3W%}y^P_ rf v4y,K,@Rx)wvrjiƺǍ)ڶ)cyWcj (T^wpe+wvtt\gY;:0Z Qw:)K{w3ϠpXWQ}0-<8)?9 i"(H@jiӦl/Lʷp%oJq v`v?X9bĈﶌŗ|u3{frŖ(%w(Ge ʭ~s\ggWPP[[UwQ+*j]<avRnSzk`CQ3TUBYM @ـ"' v,.r[ ?iavlJ}1\+s/:`~Kˈ?]~5&.\~h5JQlweBIcs:&r^>v${0r?޸x<~e8j?o.,}}I?XSS_Rٹ^|aj%r\@PTZOKS8SxZ=` ;!{{u[[9x֩lQ8$4b.o@k,ذaPY&N @7ģ)ҀYg}<أ[9oy7)e򇲿rY/‹/TQ~3PXyU/8xЧ4N 2)z);ogi %v %#`wDr2: ̝6uql@ 3y% ~WZ:֭[&Lūk2-55hE ҭ.Bz0eYPu /h 縕/9N*9P/ȽT|LLQ6>WF7f4xϹ#5N ) LZ7vʵ^(H3{e0~b+x y@II?T/,BUkCo|lҤ1*AQ5Mˊb!Pܗ+] Xu0yY[8`9 _)@bAź/?xΞfA?c |du"؀]'t' p!,@@al\᧻ ? W0gJh)yCh`MQĖGP@߬b ;U%lE>=6@ Rc s֠u8[jf)enMnx߃¸q*"rrThfU{q`8Հ-o'~ ~{|DO+6 ƊK7Bj /XXvJ6fAR`% 0-OLzT=T\؂q|>ّHvC`EHOr^ EZn3J<߲}@{9ORY T(` `Cd?P~-Z49 (}́;V@Z`&| j/9|ެP)%菦 ksx9.3PC/""̈́~~tAicH_ǦOȧL(V SiH$Ӑj-+Q TF*:cVeՀgsg򂡁L0 I0Mnm1kb/QH9kתlr#H9%"WB @ȉEjQG!M{_¢Yx~j>t">zdP<@daĻ(>gK_ |w _5u2>m$o%M7_Ω}RIĠ0g9/ܜ{e'}mY8sjuG@~t ['Wqu7,1~N@Nn)p~| ݚb~a$xvK/=Ǐ7~/;-[v8LpԱ$(~Rm J[~0s1cIq~ǓGH@Dw-r۽>ȑ[F(K)xbT`s9iD+aϑI?|eoud f^Ϣrk" ]#fQ^)s]ZTW k˕^~$v &{\r [~} X(/b /1c8Jw מb|V6KKGa775ʎYE+qjC{?IC4J @OL&360+60d ΟC9 T ŋaD^uu+V [fL[2Z=o)9?CEDWIŸmӾ4:)5GSLwF*8ӧLP(tTDXWW7z#/u, lܱiQP(bGQE܄3e/;|ٲ㡪ڮ+?+v߶ ,K)=?D p]&Mp>uuul@ƢD3 Od*3,d27 @n7r]:D}!>ޏ^UMF.Kτ}]D K6 or!_%08N)3if*ED0 0YNd3QKv',R؆=O>py`@ooa-aˆ⑨Mӈ\8b TTTme])K̗ss:X`? 8ٗU!Q- _@ Ԭ!ҁ (́FxWiDɹ ]gO%?gV|?::ކUPp;rDŦHs9TlR'&@ *tN*)(Z# X]gχUU"*WD/Kv-G( F3@{z(}1lɒbXL xg+).0XQn/#a3S:~*Og( ) D2SX(&s@c# #F,%Pv3 q5kw!vWaE"xD|@5@_M3UO]# H1]OsCMTr:$29Zns;]GS'?}:gi!'y<)>/c0_;lڳ~ϢUui.g cSN9:PCh9!^.d劳ծ5y_v9̆.?$'&$O *PC@Ө|s}/VX,/@=SOtY?J] EPE0` m'đ'yV:D$s4EUl3/Hp}YOl|&sO*PpNk /ndG(9RK@:DZl6ׯ_@N=~zd6"z(G)PsJak0Nǎ:p>s ohO@#H%ex5 `$i|7pQ>R8z+1c8zW~ɿt#P?U]C)pf}L\O;41c?(t Pq$p2sCq/3Z[@! LR }=Q8%R4 F^x_1,𜤾sc<4/S>Ixѯ2?sqb7WL@S@fcQqP31d8@!h6 MQ (*e4>&@{Y#?{w=hm_RʰsŮ[&Gti%wzEWulO9x yt: ֭ MSBrP+s:/rPco;N9X:uT: )V)O`vW?N:I-u)5;ݺp!װV8Z/O -| hmg %Q.@ /̀ #F: ́ u;$H> *EL@z=e0])>&muR q+ ot RH^( (w dspK]7i&O8aZ1_ ncN!s԰-z{ `[x饗?8$NrTuyB~2?z<K + z.{83]u6wƂX_#ΡKCUep=&6˞IZ ,HH' zg׳QȪQTT|Ȋf9j"0ZQ g³ynCY}ue[dg_ϛ_ B|%=Ɠ _+LR\OVPnu${gc$7eS?G=vP`wy]E4ƾ>NƍjH EcG@Hܚ~pμ":$7 #pu'\;`Ҥ#wsxJ%! z @S@?tTx4tdTXYP'%#du 8a"Puλ>:-UT>w40SV3stBm@j\R[v @1Bm qLg,끶u0v)gLnl V](y3g3cǎj0-i5? g}zzz,H ? *Q ]r38\͇2(|P{$}d|Qg±܀?CEb;` &a| 揂郴E@rԓfS`h9HMU)] B`LP=?3fS7dMcӎmpf oehMJ_}/ ,dwl )JL$x V<"s;C>ms_% O֤gχ@y;fTD* ^q@XvR g0J7Zd{].'V?|Mm%LT _3DF]y PV;@~NI@۟@D!hG h)NjA|~ya f#~ׂl6x͊{ԛ{d;=N:i 8_ \K+i:+Խp)s1(\2`^ Co@'Tfw)6:{l6 ~,[v l3`3ܢ<ɨ$ g߈K)D,SM},?REسeQ PyXP{(g[d)_h98݅J5@!X0x7E'1,a .--- ]gLT _E1 ]TQ>  <$o oj*_?{旀h8fc_(*\ *=Gs9 PJ67X'M3+`&Z&2(]K#Pv?A'/iF} dZZK T>sBKHjD"kG,16pb>7CP5~<((+>N(?+߁/z@2fLtqRio_-KeK!+8‘*[3bmqO<8k_͚577@Z@Hx2?IMAbb n G`,.+uom]V\nnnehllF?M {nPaP.Pjk߃/!8(GGTd.oiZt.62 E!'Y˨*ey@)4F CDA.l RE%R_lpaΜ NJ>gUww͙L^{+=7pKǣ] F婡 U-;q{gVv< P~yߡŬ?ga@BiXPް pqA H9t1RrCGG; { ;#L~05^?W_&Mĵ2id)H2N ^A3 4@=y`ʔEo"#׿^'|֬mc^oP:LCfK$`w sh CMʸ$R+cM+V`" Md9(,S2PcXxդEߕΛč d#g!MWa#[̙Ӡ4R׻C(8% W_ Wg &mP$FήEg@ ش_);Ҁ˜voi8}s(J&SJPǐCNiΠ )>S`QXLϤYX8 ΃'BUU8i HgR"$"t@WdUެ&݇ W^C/~ XJQ|Kc6lhv {u0cTj8 ,Io4Xb_>I@9B~}v2*_K# 3{w04\1n(dQ!:vl3̚ p@&|OOw|gfV8Ex!_yGS=Tkfʢ3Sؙe8O8پ8w wF_9CvXx{% O 8[󶶵0jT#l9|/:\>x"8ѤXF+*bQUͱ8"dDoxőh@P91*3dӐR@WVljxX$&I'Q+L&.1Kc$$ ~/_L%9U9L28>GIAs),7X}o[v_I+vd_yVI0Q"}ezThMv-@GƵw'w! E7d̽m^GTeQĄжQ;;X*r @ ]@^\suIA_믿{vEZ z]L zZ'@sv.PQ9yNf"X L8Yx|3)8)bе(}z F @(ʦ Ȕ BtK xQ=>1cj !^~!hmƍKOݏ}.0%p IAſtJf/ g"u/_<^J|geуel.+p~4|?JtI/Dq…nd!aN'`Ӧ6gNL)\˯̗}|Sa0vxV]][@M˰('OP5`*`DGwۋf@_)wSK6 ^V]IKDZme7]TrjT8;@4̇ ˖ ^|<^dJdJ1H  wfb-?')PU㠫# HdSR;/7%[iY, w<3Z'Q-Ē6!! tX}~Psxi!J؝<4?_{ q8ǿAAN/j bf.+}0a7S4M5P͊9#' tg4 % õ {~ çĀjyUUi݈|_u`CF|K"Q1ș%Aoz>0E(bNoE><=/ڎlb y8%E^abD C P: te%D]\|%g~^z>̚=jkjEnCT*)Z0M&@2D(BQ E11}çMCw(?޸죏֊IAJ9H,XeN=|jCW ـi(6r -,b5gz6γGv?\kW-k&rQ$kW7SeGnjiZZ/z32W$; KRziYj7ř^#os_W>n dY/+PbT(,rzGP2|JxA@r9e,Ú5Ж;%㎅ &L)åP>_^9Umz,BO@XQtQ4A[K'UXqxI :>`Y|2Ԁ A@<ijt @+?a}T5C;I ()M\$!ȔL)GMKVvaKj߇wĻ <[ m0GS?s uiz~ Z)Lm|"n`9EB^wQ;=RP&1:P%{۵}]uFidytՕQea?܋px'7&O^n`&!jR4Cx"e p>"V` &c1ȔX(V`O~3R3&ϲtu4cb? =0A477L @ۉgss͛s^B!Gqcɳjg+iIT$v %QE~{r^8U,d(t2;a9lBspcp UD1t؆Ŵ m﫱X_?RQXy< u!=Ƥ Eݧsi!-ZP %PLYoun p Q_ p#֌5@˅|E_#=`"i>B|۶;`P(8`a?deT &:)c  85$wKNǸn.需[[nVY.W^*v:=NenN1'\NÑNLڼ&<.VWPUw`ټI@3Y~߹@2X O? +q>l@-\4W,Q\ #^CPv}XxpZ!C8so(uMw%+ܛL4*A_]dT'唾feH{҄;ۏy,Vi֊(*O(C[o˗Jzhr @6&@P }DZQ@}?Lg`;6>6W,tBK =mŃV|Lg DN@ YXIPf@yQS$,OQT "$eJz08~0˃nl9s[! g3Ν{֭+=F:80 hJ(.Sm{5IF]E8?r1-]WK(G8h9{۵ Pt 4j <t~b' j:99AI?&R i )Yd~~:/ @_3\z5je2j9g9:ϡN|ڞu)-Ω4g#eYb!ՊS+~y6'| 1[_{sY1J5M ͵0{v+:&'ҾKe3IG˨P$O>t=9}Q$|JR[x&v@QЌkC,/<̇YZf@A.bGmT~aSL[~`'7X '.2y:_|SiphIE6H^\N*r({Q+4d =" :p\1‘e|LʠsTѡv~w^d c3i0I P$f\8{0a\VԮoMOWSKz^{!u%@iH۞g9F}M]eXDV"s(2a7@b3J Oon,vPaFtN'š+`ܹG˜VMZ< [6M >Лq!xb2bS1"JyhF@:+4Sh5Ro';l~:'8{P ʲDA5 `:Y3s #e|:(BG ŌNdl2K ^54`!vJ ٵK0uUU0-\-6?{nN}:xmw$:Kꢵb֥=Gc]u/^h\>l+1>2clv;;x`]xCWz}/uJϏ>c@93a6h 5u \&aQ 9s/m4Ohd1tRR6AVbkt&]p%N4Vp̪1 ښCs8 yHTym8G$' =9rT㟌dN?(4;v?fY9UUᄛ 6'\ȳɇoHݱ3^K՝ͷ:Y^4z*Vl*~:g\eE~u>Su2k$|k%t6]h3E>uX(,:Z[fj I%ƷM/.7}Hk3ze>C}$^ pHH`X'RR=xJhs_.C.@:! l˖< P+^h|h&|0P#k_Αj x!䤕 r50GXń3A)"T'N$h?(kmyFPntuߒ LUD| \RZqA&~f9sBtq=70~O!t2Z.i)aPL7VB aɬ]SG{i;9m|`e5ͅ+p*/Df6>}/eL[o`.Z.zzo YPtʰWvv@__?I@oٓ~ +5ف~X6>N`c3 l^lh6Ō&a6*Ȫ;M('$L%+_('K/##c1Q*́s@|>@8q,9Q$Lۏ#(=2c0s5 mcnP$iHKKݴ/  C#Mp5 o/ C 'LA Spn<^3*1ۯ~Nr(+V^Ar-,$rS!A`<: МX3\#n]y JU\aɥq/'%ҜBC 80 s_6=}G?IgBT8&Vq"(@_7K`&4 79X2wXݼyRc)ѡ!1+x$URKkZB$t ꋉFY )ו~cF!6:28gY< Ƞ|dEʢ&&t,MDӄcYse%6pe  Sw{7Lϛ! -֐fT-OfgoNXbO-^EPM^D׬]xH+,xS 0rPh8p8pTt<؈3t 53x\&",*s8\>c$xiuFXHf YnX6hIQi `p`FY!nWFg0F~\Mg-?Ro^!(ܨ kM%DžzK0y  U֭hR|DD*hcQ>Y}4XǞT}/ m[0>%KD`~[+TRd T&>&&ky\ȊyG\X8Y:vA>E!m!Bu#`, C6GP^\? 7ΜѦbD*3aCY+<h Y- *=?[U>}#7^) hoE*9G\K?k"Kd@=w˯@wiCd晞b޾^݋Pl"UwOP$%@<N]qS_xa' WâE yu CXTl!;H^Z#(g:ʦ0y !! pQ4=045 6@>AΖ- N٬jDŽa#&|r2S$QaNxS Њ5 Ic u l{&{=hsPd2Ȅ5Q!~ؑ#mr5׭p]h azy6"0aaI VU-Li6\B 9<<}2e5{lRyr>r o ;8{p7qa7@^h-Lڡv6'&^ w 6v?>Z_lϗ:4p~`S7p/+Ka9P_@ >x\N?4vIJx,Ŧ>5%5& % PD!y vqLphe ު*s̚ :g4Acm"a1HiJ ءo%ΐ愦vhaZ ׹ S`B[NSjڔ7nؐgb xW-J ,ْ~a+*GiNjsu~sbf*R*\kڸߓ|QnԽw4y/ Sp@U^-5I1Y%kF`Hv'ya dW<.Ę@@ ;=[^|,SXم[~ݡǔNvoo_ye7 Š٪U ?*+YEEzT'le2GA_DN?B#6ľ8f @r,8>ף7b5YϚNx]u _@]<+ #dML f(}y:r MfAW{t1<2 pӧA\[K"><]n8{za5~X0kyl h/yy0zlue|6]\we fX 9Pt"=CgN7zpSjh?: ;v#GOa.oAqa^mo%͋҄B;(RГG`ֶeZkY,[ZZ**",`X`|-樟&R175xaG@#PTӁ,DhUĕb ?uy Z#phmhj<@ThOpE~1ّ:@.p,#8b(s+G WUx Wxdr 姻ĵ$aoB"#\rNTrM n~õ"ժYF7dܣƽlf$4ظq M~kjeV\Ls0-`ؾcAB$*wsAho?NN-Y~\aW\ hv'dB;"{}^mOEmxǎ7&Ud"υF!UV#FDBmGB@@-^|H@,&pL6cX3zlU jj@hR0D >7e.%S%A~ڒpU*!Hbŷj)bӿA;kpj?,'czi k1hAلi't Do8" c[xPtr<`7Ri45\U 3BP G V<1P2 p6N$|jX21bTXgZn< WTo$۾D D6}&ʚ WyZ`y>9sokj8p d% ƅY 󉉘j>)MN* HжF8 ːJ.Ekz|ޒ!|7Cc=V{<-s "`1gk}/e&&>{peǴtts̳mq8`m|H ׭ ¢y. ъ=wL4j)iqՎKK) 2$)L"pz( 3[g{CKx|c >#oFŒQz^Ut P uT~go@*(~ih^<K׏_?O:M!/KM=S~{!M2'ټ Nh`)u b.?O ֬YN^٬ʏH$|Xrञ8tjD!93TfuB @1t86&d P `p{vhɹ$Ji4>J\qXv&T``V%@/Ff`D/%AiA[+s;EΕtC`곙, Z[QrmX W|r[Jl`z5M4#L! "kpj;y >CE,BZ.~d \lr+オo ~GL d_޽)V$#UR4 u-'yی}̹lj3YU5/hi¦}PS,rV~˞az~r1Lqգ?S $@G02E#p >~.@_fct4uDs<_P06_7 -f>C8HH}W : ™ᎡCȥ@[`v "|n;h%Ë-/J 4 jeRuubКY4+W-61Kw|͛-3g=D&ߡ{! |*=Bm`"~ aA-M8@J4\T 7oZOOQuk& uM"a|Ow"-C\qh`,f6w_@f ^TQWk-*4&Vc Ang<#.ƻ=>@OԶu Zlu¹p a5ق5`99?pݮxso{ݼ lvaoTzs1+j&gqaA,2>Xl6<{¥"|^ye?[t>3UP]]>{/>&V zH 0M>;OIj󭒂(3P'C҂OPE&@jogs8Ʒw~Ğ~f79QvcsZ!r>N6lP+4SIq5Äz7۰R%L%hiඡY9H;' x: ٿyr{9\|Ǯ=O?rl"VYaټlE=S+W"g&P|߰Ҍ !K|+ᵝQu%R,-uޕKe)<W+++jRݧNĊ?,[H|Gf%w3oɒu44S_HGAQXf+Ġ8]%̈́qTӑR=5y)~*ۻ7 N eX֋ : u+y}e4zmpvkFB^QZ<ƴ\3(íl1OW@h  Fxp %xx=_Kݪ+ئsiFT&N 'JX`J?,O9㮀{a5:txdR@d8R*eh{fΨJ5W&xW;?#T*Xp.̚ ɧ|U<pŧ4%} 5Y2=ǩ +c30E܀2#0up|>w(Cwx؍ Zi 0c8p~"5B amVU{AW34J᠄1rS/u}\f'JFSAHi_ 2sG^}?zl97@Xz\q.TdP02"@Rv}ʋCuZU55!ݻPk1!H;ʄ5(eR Bg+kY)'S|͛ƛ1OjB(bgo.n,S~T/;BRQY0 m 611AB"A?d-zh_'뾑,'r{}} UդAa7! Zö R&ɢ0W|>[*ȮZ#̴AvpE `0u1۸ YβV|}#^8q&1-e z'G3>pmZR mmjj*QFfl[|X|CP[[ H5ӫV!'L Wy|:yht)Cep@z*'b(/Ԙ7^{qzk͊.;S? GCLXk(_CCn1 `HO2(^l~jU_WJ,.g3'5)?cI dǻ>>7004sFZT+1;hei"(% =dSL ls{8{{㹐&|M[o~w  B` X9 |ox/kj3f4Auuxx.AX6(I(᧟cw j{>W3Y*Va,AHfcQWڕ'p]Cf4=dxeqs1>(}9@j0EFʫ7n +*W %Ej;VyRPA _n4L]=>8L%!Ϸ?ŋz|W67>3p2-U6z22Z /mn=?̬i&Қ8 ۟0}0227ݴ=m|֬qZ񙥺s-_gCYǠ@đ?+kO@5\jY^X2"!*q -@qbJPcP\Iq#1E]XvuΧ]oP~"&́ax~j*n^'l9kvU7'"TU,CҞW6y 1h@<G>%9s}C?u_Z' ={]3y*Dö`iNX$M+X ,1><9_`:ZxaܙLQYNfsY=SUp#'?IgPHu:fK@Q :2 V/MҵB*?R [;\Doa~=?aFdkm`j~ 7?z5q=8ຫ5ai2-tSd3jR+QL*m| ;0pP0~< q\ۮ7ljD`zrQ<"ᠵjCvK0z6.aV' f:ĝ-xgL.wRb\T9L)f&%(HULk{^S3IKZqicN=/Mku!FE"CyM&,3/ Vv~pQy.rJ@SA^\2a. 6ch0Xp1 L?eޕY&%9QܿRҕK-dȼ{;Y>JG7\v5T_ 1JHHU~/^0MS2 :X{ <.|2 d\% 8M{zG$&͕;USxC_hKәhV ѾE#-|C,`oXa{cTH(B\'q@29CϨ'9! *) a0Ecc=9m>$Rb.A D>Mdg .%p7lrD+B䚋{Y-"3L1R#@&:پ=篾3عk&8/%pMXh~K9`1wS.g"·}dő,mum`b\ Vf/D$t G;O' ][]"g (mg)UzT l_w~g3,[&ͼ&@mC378vt;ĦmTvgǸj6_'gL(i`1!'0vg*K\/qM85[6/cwܲE+qpУC[};5Wľ-oN|pE>8c (=FR1~b|;~v>G"ARCWuX6k*,`:y:rlٲs4(Lt : ?ugxI\a `7M0sWPI>Ia9?<ӽNV[F`=`lF(]_X㖭W-\6; ޴ nq-7x.; m  `Kޔ@`x6 pB!6pfb,C#p`'x{ZHO44\t }f* k^-ՑNNvn(Psc IW)4ja8uUU}:PN= -ޑϋsSC}ݺu5i(8@/ZPPtLyf&uigNW i+)H `f^L'˲BhXB|@{'SD@ςA?Gn4 Q@\L@Q޿d_N}} XTp\@{47W j`Lhmi pc.O3+pxc0Sbx:;&M}J=Zv08`{]wGz*"lsb:~)@Od_T`y%I;?-VXe $Ыͤrhpt13d' WDcSSo_nhol4\~/:U]I*K5]v5s EP|\|h@ Byj.0cfՈf7CccDT":4/u418֣߳_9+K'bY|-ؠcJ9-4s'V}Nu]gx }sbETDx_{ Vlea|m|OiY+/8+{{ & 5dz6E+a (@(٬0MpFVP**<<"5 ^WPY]V!N> txbS# +(SqxSHqC[S'iY p"{[tu Jzm{g~>Tm׳ؒ޾?dNϖKB&}Vs`ygx8Q6/$<)󐣱n-.9DžFЏBHb`phB ? N aJ/sK$)|5 HÌ LBI.ڄR#Xs/A4*"b寮 R2TuuUs(^8qYꕩ*94d<&IP]{A?'bڞ4C02׫p8,|"xR:㞻8wBnJLL\RULYfY3NB7E_ .!x:,1><<##S02*a0Nu1CJ tǢ\X{* Vj*?{P0ыe,PF,Z*+X$ݞF9(i{8FPds N;fD i~Y 0AP c ({KG|AMn;B-naUfV;s5z\p{**vj+'V/ zKNVpcAUx0T.ڕp <}LPlΑfB'15>!LM) dgL!45'Koidoz%,Ǖ .!L'Bn,`C[  aǤ'  C((:6p T!v o=.qJ}^fBa,jl[ͭ05JRD1/Bry @^9ua2<c@TWBegGx>79 Lz Y?Hg^,%iJdy*HLgy:EFHR<9a$t AEd'P OE2/ ˠbsq)&B P|.AĥD# 9b,>99]Ǟ3!I*KK cV~y#ah0^[/پ#ſ!)cUQ CG}/eH|e8˸+zoxճ[BKK%8h2NRIAl41f"f""{uZ LcT,} q]/YKԶ`H`ʮ@2  3X{<^008BRe޴]7KV%2h?H0_RtV!:= {#lÐbR$99r4rUHm$䥂Dț ,pf9({Cat|:XWt= fm(Ie!5*tlcoVDw^}bύ_qø޾ɻc_ta[K%vRXՖqSYNo Ȕ02qa1kl^SrR6 [\WBjjFZ{ 1jp#CxS|pc"V&4A'Brʗ ٓ|<#'"_u=1.0Jԃ}omɢ:l*hn(yLP$CRub;j%8ͮDD-g,3@mz!9Hly)I&ƬwA7fVLD3I~èNg+LLñCHӠ( bS&S {Y#S~Si`^}{^{>.8l^Z?ɩ=gUM֭9Q}n65u#M^SksIe٤dPFy57]-f3 <(ΕbNaFA"_d{ P.=Bݟ ?~y8չ R tLTk, H`y2kL;D(s˃XpMxဧa^}m]2\SOO2:׮w޶WWGdi2 u&{fDܢ3ͺ֯;!r1,BWU p\'BBp{>d38 xǦF#04fjMZyA)3|imi?ٝ7fa|.bB^~!q\ 8naS'>Od ]-[`V!Xu)1iak0ĵ3@&(+71&Y$;#L#B YيAiS.0ثp.䲕se8,LM D"Uu(8)%AlNHIL^gzs$Ci*EQa_ xܴe)HJA6[qslz&ك阓F\R3+  sD"3Yc^Y B#8*n-nϡ̧s <n oG㣧!f8 $r' !Ud-Tf-vziA2S8 _W޹ob_q>qK gzLL Avs`ݚf!`+fδ T{M_ # /m0cMbÌ,>!d/2Ttgs Ãp b|Ɩ?D6b++(h(p8f" Ȍ\'8{Bj5 o*+Vob߳ø eP|[OosBDw>/[\KؠZq[\:L&LA  kg*P X >q|tk>=#CGPQaJ;bRT*PK)&|A@L@񩓱<ٟ}HV: W\{a"MY dQ5F0ov0;!$զnp*OE:>[ef vno^M@0 p: jp|zO NTILJ :/]t>yf (O[SO ?w}O>2\}OOvTXVAC]Ж ĔF2W&qĥM\$Van4Xn'I~I,ցL:&S  k>z9^03ȧ" IĐI9oOT!t3U?{=;v^v]q.q jzcml<*7];njk|f& LgQ+[),P eN3?g,{1+ nfcy<>l((ui5DpPPTc .IxIg^W➷ Xse뢡%S_=m-׷H#a#~f VPtSx!(UU [sɼ(Y-d{R cDg:\[w\]b2\cڶOMXTKhufwa^I66IZ[-&-B-zAP*^"Z̓'*45¦Ԥ/"-7Mycfwv̤q?,Y߿k5o\l˙)-7xɮcQVמ'nW`Է FT;h4J//4{>o {΍_YتuC}ܻvr:]mn6Ҧ|bq4ެ*dA}"y~J}Gm`_^:"ۃs܃AnfX6) M۞(w-rvc7ԍUc, ]h䵅_*}mATv&S3_ jGwP $+yk0 P؟ux8;K O{iOBB+z=x? KY|W!@;2DL&k {u `uurm5W)$Xqkd Xp;=k)qa4A3sy~w:"ٖw4Vdž{Y6W|bv~|kj#F)Ý#_Q <з'RMpqݽo{Y{4k f5xjE}X4;#~yNB>cN~ LSFAە# [4"ݼFEXhw:5Z;JZ}> #Q?d![yk4!/n.S6gds9, @;2OϽL3ovIOFoWSz~tb%!|ج{H.hbrh0 Dcl:x=?i}zbkXw+~CѮuIb&eܼ ;.쑤'3 @`!@`!@`!@`!@`!@`!؟T5P-IENDB`plugins-1.5/generic/chessplugin/figures/black_bishop.png000066400000000000000000000004571336777360500236210ustar00rootroot00000000000000PNG  IHDR((msRGBbKGD pHYs  tIME  [@IDATX0D}?7h2'-3P(ȀX<6Adw\OE n$q|(ř}_23ɹ[]3+l0a̖29$1uֵͼGA<%ؾR>i"P$qn~8,R\=M1#IENDB`plugins-1.5/generic/chessplugin/figures/black_castle.png000066400000000000000000000004141336777360500236010ustar00rootroot00000000000000PNG  IHDR((msRGBbKGD pHYs  tIME +2IDATX 0 Cr$W<$I[g{J 4p{6~*8_ܗ?m]WES$IENDB`plugins-1.5/generic/chessplugin/figures/black_knight.png000066400000000000000000000005511336777360500236140ustar00rootroot00000000000000PNG  IHDR((msRGBbKGD pHYs  tIME hIDATXK0 CqgϪ &N Nڊ:::::$и<=$3\2ZU"8i,FK2{(N up~I$]- uIILc5pXY9"OkobS< 'f[Z51cR8  ϻ#_i9^u$R_W:z>g}=IENDB`plugins-1.5/generic/chessplugin/figures/black_pawn.png000066400000000000000000000003521336777360500232740ustar00rootroot00000000000000PNG  IHDR((msRGBbKGD pHYs  tIME 3sċjIDATX핁!ì;(EO=Qp̖\|˥d\8g.lA$*(wry<37%y3Vf;:F6_,&IENDB`plugins-1.5/generic/chessplugin/figures/black_queen.png000066400000000000000000000005411336777360500234440ustar00rootroot00000000000000PNG  IHDR((msRGBbKGD pHYs  tIME  jMTIDATX0waaH)zΏֳx~ev.p\T=𪦘GwM3j^[Bf :Ŗ:3ՙFG+7 3V?k5Ӛhfɞyr%!ד'ZIJ0>{ʀY  LQ-vb-(G}!uMzQ':5IENDB`plugins-1.5/generic/chessplugin/figures/white_bishop.png000066400000000000000000000005111336777360500236540ustar00rootroot00000000000000PNG  IHDR((msRGBbKGD pHYs  tIME ($ <&IDATXWI 0 ˞Cۡ.q@ XțjH${zd m2ͪ*T(U; BXPRz=VlMSޮSTN&ts&x^*"=XBtI9;4H]>-J ('wЅ˖Kp*d 3P] ^w, K=ʲ'gR~DIENDB`plugins-1.5/generic/chessplugin/figures/white_knight.png000066400000000000000000000006171336777360500236630ustar00rootroot00000000000000PNG  IHDR((msRGBbKGD pHYs  tIME !EIDATXK D.*$HgV-CQcI)GGGGTp"2B+ݵ>fE^DQ;:|^8$oPdA^d6

ce ;?@gfDzrf6N,oj+t k,گS ^$ >h2gkF ^`y+r9֪&He(ԦXԙ'רHN/Q0e̺drE&e/MB@ZPtٟ` & %]I&:^_.vf )IENDB`plugins-1.5/generic/chessplugin/invitationdialog.ui000066400000000000000000000030301336777360500227200ustar00rootroot00000000000000 InvitationDialog 0 0 202 72 0 0 Chess Plugin - Invitation Qt::Horizontal 0 20 Accept Reject plugins-1.5/generic/chessplugin/invitedialog.cpp000066400000000000000000000051211336777360500222020ustar00rootroot00000000000000/* * invitedialog.cpp - plugin * Copyright (C) 2010-2011 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "invitedialog.h" using namespace Chess; InviteDialog::InviteDialog(const Request& _r, const QStringList& resources, QWidget *parent) : QDialog(parent) , resources_(resources) , r(_r) { setAttribute(Qt::WA_DeleteOnClose); ui_.setupUi(this); ui_.cb_resource->setEditable(true); if(!resources.isEmpty()) { ui_.cb_resource->addItems(resources_); } else { ui_.cb_resource->addItem("Enter resource"); } connect(ui_.pb_black, SIGNAL(pressed()), this, SLOT(buttonPressed())); connect(ui_.pb_white, SIGNAL(pressed()), this, SLOT(buttonPressed())); adjustSize(); setFixedSize(size()); } void InviteDialog::buttonPressed() { QString color = "white"; if(ui_.pb_black->isDown()) { color = "black"; } emit play(r, ui_.cb_resource->currentText(), color); close(); } static QString unescape(const QString& escaped) { QString plain = escaped; plain.replace("<", "<"); plain.replace(">", ">"); plain.replace(""", "\""); plain.replace("&", "&"); return plain; } InvitationDialog::InvitationDialog(const QString& jid, QString color, QWidget *parent) : QDialog(parent) { setAttribute(Qt::WA_DeleteOnClose); setModal(false); ui_.setupUi(this); accepted = false; if(color == "white") color = tr("white"); else color = tr("black"); ui_.lbl_text->setText(tr("Player %1 invites you \nto play chess. He wants to play %2.") .arg(unescape(jid)).arg(color)); connect(ui_.pb_accept, SIGNAL(pressed()), this, SLOT(buttonPressed())); connect(ui_.pb_reject, SIGNAL(pressed()), this, SLOT(close())); adjustSize(); setFixedSize(size()); } void InvitationDialog::buttonPressed() { emit accept(); accepted = true; close(); } void InvitationDialog::closeEvent(QCloseEvent *e) { if(!accepted) emit reject(); e->accept(); close(); } plugins-1.5/generic/chessplugin/invitedialog.h000066400000000000000000000031601336777360500216500ustar00rootroot00000000000000/* * invitedialog.h - plugin * Copyright (C) 2010-2011 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef INVITEDIALOG_H #define INVITEDIALOG_H #include #include "ui_invitedialog.h" #include "ui_invitationdialog.h" #include "request.h" namespace Chess { class InviteDialog : public QDialog { Q_OBJECT public: InviteDialog(const Request& r, const QStringList& resources, QWidget *parent = 0); private: Ui::InviteDialog ui_; QStringList resources_; Request r; private slots: void buttonPressed(); signals: void play(const Request& r, const QString&, const QString&); }; class InvitationDialog : public QDialog { Q_OBJECT public: InvitationDialog(const QString& jid, QString color, QWidget *parent = 0); private: Ui::InvitationDialog ui_; bool accepted; private slots: void buttonPressed(); signals: void accept(); void reject(); protected: void closeEvent(QCloseEvent *e); }; } #endif // INVITEDIALOG_H plugins-1.5/generic/chessplugin/invitedialog.ui000066400000000000000000000043671336777360500220500ustar00rootroot00000000000000 InviteDialog 0 0 221 83 0 0 Invitation Select resource: 0 0 Qt::Horizontal 0 20 Qt::Horizontal 0 20 Play White Play Black plugins-1.5/generic/chessplugin/mainwindow.cpp000066400000000000000000000263031336777360500217050ustar00rootroot00000000000000/* * mainwindow.cpp - plugin * Copyright (C) 2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "mainwindow.h" #include #include #include using namespace Chess; SelectFigure::SelectFigure(const QString& player, QWidget *parent) : QWidget(parent) { setAttribute(Qt::WA_DeleteOnClose); setWindowModality(Qt::WindowModal); setFixedSize(62,62); setStyleSheet("QPushButton { background-color: #e9edff;}" "QPushButton:hover { background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #e9edff, stop: 1 black)}"); QGridLayout *layout = new QGridLayout(this); tb_queen = new QPushButton(this); tb_castle = new QPushButton(this); tb_knight = new QPushButton(this); tb_bishop = new QPushButton(this); tb_queen->setFixedSize(25,25); tb_queen->setObjectName("queen"); tb_castle->setFixedSize(25,25); tb_castle->setObjectName("rook"); tb_knight->setFixedSize(25,25); tb_knight->setObjectName("knight"); tb_bishop->setFixedSize(25,25); tb_bishop->setObjectName("bishop"); if(player == "white") { tb_queen->setIcon(QIcon(QPixmap(":/chessplugin/figures/white_queen.png").scaled(22,22, Qt::KeepAspectRatio, Qt::SmoothTransformation))); tb_castle->setIcon(QIcon(QPixmap(":/chessplugin/figures/white_castle.png").scaled(22,22, Qt::KeepAspectRatio, Qt::SmoothTransformation))); tb_knight->setIcon(QIcon(QPixmap(":/chessplugin/figures/white_knight.png").scaled(22,22, Qt::KeepAspectRatio, Qt::SmoothTransformation))); tb_bishop->setIcon(QIcon(QPixmap(":/chessplugin/figures/white_bishop.png").scaled(22,22, Qt::KeepAspectRatio, Qt::SmoothTransformation))); } else { tb_queen->setIcon(QIcon(QPixmap(":/chessplugin/figures/black_queen.png").scaled(22,22, Qt::KeepAspectRatio, Qt::SmoothTransformation))); tb_castle->setIcon(QIcon(QPixmap(":/chessplugin/figures/black_castle.png").scaled(22,22, Qt::KeepAspectRatio, Qt::SmoothTransformation))); tb_knight->setIcon(QIcon(QPixmap(":/chessplugin/figures/black_knight.png").scaled(22,22, Qt::KeepAspectRatio, Qt::SmoothTransformation))); tb_bishop->setIcon(QIcon(QPixmap(":/chessplugin/figures/black_bishop.png").scaled(22,22, Qt::KeepAspectRatio, Qt::SmoothTransformation))); } layout->addWidget(tb_queen,0,0); layout->addWidget(tb_castle,1,0); layout->addWidget(tb_knight,0,1); layout->addWidget(tb_bishop,1,1); connect(tb_queen, SIGNAL(clicked()), this, SLOT(figureSelected())); connect(tb_castle, SIGNAL(clicked()), this, SLOT(figureSelected())); connect(tb_knight, SIGNAL(clicked()), this, SLOT(figureSelected())); connect(tb_bishop, SIGNAL(clicked()), this, SLOT(figureSelected())); } void SelectFigure::figureSelected() { QString objectName = sender()->objectName(); newFigure(objectName); close(); } //------------------------- //----ChessWindow---------- //------------------------- ChessWindow::ChessWindow(Figure::GameType type, bool enableSound_ , QWidget *parent) : QMainWindow(parent) , enabledSound(enableSound_) , movesCount(0) { ui_.setupUi(this); setAttribute(Qt::WA_DeleteOnClose); setFixedSize(610,555); setWindowIcon(QIcon(QPixmap(":/chessplugin/figures/Chess.png"))); setStyleSheet("QMainWindow *{background-color: #ffffe7; color: black; }" "QMenu {background-color: #ffa231;}" "QMenu::item { background-color: #ffa231; padding: 1px; padding-right: 5px; padding-left: 18px; }" "QMenu::item:selected:!disabled {background-color: #ffeeaf; border: 1px solid #74440e; }" "QMenu::item:disabled {color: #646464; }" "QMenu::separator { height: 2px; background: yellow;}" "QMenu::item:checked { background-color: #ffeeaf;}" "QPushButton { background-color: #e9edff;}" "QPushButton:hover { background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #e9edff, stop: 1 black)}"); model_ = new BoardModel(type, this); model_->reset(); ui_.tv_board->setModel(model_); if(type == Figure::WhitePlayer) ui_.tv_board->setCurrentIndex(model_->kingIndex()); else ui_.tv_board->setCurrentIndex(model_->invert(model_->kingIndex())); ui_.te_moves->setText(tr(" White Black\n")); connect(model_, SIGNAL(move(int,int,int,int, QString)), this, SIGNAL(move(int,int,int,int, QString))); connect(model_, SIGNAL(move(int,int,int,int, QString)), this, SLOT(addMove(int,int,int,int))); connect(model_, SIGNAL(figureKilled(Figure*)), this, SLOT(figureKilled(Figure*))); connect(model_, SIGNAL(needNewFigure(QModelIndex, QString)), this, SLOT(needNewFigure(QModelIndex, QString))); createMenu(); } void ChessWindow::closeEvent(QCloseEvent *e) { e->ignore(); emit closeBoard(); } void ChessWindow::moveRequest(int oldX, int oldY, int newX, int newY, const QString& figure) { bool b = model_->moveRequested(oldX, oldY, newX, newY); ui_.tv_board->viewport()->update(); if(!b) emit error(); else { emit moveAccepted(); addMove(oldX, oldY, newX, newY); } if(!figure.isEmpty()) model_->updateFigure(model_->index(7-newY,newX), figure);//7- - for compatibility with tkabber int state = model_->checkGameState(); if(state == 2) emit lose(); else if(state == 1) emit draw(); } void ChessWindow::addMove(int oldX, int oldY, int newX, int newY) { Figure *f = 0; if(model_->gameType_ == Figure::WhitePlayer) { //for compatibility with tkabber oldY = 7-oldY; newY = 7-newY; f = model_->findFigure(model_->index(newY, newX)); } else if(model_->gameType_ == Figure::BlackPlayer) { f = model_->findFigure(model_->index(7-newY, newX)); oldX = 7-oldX; newX = 7-newX; } QString type = " "; if(f) type = f->typeString(); QString text = ui_.te_moves->toPlainText(); int moveNumber = movesCount+2; if(moveNumber&1) { text += " "+type[0]+model_->headerData(oldX, Qt::Horizontal).toString().toLower()+model_->headerData(oldY, Qt::Vertical).toString()+"-" +model_->headerData(newX, Qt::Horizontal).toString().toLower()+model_->headerData(newY, Qt::Vertical).toString()+"\n"; } else { text += QString::number(moveNumber/2)+". "+type[0]+model_->headerData(oldX, Qt::Horizontal).toString().toLower() +model_->headerData(oldY, Qt::Vertical).toString()+"-"+model_->headerData(newX, Qt::Horizontal).toString().toLower() +model_->headerData(newY, Qt::Vertical).toString(); } ui_.te_moves->setText(text); QTextCursor cur = ui_.te_moves->textCursor(); cur.setPosition(text.length()); ui_.te_moves->setTextCursor(cur); movesCount++; } void ChessWindow::createMenu() { QMenuBar *menuBar = ui_.menubar; menuBar->setStyleSheet("QMenuBar::item {background-color: #ffffe7; border-radius: 1px; border: 1px solid #74440e; color: black;" "spacing: 10px; padding: 1px 4px; background: transparent; }" "QMenuBar::item:selected { background-color: #ffeeaf; color: black; }" "QMenuBar::item:pressed { background: #ffeeaf; color: black; }"); QAction *loadAction = new QAction(tr("Load game"), menuBar); QAction *saveAction = new QAction(tr("Save game"), menuBar); QAction *quitAction = new QAction(tr("Quit"), menuBar); loseAction = new QAction(tr("Resign"), menuBar); QAction *soundAction = new QAction(tr("Enable sound"),menuBar); soundAction->setCheckable(true); soundAction->setChecked(enabledSound); QMenu *fileMenu = menuBar->addMenu(tr("File")); QMenu *gameMenu = menuBar->addMenu(tr("Game")); fileMenu->addAction(loadAction); fileMenu->addAction(saveAction); fileMenu->addSeparator(); fileMenu->addAction(quitAction); gameMenu->addAction(loseAction); gameMenu->addSeparator(); gameMenu->addAction(soundAction); connect(loadAction, SIGNAL(triggered()), this, SLOT(load())); connect(saveAction, SIGNAL(triggered()), this, SLOT(save())); connect(quitAction, SIGNAL(triggered()), this, SLOT(close()), Qt::QueuedConnection); connect(loseAction, SIGNAL(triggered()), this, SIGNAL(lose())); connect(soundAction, SIGNAL(triggered(bool)), this, SIGNAL(toggleEnableSound(bool))); } void ChessWindow::load() { QString fileName = QFileDialog::getOpenFileName(0,tr("Load game"), "", tr("*.chs")); if(fileName.isEmpty()) return; QFile file(fileName); if(file.open(QIODevice::ReadOnly)) { QTextStream in(&file); in.setCodec("UTF-8"); QString settings = in.readAll(); model_->loadSettings(settings); if(model_->gameType_ == Figure::WhitePlayer) ui_.tv_board->setCurrentIndex(model_->kingIndex()); else ui_.tv_board->setCurrentIndex(model_->invert(model_->kingIndex())); emit load(settings); ui_.te_moves->setText(tr(" White Black\n")); movesCount = 0; } } void ChessWindow::loadRequest(const QString& settings) { model_->loadSettings(settings, false); if(model_->gameType_ == Figure::WhitePlayer) ui_.tv_board->setCurrentIndex(model_->kingIndex()); else ui_.tv_board->setCurrentIndex(model_->invert(model_->kingIndex())); ui_.te_moves->setText(tr(" White Black\n")); movesCount = 0; } void ChessWindow::save() { QString fileName = QFileDialog::getSaveFileName(0,tr("Save game"), "", tr("*.chs")); if(fileName.isEmpty()) return; if(fileName.right(4) != ".chs") fileName.append(".chs"); QFile file(fileName); if(file.open(QIODevice::WriteOnly | QIODevice::Truncate)) { QTextStream out(&file); out.setCodec("UTF-8"); out.setGenerateByteOrderMark(false); out << model_->saveString(); } } void ChessWindow::figureKilled(Figure *figure) { QPixmap pix = figure->getPixmap().scaled(24,24, Qt::KeepAspectRatio, Qt::SmoothTransformation); QLabel *label = new QLabel; label->setFixedSize(24,24); label->setPixmap(pix); if(figure->gameType() == Figure::WhitePlayer) { ui_.white_layout->addWidget(label); if(!model_->myMove) ui_.tv_board->setCurrentIndex(model_->kingIndex()); } else { ui_.black_layout->addWidget(label); if(!model_->myMove) ui_.tv_board->setCurrentIndex(model_->invert(model_->kingIndex())); } } void ChessWindow::needNewFigure(QModelIndex index, const QString& player) { tmpIndex_ = index; if(model_->gameType_ == Figure::BlackPlayer) index = model_->invert(index); SelectFigure *sf = new SelectFigure(player, this); QPoint pos = ui_.tv_board->pos(); pos.setX(pos.x() + index.column()*50 + 4); pos.setY(pos.y() + index.row()*50 + 25); sf->move(pos); connect(sf, SIGNAL(newFigure(QString)), this, SLOT(newFigure(QString))); sf->show(); } void ChessWindow::newFigure(QString figure) { model_->updateFigure(tmpIndex_, figure); } void ChessWindow::youWin() { model_->gameState_ = 2; model_->updateView(); loseAction->setEnabled(false); } void ChessWindow::youLose() { model_->gameState_ = 3; model_->updateView(); } void ChessWindow::youDraw() { model_->gameState_ = 1; model_->updateView(); } plugins-1.5/generic/chessplugin/mainwindow.h000066400000000000000000000044761336777360500213610ustar00rootroot00000000000000/* * mainwindow.h - plugin * Copyright (C) 2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef MAINWINDOW_H #define MAINWINDOW_H #include #include #include "ui_mainwindow.h" #include "boardview.h" #include "boarddelegate.h" #include "boardmodel.h" using namespace Chess; class ChessWindow : public QMainWindow { Q_OBJECT public: ChessWindow(Figure::GameType type, bool enableSound_, QWidget *parent = 0); void moveRequest(int oldX, int oldY, int newX, int newY, const QString& figure = ""); void loadRequest(const QString& settings); void youWin(); void youLose(); void youDraw(); protected: void closeEvent(QCloseEvent *e); private slots: void figureKilled(Figure* figure); void needNewFigure(QModelIndex index, const QString& player); void newFigure(QString figure); void load(); void save(); void addMove(int,int,int,int); signals: void closeBoard(); void move(int, int, int, int, QString); void moveAccepted(); void error(); void load(QString); void draw(); void lose(); void toggleEnableSound(bool); private: void createMenu(); BoardModel *model_; QModelIndex tmpIndex_; bool enabledSound; int movesCount; QAction *loseAction; Ui::ChessWindow ui_; }; class SelectFigure : public QWidget { Q_OBJECT public: SelectFigure(const QString& player, QWidget *parent = 0); private slots: void figureSelected(); private: QPushButton *tb_queen, *tb_castle, *tb_knight, *tb_bishop; signals: void newFigure(QString figure); }; #endif // MAINWINDOW_H plugins-1.5/generic/chessplugin/mainwindow.ui000066400000000000000000000125571336777360500215460ustar00rootroot00000000000000 ChessWindow 0 0 612 554 0 0 5000 5000 Chess Board Moves: true 170 16777215 Qt::ScrollBarAsNeeded Qt::ScrollBarAlwaysOff true 0 0 414 423 414 423 Qt::ScrollBarAlwaysOff Qt::ScrollBarAlwaysOff false 50 50 50 50 50 50 50 50 0 80 16777215 80 Qt::Horizontal 0 20 Qt::Horizontal 380 20 0 0 612 25 BoardView QTableView

boardview.h
plugins-1.5/generic/chessplugin/options.ui000066400000000000000000000151531336777360500210600ustar00rootroot00000000000000 options 0 0 338 254 Form Select Sounds: Game started: Game finished: Your turn: Error message: 0 0 25 25 25 25 0 0 25 25 25 25 0 0 25 25 25 25 0 0 25 25 25 25 If checked, the sound will always enabled (or disabled) Override default sound settings Disable invitations if status is DND Qt::Vertical 20 0 plugins-1.5/generic/chessplugin/request.h000066400000000000000000000021171336777360500206630ustar00rootroot00000000000000/* * request.h - plugin * Copyright (C) 2011 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef REQUEST_H #define REQUEST_H #include "figure.h" struct Request { int account; QString jid; QString yourJid; Figure::GameType type; QString requestId; QString chessId; bool operator==(const Request& other) { return jid == other.jid && account == other.account; } }; #endif // REQUEST_H plugins-1.5/generic/cleanerplugin/000077500000000000000000000000001336777360500173255ustar00rootroot00000000000000plugins-1.5/generic/cleanerplugin/CMakeLists.txt000066400000000000000000000027461336777360500220760ustar00rootroot00000000000000unset(_HDRS) unset(_UIS) unset(_SRCS) unset(_RSCS) unset(PLUGIN) set( PLUGIN cleanerplugin ) project(${PLUGIN}) cmake_minimum_required(VERSION 3.1.0) set( CMAKE_AUTOMOC TRUE ) IF( NOT WIN32 ) set( LIB_SUFFIX "" CACHE STRING "Define suffix of directory name (32/64)" ) set( PLUGINS_PATH "lib${LIB_SUFFIX}/psi-plus/plugins" CACHE STRING "Install suffix for plugins" ) ELSE() set( PLUGINS_PATH "psi-plus/plugins" CACHE STRING "Install suffix for plugins" ) ENDIF() add_definitions( -DQT_PLUGIN -DHAVE_QT5 ) include_directories( ${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ../../include . ) set( _HDRS ${PLUGIN}.h cleaner.h common.h models.h viewers.h optionsparser.h ) set( _SRCS ${PLUGIN}.cpp cleaner.cpp common.cpp models.cpp viewers.cpp optionsparser.cpp ) set( _UIS cleaner.ui clearingtab.ui ) set( _RSCS ${PLUGIN}.qrc ) find_package( Qt5 COMPONENTS Widgets Xml REQUIRED ) set(QT_DEPLIBS Qt5::Widgets Qt5::Xml ) qt5_wrap_ui(UIS ${_UIS}) qt5_add_resources(RSCS ${_RSCS}) add_library( ${PLUGIN} MODULE ${_SRCS} ${UIS} ${RSCS} ) target_link_libraries( ${PLUGIN} ${QT_DEPLIBS} ) if( UNIX AND NOT( APPLE OR CYGWIN ) ) install( TARGETS ${PLUGIN} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} ) endif() if( WIN32 ) install( TARGETS ${PLUGIN} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} ) endif() plugins-1.5/generic/cleanerplugin/changelog.txt000066400000000000000000000122621336777360500220200ustar00rootroot000000000000002013-08-13 v0.3.2 - taurus + Иконка плагина 2011-10-26 v0.3.1 * заголовок окна изменен на Psi+ Cleaner * теперь при нажатии на кнопку "выделить все" выделяются только отфильтрованные элементы * различные исправления ВНИМАНИЕ!!! Рекомендуется делать бэкапы важных данных перед запуском! 2011-10-25 v0.3.0 * исправлено большое количество накопившихся ошибок, связанных с изменениями в ядре * оптимизации кода, исправление возможных утечек памяти, другие улучшения 2011-05-27 v0.2.11 * пересобрано с новым appHomeDir 2011-01-22 v0.2.10 * исправление для локализации 2010-12-10 v0.2.9 * исправлены некоторые опечатки 2010-11-25 v0.2.8 * некоторые исправления 2010-09-11 v0.2.7 * обновлена ссылка на wiki ( http://psi-plus.com/wiki/plugins#cleaner_plugin ) 2010-05-17 v0.2.6 + добавлена информация о плагине 2010-05-04 v0.2.5 * исправлена ссылка на wiki 2010-03-11 v0.2.4 * обновлены иконки 2010-03-05 v0.2.3 * исправлена сортировка таблицы после удаления элементов * исправлено отображение истории для транспортов * исправлено изменение содержимого таблиц аватаров и опций при смене профиля - убрано выделение правой кнопкой мышки + добавлено контекстное меню на элементах таблиц + в просмотрщике аватар кнопка сохранения аватары перенесена вверх и текст на ней заменён на иконку 2010-03-05 v0.2.2 * исправлено определение местонахождения каталога текущего профиля для ОС семейства Windows + добавлено отображение значений "лишних" опций 2010-03-03 v0.2.1 * исправлена ошибка с выделением правой кнопкой мыши * при чистке кэша дней рождения и жуика удаляются только файлы + просмотр аватары с возможностью сохранения при даблклике + начата работа на чисткой опций 2010-03-02 v0.2.0 * почти полностью переписан код плагина + в настройках плагина запоминается геометрия окна + списки файлов представлены в виде таблиц с возможностью сортировки + выделение файла или группы файлов по нажатию клавиши "пробел" + выделение файла при райтклике по нему + при фильтрации показываются только отфильтрованные элементы + иконки :) 2010-01-27 v0.1.1 + при использовании фильтра выводится сообщение о количестве найденных совпадений + рядом с названием файла истории выводится информация о его размере + рядом с аватарой выводится информация о дате ее создания и о размере 2010-01-18 v0.1.0 * на месте пустых аватар пишется "Empty" * исправления 2010-01-14 v0.0.8 * исправления и оптимизация 2010-01-08 v0.0.7 * различные исправления 2009-12-30 v0.0.6 * исправлены опечатки + добавлены информационные подсказки + добавлен запрос подтверждения на удаление 2009-12-29 v0.0.5 + добавлена строка состояния + добавлено меню + добавлена возможность сменить профиль для очистки + добавлена возможность очистить кэш плагинов juick и birthdayreminder + на вкладке с аватарами также показывается и содержимое каталога pictures + различные исправления и улучшения 2009-12-28 v0.0.3 + добавлена очистка кэша аватар + добавлена возможность выбора файлов по фильтру + добавлена возможность просмотреть историю и vcard 2009-12-26 v0.0.1 ! initial version CAUTION: THIS IS AN ALPHA STAGE PLUGIN. IT CAN DO VERY BAD THINGS. USE AT YOUR OWN RISK. plugins-1.5/generic/cleanerplugin/cleaner.cpp000077500000000000000000000352001336777360500214450ustar00rootroot00000000000000/* * cleaner.cpp - plugin * Copyright (C) 2009-2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "cleaner.h" #include "common.h" #include #include #include CleanerMainWindow::CleanerMainWindow(CleanerPlugin *cleaner) : QMainWindow(0) , cleaner_(cleaner) { setAttribute(Qt::WA_DeleteOnClose); vCardDir_ = cleaner_->appInfo->appVCardDir(); historyDir_ = cleaner_->appInfo->appHistoryDir(); cacheDir_ = cleaner_->appInfo->appHomeDir(ApplicationInfoAccessingHost::CacheLocation); profilesConfigDir_ = cleaner_->appInfo->appProfilesDir(ApplicationInfoAccessingHost::ConfigLocation); profilesDataDir_ = cleaner_->appInfo->appProfilesDir(ApplicationInfoAccessingHost::DataLocation); profilesCacheDir_ = cleaner_->appInfo->appProfilesDir(ApplicationInfoAccessingHost::CacheLocation); ui_.setupUi(this); setWindowIcon(cleaner_->iconHost->getIcon("psi/psiplus_logo")); ui_.pb_close->setIcon(cleaner_->iconHost->getIcon("psi/quit")); ui_.pb_delete->setIcon(cleaner_->iconHost->getIcon("psi/remove")); ui_.tw_tab->setTabIcon(0, cleaner_->iconHost->getIcon("psi/history")); ui_.tw_tab->setTabIcon(1, cleaner_->iconHost->getIcon("psi/vCard")); ui_.tw_tab->setTabIcon(2, cleaner_->iconHost->getIcon("psi/default_avatar")); ui_.tw_tab->setTabIcon(3, cleaner_->iconHost->getIcon("psi/options")); ui_.pb_selectAll->setIcon(cleaner_->iconHost->getIcon("psi/ok")); ui_.pb_unselectAll->setIcon(cleaner_->iconHost->getIcon("psi/cancel")); createMainMenu(); createStatusBar(); } void CleanerMainWindow::showCleaner() { setContent(); show(); } void CleanerMainWindow::createMainMenu() { QMenuBar *mBar = ui_.menuBar; QAction *chooseProf = new QAction(cleaner_->iconHost->getIcon("psi/account"), tr("Choose &Profile"), mBar); QAction *quit = new QAction(cleaner_->iconHost->getIcon("psi/quit"), tr("&Quit"), mBar); QAction *rmJuick = new QAction(cleaner_->iconHost->getIcon("clients/juick"), tr("Clear &Juick Cache"), mBar); QAction *rmBirthday = new QAction(cleaner_->iconHost->getIcon("reminder/birthdayicon"), tr("Clear &Birthdays Cache"), mBar); QMenu *file = mBar->addMenu(tr("&File")); file->addAction(chooseProf); file->addSeparator(); file->addAction(quit); QMenu *act = mBar->addMenu(tr("&Actions")); act->addAction(rmJuick); act->addAction(rmBirthday); connect(chooseProf, SIGNAL(triggered()), this, SLOT(chooseProfileAct())); connect(quit, SIGNAL(triggered()), this, SLOT(close())); connect(rmJuick, SIGNAL(triggered()), this, SLOT(clearJuick())); connect(rmBirthday, SIGNAL(triggered()), this, SLOT(clearBirhday())); } void CleanerMainWindow::createStatusBar() { QStatusBar *sBar = ui_.statusBar; sb1 = new QLabel(sBar); sb2 = new QLabel(sBar); sb3 = new QLabel(sBar); sBar->addWidget(sb1, 1); sBar->addWidget(sb2, 1); sBar->addWidget(sb3, 1); } void CleanerMainWindow::updateStatusBar() { sb1->setText(tr("History files: ") + QString::number(historyModel_->rowCount())); sb2->setText(tr("vCards: ") + QString::number(vcardsModel_->rowCount())); sb3->setText(tr("Avatars: ") + QString::number(avatarModel_->rowCount())); } void CleanerMainWindow::setContent() { historyModel_ = new ClearingHistoryModel(historyDir_, this); proxyHistoryModel_ = new ClearingProxyModel(this); proxyHistoryModel_->setSourceModel(historyModel_); ui_.tab_history->tv_table->setModel(proxyHistoryModel_); ui_.tab_history->tv_table->init(cleaner_->iconHost); vcardsModel_ = new ClearingVcardModel(vCardDir_, this); proxyVcardsModel_ = new ClearingProxyModel(this); proxyVcardsModel_->setSourceModel(vcardsModel_); ui_.tab_vcard->tv_table->setModel(proxyVcardsModel_); ui_.tab_vcard->tv_table->init(cleaner_->iconHost); QStringList avatars; avatars.append(avatarsDir()); avatars.append(picturesDir()); avatarModel_ = new ClearingAvatarModel(avatars, this); proxyAvatarModel_ = new QSortFilterProxyModel(this); proxyAvatarModel_->setSourceModel(avatarModel_); ui_.tab_avatars->tv_table->verticalHeader()->setDefaultSectionSize(120); ui_.tab_avatars->tv_table->setItemDelegateForColumn(1, new AvatarDelegate(this)); ui_.tab_avatars->tv_table->setModel(proxyAvatarModel_); ui_.tab_avatars->tv_table->init(cleaner_->iconHost); QString optionsFile = profilesConfigDir_ + "/" + currentProfileName() + "/options.xml"; optionsModel_ = new ClearingOptionsModel(optionsFile, this); proxyOptionsModel_ = new QSortFilterProxyModel(this); proxyOptionsModel_->setSourceModel(optionsModel_); ui_.tab_options->tv_table->setModel(proxyOptionsModel_); ui_.tab_options->tv_table->init(cleaner_->iconHost); connect(ui_.tab_history->tv_table, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(viewHistory(QModelIndex))); connect(ui_.tab_vcard->tv_table, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(viewVcard(QModelIndex))); connect(ui_.tab_avatars->tv_table, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(viewAvatar(QModelIndex))); connect(ui_.le_filter, SIGNAL(textChanged(QString)), this, SLOT(filterEvent())); connect(ui_.pb_delete, SIGNAL(released()), this, SLOT(deleteButtonPressed())); connect(ui_.tw_tab, SIGNAL(currentChanged(int)), this, SLOT(currentTabChanged(int))); connect(historyModel_, SIGNAL(updateLabel(int)), this, SLOT(currentTabChanged(int))); connect(vcardsModel_, SIGNAL(updateLabel(int)), this, SLOT(currentTabChanged(int))); connect(avatarModel_, SIGNAL(updateLabel(int)), this, SLOT(currentTabChanged(int))); connect(optionsModel_, SIGNAL(updateLabel(int)), this, SLOT(currentTabChanged(int))); connect(ui_.pb_selectAll, SIGNAL(released()), this, SLOT(selectAll())); connect(ui_.pb_unselectAll, SIGNAL(released()), this, SLOT(unselectAll())); connect(ui_.pb_close, SIGNAL(released()), this, SLOT(close())); ui_.le_filter->installEventFilter(this); ui_.tw_tab->setCurrentIndex(0); updateStatusBar(); } static QModelIndexList visibleIndexes(const QSortFilterProxyModel *const model) { int count = model->rowCount(); QModelIndexList l; for(int i = 0; i < count; i++) { QModelIndex index = model->index(i, 0); index = model->mapToSource(index); l.append(index); } return l; } void CleanerMainWindow::selectAll() { int tab = ui_.tw_tab->currentIndex(); switch(tab) { case(0): { QSortFilterProxyModel *model = static_cast(ui_.tab_history->tv_table->model()); historyModel_->selectAll(visibleIndexes(model)); break; } case(1): { QSortFilterProxyModel *model = static_cast(ui_.tab_vcard->tv_table->model()); vcardsModel_->selectAll(visibleIndexes(model)); break; } case(2): { QSortFilterProxyModel *model = static_cast(ui_.tab_avatars->tv_table->model()); avatarModel_->selectAll(visibleIndexes(model)); break; } case(3): { QSortFilterProxyModel *model = static_cast(ui_.tab_options->tv_table->model()); optionsModel_->selectAll(visibleIndexes(model)); break; } } } void CleanerMainWindow::unselectAll() { int tab = ui_.tw_tab->currentIndex(); switch(tab) { case(0): historyModel_->unselectAll(); break; case(1): vcardsModel_->unselectAll(); break; case(2): avatarModel_->unselectAll(); break; case(3): optionsModel_->unselectAll(); break; } } void CleanerMainWindow::filterEvent() { QString text = ui_.le_filter->text(); proxyHistoryModel_->setFilterFixedString(text); proxyVcardsModel_->setFilterFixedString(text); } void CleanerMainWindow::currentTabChanged(int tab) { tab = ui_.tw_tab->currentIndex(); switch(tab){ case(0): ui_.lbl_selected->setText(QString::number(historyModel_->selectedCount())); break; case(1): ui_.lbl_selected->setText(QString::number(vcardsModel_->selectedCount())); break; case(2): ui_.lbl_selected->setText(QString::number(avatarModel_->selectedCount())); break; case(3): ui_.lbl_selected->setText(QString::number(optionsModel_->selectedCount())); break; } updateStatusBar(); } void CleanerMainWindow::deleteButtonPressed() { int tab = ui_.tw_tab->currentIndex(); switch(tab) { case(0): deleteHistory(); break; case(1): deleteVcards(); break; case(2): deleteAvatars(); break; case(3): deleteOptions(); break; } } void CleanerMainWindow::deleteHistory() { int ret = QMessageBox::warning(this, tr("Clear History"), tr("Are You Sure?"), QMessageBox::Ok | QMessageBox::Cancel); if(ret == QMessageBox::Cancel) return; historyModel_->deleteSelected(); updateStatusBar(); } void CleanerMainWindow::deleteVcards() { int ret = QMessageBox::warning(this, tr("Clear vCards"), tr("Are You Sure?"), QMessageBox::Ok | QMessageBox::Cancel); if(ret == QMessageBox::Cancel) return; vcardsModel_->deleteSelected(); updateStatusBar(); } void CleanerMainWindow::deleteAvatars() { int ret = QMessageBox::warning(this, tr("Clear Avatars"), tr("Are You Sure?"), QMessageBox::Ok | QMessageBox::Cancel); if(ret == QMessageBox::Cancel) return; avatarModel_->deleteSelected(); updateStatusBar(); } void CleanerMainWindow::deleteOptions() { int ret = QMessageBox::warning(this, tr("Clear Options"), tr("Not supported yet!"), QMessageBox::Ok | QMessageBox::Cancel); Q_UNUSED(ret); updateStatusBar(); } void CleanerMainWindow::viewVcard(const QModelIndex& index) { QModelIndex modelIndex = proxyVcardsModel_->mapToSource(index); QString filename = vcardsModel_->filePass(modelIndex); new vCardView(filename, this); } void CleanerMainWindow::viewHistory(const QModelIndex& index) { QModelIndex modelIndex = proxyHistoryModel_->mapToSource(index); QString filename = historyModel_->filePass(modelIndex); new HistoryView(filename, this); } void CleanerMainWindow::viewAvatar(const QModelIndex& index) { if(index.column() != 1) return; AvatarView *avaView = new AvatarView(index.data(Qt::DisplayRole).value(), this); avaView->setIcon(cleaner_->iconHost->getIcon("psi/save")); avaView->show(); } void CleanerMainWindow::chooseProfileAct() { QStringList prof; foreach(const QString& dir, QDir(profilesConfigDir_).entryList(QDir::Dirs | QDir::NoDotAndDotDot)) { prof.append(dir); } const QString profile = QInputDialog::getItem(this, tr("Choose profile"), tr("Profile:"), prof, prof.indexOf(currentProfileName()), false); if(!profile.isEmpty()) changeProfile(profile); } void CleanerMainWindow::changeProfile(const QString& profDir) { vCardDir_ = profilesCacheDir_ + QDir::separator() + profDir + QDir::separator() + "vcard"; historyDir_ = profilesDataDir_ + QDir::separator() + profDir + QDir::separator() + "history"; historyModel_->setDirs(QStringList() << historyDir_); vcardsModel_->setDirs(QStringList() << vCardDir_); ; QStringList avatars; avatars.append(avatarsDir()); avatars.append(picturesDir()); avatarModel_->setDirs(avatars); QString optionsFile = profilesConfigDir_ + "/" + currentProfileName() + "/options.xml"; optionsModel_->setFile(optionsFile); updateStatusBar(); } void CleanerMainWindow::clearJuick() { int ret = QMessageBox::warning(this, tr("Clear Juick Cache"), tr("Are You Sure?"), QMessageBox::Ok | QMessageBox::Cancel); if(ret == QMessageBox::Cancel) return; QDir dir(cacheDir_ + QDir::separator() + QString::fromUtf8("avatars") + QDir::separator() + QString::fromUtf8("juick")); if(dir.exists()) { bool b = clearDir(dir.absolutePath()); if(b) { QMessageBox::information(this, tr("Clear Juick Cache"), tr("Juick Cache Successfully Cleared"), QMessageBox::Ok); } else { QMessageBox::critical(this, tr("Clear Juick Cache"), tr("Something wrong!"), QMessageBox::Ok); } } else { QMessageBox::critical(this, tr("Clear Juick Cache"), tr("Cache Not Found!"), QMessageBox::Ok); } } void CleanerMainWindow::clearBirhday() { int ret = QMessageBox::warning(this, tr("Clear Birthdays Cach"), tr("Are You Sure?"), QMessageBox::Ok | QMessageBox::Cancel); if(ret == QMessageBox::Cancel) return; QDir dir(vCardDir_ + QDir::separator() + QString::fromUtf8("Birthdays")); if(dir.exists()) { bool b = clearDir(dir.absolutePath()); if(b) { QMessageBox::information(this, tr("Clear Birthdays Cache"), tr("Birthdays Cache Successfully Cleared"), QMessageBox::Ok); } else { QMessageBox::critical(this, tr("Clear Birthdays Cache"), tr("Something wrong!"), QMessageBox::Ok); } } else { QMessageBox::critical(this, tr("Clear Birthdays Cache"), tr("Cache Not Found!"), QMessageBox::Ok); } } bool CleanerMainWindow::clearDir(const QString& path) { bool b = true; QDir dir(path); foreach (QString filename, dir.entryList(QDir::Files)) { QFile file(path + QDir::separator() + filename); if(file.open(QIODevice::ReadWrite)) { b = file.remove(); if(!b) return b; } } foreach (QString subDir, dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)) { b = clearDir(path + QDir::separator() + subDir); if(!b) return b; } //dir.rmpath(path); //remove dir return b; } void CleanerMainWindow::closeEvent(QCloseEvent *e) { e->ignore(); cleaner_->deleteCln(); } bool CleanerMainWindow::eventFilter(QObject *o, QEvent *e) { if(o == ui_.le_filter && e->type() == QEvent::KeyPress) { QKeyEvent *ke = static_cast(e); if(ke->key() == Qt::Key_Escape) { ui_.le_filter->clear(); return true; } } return QMainWindow::eventFilter(o, e); } QString CleanerMainWindow::avatarsDir() const { return cacheDir_ + QDir::separator() + QString::fromUtf8("avatars"); } QString CleanerMainWindow::picturesDir() const { QString picturesDir = currentProfileDir() + QDir::separator() + QString::fromUtf8("pictures"); return picturesDir; } QString CleanerMainWindow::currentProfileDir() const { QString profileDir = historyDir_; int index = profileDir.size() - profileDir.lastIndexOf("/"); profileDir.chop(index); return profileDir; } QString CleanerMainWindow::currentProfileName() const { QString name = currentProfileDir(); name = name.right(name.size() - name.lastIndexOf("/") - 1); return name; } plugins-1.5/generic/cleanerplugin/cleaner.h000077500000000000000000000050111336777360500211070ustar00rootroot00000000000000/* * cleaner.h - plugin * Copyright (C) 2009-2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef CLEANER_H #define CLEANER_H #include #include "cleanerplugin.h" #include "ui_cleaner.h" #include "models.h" class CleanerMainWindow : public QMainWindow { Q_OBJECT public: CleanerMainWindow(CleanerPlugin *cleaner); virtual ~CleanerMainWindow() {}; void showCleaner(); private: void setContent(); void changeProfile(const QString&); void createStatusBar(); void updateStatusBar(); void createMainMenu(); QString picturesDir() const; QString avatarsDir() const; QString currentProfileDir() const; QString currentProfileName() const; bool clearDir(const QString& path); private slots: void deleteButtonPressed(); void deleteVcards(); void deleteHistory(); void deleteAvatars(); void deleteOptions(); void filterEvent(); void viewVcard(const QModelIndex& index); void viewHistory(const QModelIndex& index); void viewAvatar(const QModelIndex& index); void chooseProfileAct(); void clearJuick(); void clearBirhday(); void currentTabChanged(int tab); void selectAll(); void unselectAll(); protected: void closeEvent(QCloseEvent * event); bool eventFilter(QObject *o, QEvent *e); private: QString vCardDir_, historyDir_, cacheDir_; QString profilesConfigDir_, profilesDataDir_, profilesCacheDir_; QAction *findHistory, *findVcards; QLabel *sb1, *sb2, *sb3; CleanerPlugin *cleaner_; Ui::CleanerMainWindow ui_; ClearingHistoryModel *historyModel_; ClearingVcardModel *vcardsModel_; ClearingAvatarModel *avatarModel_; ClearingOptionsModel *optionsModel_; ClearingProxyModel *proxyHistoryModel_, *proxyVcardsModel_; QSortFilterProxyModel *proxyAvatarModel_, *proxyOptionsModel_; }; #endif // CLEANER_H plugins-1.5/generic/cleanerplugin/cleaner.png000066400000000000000000000011721336777360500214450ustar00rootroot00000000000000PNG  IHDRaAIDATxcdY@ ;x7˞o F) ~30HddbfFFf`߁S:2ZM{/*O_1 4 ^|uOKyrgͺ뙊e7y9K0 c??qUI|}0F3nl r!o!D?sّ7fbu~` I7 HMy0sdHÐc̞r2a'^`!؀]ZEEA \, |bex CYA%& O+STg8b ÖKv 1аf aƹ v9 d:qVЀ`ʋjU5UzbV0H0d@M4[[$ ö;n_׼h=w3m*fp&dرm0z򭃿1iS(bEA;'0>?t̅O4_μpiIENDB`plugins-1.5/generic/cleanerplugin/cleaner.ui000066400000000000000000000121021336777360500212710ustar00rootroot00000000000000 CleanerMainWindow 0 0 800 600 99999 99999 Psi+ Cleaner 3 History vCards Avatars Options Filter: 25 25 Select All Files 25 25 Unselect All Files Qt::Horizontal 40 20 50 0 50 16777215 0 Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter files selected Delete selected files Delete selected Qt::Horizontal 40 20 Close Psi Cleaner Close 0 0 800 25 ClearingTab QWidget
common.h
1
plugins-1.5/generic/cleanerplugin/cleanerplugin.cpp000077500000000000000000000065351336777360500226750ustar00rootroot00000000000000/* * cleanerplugin.cpp - plugin * Copyright (C) 2009-2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "cleanerplugin.h" #include "cleaner.h" #define constVersion "0.3.2" #define constHeight "height" #define constWidth "width" #ifndef HAVE_QT5 Q_EXPORT_PLUGIN(CleanerPlugin); #endif CleanerPlugin::CleanerPlugin() : enabled(false) , appInfo(0) , iconHost(0) , psiOptions(0) , cln(0) , height(650) , width(900) { } QString CleanerPlugin::name() const { return "Cleaner Plugin"; } QString CleanerPlugin::shortName() const { return "cleaner"; } QString CleanerPlugin::version() const { return constVersion; } bool CleanerPlugin::enable() { if(psiOptions) { enabled = true; height = psiOptions->getPluginOption(constHeight, QVariant(height)).toInt(); width = psiOptions->getPluginOption(constWidth, QVariant(width)).toInt(); } return enabled; } bool CleanerPlugin::disable() { if (cln) { delete cln; } enabled = false; return true; } QWidget* CleanerPlugin::options() { if (!enabled) { return 0; } QWidget *options = new QWidget(); QVBoxLayout *hbox= new QVBoxLayout(options); QPushButton *goButton = new QPushButton(tr("Launch Cleaner")); QHBoxLayout *h = new QHBoxLayout; h->addWidget(goButton); h->addStretch(); hbox->addLayout(h); QLabel *wikiLink = new QLabel(tr("
Wiki (Online)")); wikiLink->setOpenExternalLinks(true); hbox->addStretch(); hbox->addWidget(wikiLink); connect(goButton, SIGNAL(released()), SLOT(start())); return options; } void CleanerPlugin::setApplicationInfoAccessingHost(ApplicationInfoAccessingHost * host) { appInfo = host; } void CleanerPlugin::setIconFactoryAccessingHost(IconFactoryAccessingHost* host) { iconHost = host; } void CleanerPlugin::setOptionAccessingHost(OptionAccessingHost* host) { psiOptions = host; } void CleanerPlugin::start() { if(!enabled) return; if(!cln) { cln = new CleanerMainWindow(this); cln->resize(width, height); cln->showCleaner(); } else { cln->raise(); cln->activateWindow(); } } void CleanerPlugin::deleteCln() { height = cln->height(); psiOptions->setPluginOption(constHeight, QVariant(height)); width = cln->width(); psiOptions->setPluginOption(constWidth, QVariant(width)); delete cln; } QString CleanerPlugin::pluginInfo() { return tr("Author: ") + "Dealer_WeARE\n" + tr("Email: ") + "wadealer@gmail.com\n\n" + trUtf8("This plugin is designed to clear the avatar cache, saved local copies of vCards and history logs.\n" "You can preview items before deleting them from your hard drive."); } QPixmap CleanerPlugin::icon() const { return QPixmap(":/cleanerplugin/cleaner.png"); } plugins-1.5/generic/cleanerplugin/cleanerplugin.h000066400000000000000000000045701336777360500223340ustar00rootroot00000000000000/* * cleanerplugin.h - plugin * Copyright (C) 2009-2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef CLEANERPLUGIN_H #define CLEANERPLUGIN_H #include "psiplugin.h" #include "applicationinfoaccessor.h" #include "applicationinfoaccessinghost.h" #include "iconfactoryaccessor.h" #include "iconfactoryaccessinghost.h" #include "optionaccessor.h" #include "optionaccessinghost.h" #include "plugininfoprovider.h" class CleanerMainWindow; class CleanerPlugin : public QObject, public PsiPlugin, public ApplicationInfoAccessor, public IconFactoryAccessor, public OptionAccessor, public PluginInfoProvider { Q_OBJECT #ifdef HAVE_QT5 Q_PLUGIN_METADATA(IID "com.psi-plus.CleanerPlugin") #endif Q_INTERFACES(PsiPlugin ApplicationInfoAccessor IconFactoryAccessor OptionAccessor PluginInfoProvider) public: CleanerPlugin(); virtual QString name() const; virtual QString shortName() const; virtual QString version() const; virtual QWidget* options(); virtual bool enable(); virtual bool disable(); virtual void applyOptions() {}; virtual void restoreOptions() {}; virtual void setApplicationInfoAccessingHost(ApplicationInfoAccessingHost* host); virtual void setIconFactoryAccessingHost(IconFactoryAccessingHost* host); virtual void setOptionAccessingHost(OptionAccessingHost* host); virtual void optionChanged(const QString& ) {}; virtual QString pluginInfo(); virtual QPixmap icon() const; private: bool enabled; ApplicationInfoAccessingHost *appInfo; IconFactoryAccessingHost* iconHost; OptionAccessingHost* psiOptions; QPointer cln; friend class CleanerMainWindow; int height, width; private slots: void start(); void deleteCln(); }; #endif // CLEANERPLUGIN_H plugins-1.5/generic/cleanerplugin/cleanerplugin.pro000077500000000000000000000007041336777360500227030ustar00rootroot00000000000000isEmpty(PSISDK) { include(../../psiplugin.pri) } else { include($$PSISDK/plugins/psiplugin.pri) } INCLUDEPATH += $$PWD DEPENDPATH += $$PWD RESOURCES = cleanerplugin.qrc SOURCES += cleanerplugin.cpp \ cleaner.cpp \ common.cpp \ models.cpp \ viewers.cpp \ optionsparser.cpp HEADERS += cleaner.h \ cleanerplugin.h \ common.h \ models.h \ viewers.h \ optionsparser.h FORMS += cleaner.ui \ clearingtab.ui plugins-1.5/generic/cleanerplugin/cleanerplugin.qrc000066400000000000000000000002111336777360500226560ustar00rootroot00000000000000 default.xml cleaner.png plugins-1.5/generic/cleanerplugin/clearingtab.ui000066400000000000000000000014541336777360500221430ustar00rootroot00000000000000 ClearingTab 0 0 591 429 Form QAbstractItemView::SelectRows ClearingViewer QTableView
viewers.h
plugins-1.5/generic/cleanerplugin/common.cpp000066400000000000000000000116771336777360500213350ustar00rootroot00000000000000/* * common.cpp - plugin * Copyright (C) 2009-2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "common.h" #include #include #include #include #include #include #include #include #include //--------------------------------------------- //--------------HistoryView-------------------- //--------------------------------------------- HistoryView::HistoryView(const QString& filename, QWidget *parent) :QDialog(parent, Qt::Window) { setAttribute(Qt::WA_DeleteOnClose); QFile file(filename); if(file.open(QIODevice::ReadOnly)) { setWindowTitle(filename.split(QDir::separator()).takeLast()); QVBoxLayout *layout = new QVBoxLayout(this); QTextEdit *textWid = new QTextEdit(); QString text; QTextStream in(&file); in.setCodec("UTF-8"); text = in.readAll(); textWid->setText(text); QTextCursor cur = textWid->textCursor(); cur.setPosition(text.length()); textWid->setTextCursor(cur); layout->addWidget(textWid); QPushButton *Close = new QPushButton(tr("Close")); QHBoxLayout *butLayout = new QHBoxLayout(); butLayout->addStretch(); butLayout->addWidget(Close); butLayout->addStretch(); layout->addLayout(butLayout); connect(Close, SIGNAL(released()), this, SLOT(close())); resize(800, 500); show(); } else close(); } //--------------------------------------------- //----------------vCardView-------------------- //--------------------------------------------- vCardView::vCardView(const QString& filename, QWidget *parent) :QDialog(parent, Qt::Window) { setAttribute(Qt::WA_DeleteOnClose); QFile file(filename); if(file.open(QIODevice::ReadOnly)) { setWindowTitle(filename.split(QDir::separator()).takeLast()); QVBoxLayout *layout = new QVBoxLayout(this); QGridLayout *main = new QGridLayout; QLineEdit *name = new QLineEdit; QLineEdit *nick = new QLineEdit; QLineEdit *birth = new QLineEdit; QLineEdit *email = new QLineEdit; main->addWidget(new QLabel(tr("Full Name:")),0,0); main->addWidget(name, 0, 1); main->addWidget(new QLabel(tr("Nick:")), 1, 0); main->addWidget(nick, 1, 1); main->addWidget(new QLabel(tr("Birthday:")), 2, 0); main->addWidget(birth, 2, 1); main->addWidget(new QLabel(tr("E-Mail:")), 3, 0); main->addWidget(email, 3, 1); QTextStream in(&file); in.setCodec("UTF-8"); QDomDocument text; text.setContent(in.readAll()); QDomElement VCard = text.documentElement(); nick->setText(VCard.firstChildElement("NICKNAME").text()); QString Name = VCard.firstChildElement("FN").text(); if(Name.isEmpty()) { QDomElement n = VCard.firstChildElement("N"); Name = n.firstChildElement("FAMILY").text() + " " + n.firstChildElement("GIVEN").text(); } name->setText(Name); birth->setText(VCard.firstChildElement("BDAY").text()); email->setText(VCard.firstChildElement("EMAIL").firstChildElement("USERID").text()); QPushButton *Close = new QPushButton(tr("Close")); QHBoxLayout *butLayout = new QHBoxLayout(); layout->addLayout(main); butLayout->addStretch(); butLayout->addWidget(Close); butLayout->addStretch(); layout->addLayout(butLayout); connect(Close, SIGNAL(released()), this, SLOT(close())); setFixedSize(400,200); show(); } else close(); } //--------------------------------------------- //----------------AvatarView------------------- //--------------------------------------------- AvatarView::AvatarView( const QPixmap &pix, QWidget *parent) : QDialog(parent) , pix_(pix) { setAttribute(Qt::WA_DeleteOnClose); setWindowTitle(tr("Avatar")); QVBoxLayout *layout = new QVBoxLayout(this); QLabel *pixLabel = new QLabel; pixLabel->setPixmap(pix); pbSave = new QPushButton; pbSave->setFixedSize(25,25); pbSave->setToolTip(tr("Save Image")); layout->addWidget(pbSave); layout->addWidget(pixLabel); connect(pbSave, SIGNAL(released()), this, SLOT(save())); adjustSize(); } void AvatarView::setIcon(const QIcon& ico) { pbSave->setIcon(ico); } void AvatarView::save() { QFileDialog dialog(this); dialog.setModal(true); QString filename = dialog.getSaveFileName(this, tr("Save Avatar"),"", tr("Images (*.png *.gif *.jpg *.jpeg)")); if(filename.isEmpty()) return; QImage image = pix_.toImage(); image.save(filename); } plugins-1.5/generic/cleanerplugin/common.h000066400000000000000000000030061336777360500207650ustar00rootroot00000000000000/* * common.h - plugin * Copyright (C) 2009-2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef COMMON_H #define COMMON_H #include #include "ui_clearingtab.h" class vCardView : public QDialog { Q_OBJECT public: vCardView(const QString& filename, QWidget *parent = 0); }; class HistoryView : public QDialog { Q_OBJECT public: HistoryView(const QString& file, QWidget *parent = 0); }; class ClearingTab : public QWidget, public Ui::ClearingTab { Q_OBJECT public: ClearingTab(QWidget * parent = 0) : QWidget(parent) { setupUi(this); }; }; class AvatarView : public QDialog { Q_OBJECT public: AvatarView(const QPixmap &pix, QWidget *parent = 0); void setIcon(const QIcon&); private: QPixmap pix_; QPushButton *pbSave; private slots: void save(); }; #endif // COMMON_H plugins-1.5/generic/cleanerplugin/default.xml000066400000000000000000001140321336777360500214740ustar00rootroot00000000000000 true false true false true true avi asf asx mpg mpg2 mpeg mpe mst mp4 flv 3gp mkv wmv swf rv rm rst dat vob ifo ogv true true true true true true -1 -1 -1 10 true true true true true true true true true true true false true false false false true true true psi/classic true 100 true 32 true true false false true never false false false false true false true true false false false false 325 10 barejid 500 180 640 480 false 100 true false true true true true true false alpha /* frame of avatar - general settings */ /* фрейм с аватаром - общие настройки */ RosterAvatarFrame * { margin: 1px; } /* frame of avatar - avatar */ /* фрейм с аватаром - аватар */ QLabel#lb_avatar { margin-left: 0px; margin-top: 2px; margin-bottom: 2px; border: 1px solid #949494; border-radius: 3px; } /* frame of avatar - nick */ /* фрейм с аватаром - ник */ QLabel#lb_nick { margin: 2px; margin-right: 1px; margin-bottom: 3px; border: 1px solid #949494; border-radius: 3px; } /* frame of avatar - buttons of PEP and status */ /* фрейм с аватаром - кнопки PEP и статуса */ QToolButton#tb_status, #tb_mood, #tb_activity { margin-left: 1px; margin-right: 1px; margin-bottom: 2px; width: 100%; } QToolButton#tb_status { margin-top: 0px; margin-bottom: 1px; } /* frame of avatar - button of status, arrow */ /* фрейм с аватаром - кнопка статуса, стрелка */ QToolButton#tb_status::menu-indicator { image: url(); } /* frame of avatar - field of status message */ /* фрейм с аватаром - строка статусного сообщения */ QLineEdit#le_status_text { margin-right: 0px; margin-bottom: 2px; } false false true true status false true true alpha false false false true false true true true true true true false true true false true 24 5 true true true true false true true false false false true false true 64 64 150 360 0 0 0 0 0 false false 52 0 true true true true
true
true true false true
false true false true true true alpha true false 24 true 3 false false 500 80 false 580 420 truetruetruetrue false true false false true false true 0 true false true false #f0f0f0 #5a5a5a #969696 #ffffff #004bb4 #7e0000 #646464 #000000 #969696 #808080 true #e9ecc7 #000000 Blue Green Orange Purple Red #910000 #00008a #336600 black #0000ff #ff0000 #008000 #606060 #FF0000 #0000ff #0000ff darkGreen red #5297f9 false false Sans Serif,9,-1,5,50,0,0,0,0,0 Sans Serif,9,-1,5,50,0,0,0,0,0 Sans Serif,9,-1,5,50,0,0,0,0,0 Sans Serif,7,-1,5,50,0,0,0,0,0 animate forever true true 5000 5000 5000 2000 false false false true true true true true false 25 300 -1 48 true true false true true sound/chat2.wav sound/ft_complete.wav sound/offline.wav sound/online.wav true sound/ft_incoming.wav sound/chat2.wav sound/chat2.wav sound/chat1.wav false sound/send.wav false sound/chat2.wav true true false false true false true true false true close detach CM true
Ctrl+PgDown Ctrl+Tab Ctrl+PgUp Ctrl+Shift+Tab Ctrl+F Return Enter Ctrl+Space Alt+Home Alt+End Ctrl+Down Ctrl+Up Ctrl+Alt+x Shift+Del Ctrl+C Ctrl+M Ctrl+R F2 Ctrl+L Shift+PgUp Shift+PgDown Ctrl+Q Ctrl+W ESC Alt+H Ctrl+H Ctrl+I Ctrl+Alt+B Ctrl+Return Ctrl+Enter Alt+Return Alt+Enter Ctrl+Return Ctrl+Enter Alt+Return Alt+Enter false true false false 600 false default default default default default default default chat true no false false true false false 8010 true true false false true true true true 10 false false 30 0 true true false away true false submenu false true true false 50 50 40 30 20 10 false true false
plugins-1.5/generic/cleanerplugin/models.cpp000066400000000000000000000305321336777360500213170ustar00rootroot00000000000000/* * models.cpp - plugin * Copyright (C) 2009-2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "models.h" #include "optionsparser.h" #include #include #include //---------------------------------------- //--BaseModel----------------------------- //---------------------------------------- void BaseModel::reset() { selected_.clear(); beginResetModel(); endResetModel(); } int BaseModel::selectedCount(const QModelIndex &) const { return selected_.size(); } void BaseModel::selectAll(const QModelIndexList& list) { emit layoutAboutToBeChanged(); selected_.clear(); selected_ = list.toSet(); emit updateLabel(0); emit layoutChanged(); } void BaseModel::unselectAll() { emit layoutAboutToBeChanged(); selected_.clear(); emit updateLabel(0); emit layoutChanged(); } bool BaseModel::isSelected(const QModelIndex &index) const { return selected_.contains(index); } Qt::ItemFlags BaseModel::flags(const QModelIndex &index) const { Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled; if(index.column() == 0) flags |= Qt::ItemIsUserCheckable; return flags; } bool BaseModel::setData(const QModelIndex & index, const QVariant & value, int role) { if(!index.isValid() || role != Qt::EditRole || index.column() != 0) return false; switch(value.toInt()) { case(0): if(selected_.contains(index)) selected_.remove(index); break; case(2): if(!selected_.contains(index)) selected_ << index; break; case(3): if(selected_.contains(index)) selected_.remove(index); else selected_ << index; break; } emit dataChanged(index, index); emit updateLabel(0); return true; } QVariant BaseModel::headerData(int section, Qt::Orientation orientation, int role) const { if (role == Qt::DisplayRole) { if (orientation == Qt::Horizontal) { return headers.at(section); } else { return section+1; } } else return QVariant(); } int BaseModel::columnCount(const QModelIndex & /*parent*/) const { return headers.size(); } //--------------------------------------- //------BaseFileModel-------------------- //--------------------------------------- void BaseFileModel::reset() { files_.clear(); BaseModel::reset(); } int BaseFileModel::rowCount(const QModelIndex &/* parent*/) const { return files_.size(); } QString BaseFileModel::fileName(const QModelIndex & index) const { if(!index.isValid()) return QString(); int i = index.row(); if(i < 0 || i >= files_.size()) return QString(); QString name = files_.at(i); return name.split("/", QString::SkipEmptyParts).last(); } QString BaseFileModel::filePass(const QModelIndex & index) const { if(!index.isValid()) return QString(); int i = index.row(); if(i < 0 || i >= files_.size()) return QString(); return files_.at(i); } int BaseFileModel::fileSize(const QModelIndex & index) const { if(!index.isValid()) return 0; QFile file(filePass(index)); return file.size(); } QString BaseFileModel::fileDate(const QModelIndex & index) const { if(!index.isValid()) return QString(); return QFileInfo(filePass(index)).created().toString("yyyy-MM-dd"); } void BaseFileModel::deleteSelected() { emit layoutAboutToBeChanged (); foreach(const QModelIndex& index, selected_) { const QString fileName = filePass(index); if(fileName.isEmpty()) continue; QFile file(fileName); if(file.open(QIODevice::ReadWrite)) { file.remove(); } } setDirs(dirs_); emit updateLabel(0); } void BaseFileModel::setDirs(const QStringList& dirs) { reset(); dirs_ = dirs; foreach(const QString& dirName, dirs_) { QDir Dir(dirName); foreach(const QString& fileName, Dir.entryList(QDir::Files)) { files_.append(Dir.absoluteFilePath(fileName)); } } emit layoutChanged(); } //---------------------------------------- //--ClearingModel------------------------- //---------------------------------------- ClearingModel::ClearingModel(const QString& dir, QObject* parent) : BaseFileModel(parent) { headers << tr("") << tr("Nick") << tr("Domain") << tr("Size") << tr("Creation Date"); setDirs(QStringList() << dir); } QVariant ClearingModel::data(const QModelIndex & index, int role) const { if(!index.isValid()) return QVariant(); int i = index.column(); QString filename = fileName(index); filename = filename.replace("%5f", "_"); filename = filename.replace("%2d", "-"); filename = filename.replace("%25", "@"); switch(i) { case(0): if (role == Qt::CheckStateRole) { return isSelected(index) ? 2:0; } else if (role == Qt::TextAlignmentRole) { return (int)(Qt::AlignRight | Qt::AlignVCenter); } else if (role == Qt::DisplayRole) return QVariant(""); case(1): if (role == Qt::TextAlignmentRole) { return (int)(Qt::AlignRight | Qt::AlignVCenter); } else if (role == Qt::DisplayRole) { if(filename.contains("_at_")) return QVariant(filename.split("_at_").first()); else return QVariant(); } case(2): if (role == Qt::TextAlignmentRole) { return (int)(Qt::AlignRight | Qt::AlignVCenter); } else if (role == Qt::DisplayRole) return QVariant(filename.split("_at_").last()); case(3): if (role == Qt::TextAlignmentRole) { return (int)(Qt::AlignRight | Qt::AlignVCenter); } else if (role == Qt::DisplayRole) return QVariant(fileSize(index)); case(4): if (role == Qt::TextAlignmentRole) { return (int)(Qt::AlignRight | Qt::AlignVCenter); } else if (role == Qt::DisplayRole) return QVariant(fileDate(index)); } return QVariant(); } //---------------------------------------- //--ClearingVcardModel-------------------- //---------------------------------------- QVariant ClearingVcardModel::data(const QModelIndex & index, int role) const { if(index.column() == 2) { if (role == Qt::DisplayRole) { QString domain = fileName(index).split("_at_").last(); domain.chop(4); domain = domain.replace("%5f", "_"); domain = domain.replace("%2d", "-"); domain = domain.replace("%25", "@"); return QVariant(domain); } } return ClearingModel::data(index, role); } //---------------------------------------- //--ClearingHistoryModel------------------ //---------------------------------------- QVariant ClearingHistoryModel::data(const QModelIndex & index, int role) const { QString filename = fileName(index); filename = filename.replace("%5f", "_"); filename = filename.replace("%2d", "-"); filename = filename.replace("%25", "@"); if (role == Qt::DisplayRole) { if(index.column() == 2) { QString domain; if(filename.contains("_in_")){ domain = filename.split("_in_").last(); domain = domain.replace("_at_", "@"); } else { domain = filename.split("_at_").last(); domain.remove(".history"); } return QVariant(domain); } else if(index.column() == 1) { QString jid; if(filename.contains("_in_")){ jid = filename.split("_in_").first(); jid = jid.replace("_at_", "@"); } else { if(filename.contains("_at_")) return QVariant(filename.split("_at_").first()); else return QVariant(); } } } return ClearingModel::data(index, role); } //---------------------------------------- //--ClearingAvatarModel------------------- //---------------------------------------- ClearingAvatarModel::ClearingAvatarModel(const QStringList& dir, QObject* parent) : BaseFileModel(parent) { headers << tr("") << tr("Avatar") << tr("Size") << tr("Creation Date"); setDirs(dir); } QVariant ClearingAvatarModel::data(const QModelIndex & index, int role) const { if(!index.isValid()) return QVariant(); int i = index.column(); QString filename = filePass(index); switch(i) { case(0): if (role == Qt::CheckStateRole) { return isSelected(index) ? 2:0; } else if (role == Qt::TextAlignmentRole) { return (int)(Qt::AlignRight | Qt::AlignVCenter); } else if (role == Qt::DisplayRole) return QVariant(""); case(1): if (role == Qt::TextAlignmentRole) { return (int)(Qt::AlignRight | Qt::AlignVCenter); } else if (role == Qt::DisplayRole) { QPixmap pix = QPixmap(filename); if(pix.isNull()) return QVariant(); return QVariant(pix); } case(2): if (role == Qt::TextAlignmentRole) { return (int)(Qt::AlignRight | Qt::AlignVCenter); } else if (role == Qt::DisplayRole) return QVariant(fileSize(index)); case(3): if (role == Qt::TextAlignmentRole) { return (int)(Qt::AlignRight | Qt::AlignVCenter); } else if (role == Qt::DisplayRole) return QVariant(fileDate(index)); } return QVariant(); } //---------------------------------------- //--ClearingOptionsModel------------------ //---------------------------------------- ClearingOptionsModel::ClearingOptionsModel(const QString& fileName, QObject* parent) : BaseModel(parent) , fileName_(fileName) { headers << tr("") << tr("Options") << tr("Values"); parser_ = new OptionsParser(fileName_, this); options = parser_->getMissingNodesString(); } int ClearingOptionsModel::rowCount(const QModelIndex &/* parent*/) const { return options.size(); } QVariant ClearingOptionsModel::data(const QModelIndex & index, int role) const { if(!index.isValid()) return QVariant(); int i = index.column(); switch(i) { case(0): if (role == Qt::CheckStateRole) { return isSelected(index) ? 2:0; } else if (role == Qt::TextAlignmentRole) { return (int)(Qt::AlignRight | Qt::AlignVCenter); } else if (role == Qt::DisplayRole) return QVariant(""); case(1): if (role == Qt::TextAlignmentRole) { return (int)(Qt::AlignLeft | Qt::AlignVCenter); } else if (role == Qt::DisplayRole) { return QVariant(options.at(index.row())); } case(2): if (role == Qt::TextAlignmentRole) { return (int)(Qt::AlignLeft | Qt::AlignVCenter); } else if (role == Qt::DisplayRole) { QDomNode node = parser_->nodeByString(options.at(index.row())); return QVariant(node.toElement().text()); } } return QVariant(); } void ClearingOptionsModel::deleteSelected() { emit layoutAboutToBeChanged (); setFile(fileName_); emit updateLabel(0); } void ClearingOptionsModel::reset() { options.clear(); BaseModel::reset(); } void ClearingOptionsModel::setFile(const QString& fileName) { emit layoutAboutToBeChanged (); reset(); fileName_ = fileName; delete parser_; parser_ = new OptionsParser(fileName_, this); options = parser_->getMissingNodesString(); emit layoutChanged(); } //---------------------------------------- //--ClearingProxyModel-------------------- //---------------------------------------- ClearingProxyModel::ClearingProxyModel(QObject *parent) : QSortFilterProxyModel(parent) { setDynamicSortFilter(true); } bool ClearingProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &parent) const { QModelIndex index1 = sourceModel()->index(sourceRow, 1, parent); QModelIndex index2 = sourceModel()->index(sourceRow, 2, parent); bool b = index1.data(Qt::DisplayRole).toString().contains(filterRegExp()); bool c = index2.data(Qt::DisplayRole).toString().contains(filterRegExp()); return (b | c); } plugins-1.5/generic/cleanerplugin/models.h000066400000000000000000000113731336777360500207660ustar00rootroot00000000000000/* * models.h - plugin * Copyright (C) 2009-2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef MODELS_H #define MODELS_H #include #include #include #include class OptionsParser; //--------------------------------- //------BaseModel------------------ //--------------------------------- class BaseModel : public QAbstractTableModel { Q_OBJECT public: BaseModel(QObject* p = 0) : QAbstractTableModel(p) {}; virtual bool setData ( const QModelIndex & index, const QVariant & value, int role = Qt::EditRole ); virtual QVariant headerData ( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const; virtual Qt::ItemFlags flags ( const QModelIndex & index ) const; virtual int columnCount ( const QModelIndex & parent = QModelIndex() ) const; virtual void reset(); int selectedCount(const QModelIndex & parent = QModelIndex()) const; void selectAll(const QModelIndexList& list); void unselectAll(); virtual void deleteSelected() = 0; protected: bool isSelected(const QModelIndex& index) const; protected: QStringList headers; QSet selected_; signals: void updateLabel(int); }; //--------------------------------- //------BaseFileModel-------------- //--------------------------------- class BaseFileModel : public BaseModel { Q_OBJECT public: BaseFileModel(QObject* p = 0) : BaseModel(p) {}; virtual int rowCount ( const QModelIndex & parent = QModelIndex() ) const; QString filePass(const QModelIndex & index) const; virtual void reset(); virtual void deleteSelected(); void setDirs(const QStringList& dirs); protected: QString fileName(const QModelIndex & index) const; int fileSize(const QModelIndex & index) const; QString fileDate(const QModelIndex & index) const; private: QStringList files_, dirs_; }; //--------------------------------- //------ClearingModel-------------- //--------------------------------- class ClearingModel : public BaseFileModel { Q_OBJECT public: ClearingModel(const QString& dir, QObject *parent = 0); virtual QVariant data ( const QModelIndex & index, int role = Qt::DisplayRole ) const; }; //--------------------------------- //------ClearingVcardModel--------- //--------------------------------- class ClearingVcardModel : public ClearingModel { Q_OBJECT public: ClearingVcardModel(const QString& dir, QObject *parent = 0) : ClearingModel(dir, parent) {}; virtual QVariant data ( const QModelIndex & index, int role = Qt::DisplayRole ) const; }; //--------------------------------- //------ClearingHistoryModel------- //--------------------------------- class ClearingHistoryModel : public ClearingModel { Q_OBJECT public: ClearingHistoryModel(const QString& dir, QObject *parent = 0) : ClearingModel(dir, parent) {}; virtual QVariant data ( const QModelIndex & index, int role = Qt::DisplayRole ) const; }; //--------------------------------- //------ClearingAvatarModel-------- //--------------------------------- class ClearingAvatarModel : public BaseFileModel { Q_OBJECT public: ClearingAvatarModel(const QStringList& dir, QObject *parent = 0); virtual QVariant data ( const QModelIndex & index, int role = Qt::DisplayRole ) const; }; //--------------------------------- //------ClearingOptionsModel------- //--------------------------------- class ClearingOptionsModel : public BaseModel { Q_OBJECT public: ClearingOptionsModel(const QString& fileName, QObject *parent = 0); virtual QVariant data ( const QModelIndex & index, int role = Qt::DisplayRole ) const; virtual int rowCount ( const QModelIndex & parent = QModelIndex() ) const; virtual void deleteSelected(); virtual void reset(); void setFile(const QString& fileName); private: QStringList options; QString fileName_; OptionsParser *parser_; }; //--------------------------------- //------ClearingProxyModel--------- //--------------------------------- class ClearingProxyModel : public QSortFilterProxyModel { Q_OBJECT public: ClearingProxyModel(QObject *parent = 0); bool filterAcceptsRow(int sourceRow, const QModelIndex &parent) const; }; #endif // MODELS_H plugins-1.5/generic/cleanerplugin/optionsparser.cpp000066400000000000000000000057071336777360500227520ustar00rootroot00000000000000/* * optionsparser.cpp - plugin * Copyright (C) 2009-2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "optionsparser.h" #include OptionsParser::OptionsParser(const QString& fileName, QObject *parent) : QObject(parent) , fileName_(fileName) { QFile optionsFile(fileName_); QFile defaultsFile(":/cleanerplugin/default.xml"); QDomDocument optionsDoc, defaultsDoc; optionsDoc.setContent(&optionsFile); defaultsDoc.setContent(&defaultsFile); QDomElement optionsElement = optionsDoc.documentElement(); QDomElement defaultsElement = defaultsDoc.documentElement(); defaultsElement_ = defaultsElement.firstChildElement("options"); optionsElement_ = optionsElement.firstChildElement("options"); QString root; findMissingOptions(optionsElement_, &root); } QStringList OptionsParser::getMissingNodesString() const { return missingNodes.keys(); } QList OptionsParser::getMissingNodes() const { return missingNodes.values(); } QDomNode OptionsParser::nodeByString(const QString& key) const { return missingNodes.value(key); } void OptionsParser::findMissingOptions(const QDomElement& optElement, QString *root) { QDomNode optionNode = optElement.firstChild(); while(!optionNode.isNull()) { if(!findNode(optionNode.toElement())) { QString nodeString = *root + optElement.tagName() + "." + optionNode.toElement().tagName(); missingNodes[nodeString] = optionNode; } QDomNode childNode = optionNode.firstChild(); while(!childNode.isNull()) { QString childRoot = *root + optElement.tagName()+"." + optionNode.toElement().tagName() + "."; findMissingOptions(childNode.toElement(), &childRoot); childNode = childNode.nextSibling(); } optionNode = optionNode.nextSibling(); } *root += optElement.tagName()+"."; } bool OptionsParser::findNode(const QDomElement& elem) const { QString tag = elem.tagName(); if(defaultsElement_.elementsByTagName(tag).isEmpty()) return false; else return true; } /*QString OptionsParser::nodeToString(QDomNode node) { QString optionText; optionText = node.toElement().tagName(); QDomNode option = node.firstChild(); while(!option.isNull()) { optionText += QString(".") + option.toElement().tagName(); option = option.nextSibling(); } return optionText; }*/ plugins-1.5/generic/cleanerplugin/optionsparser.h000066400000000000000000000026641336777360500224160ustar00rootroot00000000000000/* * optionsparser.h - plugin * Copyright (C) 2009-2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef OPTIONSPARSER_H #define OPTIONSPARSER_H #include #include #include #include class OptionsParser : public QObject { Q_OBJECT public: OptionsParser(const QString& fileName, QObject *parent = 0); QStringList getMissingNodesString() const; QList getMissingNodes() const; QDomNode nodeByString(const QString& key) const; private: QString fileName_; QDomElement optionsElement_, defaultsElement_; QMap missingNodes; void findMissingOptions(const QDomElement& optElement, QString *root); bool findNode(const QDomElement& elem) const; }; #endif // OPTIONSPARSER_H plugins-1.5/generic/cleanerplugin/viewers.cpp000066400000000000000000000111431336777360500215150ustar00rootroot00000000000000/* * viewers.cpp - plugin * Copyright (C) 2009-2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "viewers.h" #include #include #include #include #include "iconfactoryaccessinghost.h" //------------------------------------------ //-----------ClearingViewer----------------- //------------------------------------------ void ClearingViewer::init(IconFactoryAccessingHost *iconHost) { iconHost_ = iconHost; resizeColumnsToContents(); #ifdef HAVE_QT5 horizontalHeader()->setSectionResizeMode(0, QHeaderView::ResizeToContents); #else horizontalHeader()->setResizeMode(0, QHeaderView::ResizeToContents); #endif horizontalHeader()->setStretchLastSection(true); horizontalHeader()->setSortIndicator(-1, Qt::AscendingOrder); verticalHeader()->setDefaultAlignment( Qt::AlignHCenter ); connect(horizontalHeader(), SIGNAL(sectionClicked(int)), this, SLOT(sortByColumn(int))); connect(this, SIGNAL(clicked(QModelIndex)), this, SLOT(itemClicked(QModelIndex))); } void ClearingViewer::keyPressEvent(QKeyEvent * e) { if (e->key() == Qt::Key_Space) { foreach(const QModelIndex &check, selectionModel()->selectedRows(0)) { model()->setData(check, 3); //invert } e->accept(); } else { QTableView::keyPressEvent(e); e->ignore(); } } void ClearingViewer::contextMenuEvent( QContextMenuEvent * e ) { QMenu *popup = new QMenu(this); QList actions; actions <getIcon("psi/cm_check"), tr("Check"), popup) <getIcon("psi/cm_uncheck"), tr("Uncheck"), popup) <getIcon("psi/cm_invertcheck"), tr("Invert"), popup); popup->addActions(actions); QAction *result = popup->exec(e->globalPos()); int iresult; if (result) { iresult = actions.indexOf(result); foreach(const QModelIndex &check, selectionModel()->selectedRows(0)) { switch (iresult) { case 0: //check model()->setData(check, QVariant(2)); break; case 1: //uncheck model()->setData(check, QVariant(0)); break; case 2: //invert model()->setData(check, QVariant(3)); break; } } } delete popup; } void ClearingViewer::itemClicked(const QModelIndex& index) { if(index.column() == 0) { model()->setData(currentIndex(), 3); //invert } } //------------------------------------------ //-----------AvatarDelegate----------------- //------------------------------------------ QSize AvatarDelegate::sizeHint(const QStyleOptionViewItem & /*option*/, const QModelIndex & index) const { if(!index.isValid()) return QSize(0,0); return QSize(300, 120); } void AvatarDelegate::paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const { QPalette palette = option.palette; QRect r = option.rect; QColor c = (option.state & QStyle::State_Selected) ? palette.color(QPalette::Highlight) : palette.color(QPalette::Base); painter->fillRect(r, c); QPixmap pix = index.data(Qt::DisplayRole).value(); painter->save(); painter->setClipRect(r); if(!pix.isNull()) { pix = pix.scaled(100,100, Qt::KeepAspectRatio, Qt::SmoothTransformation); r.translate(10,10); r.setSize(pix.size()); painter->drawPixmap(r, pix); } else { QPalette::ColorGroup cg = option.state & QStyle::State_Enabled ? QPalette::Normal : QPalette::Disabled; if (option.state & QStyle::State_Selected) { painter->setPen(option.palette.color(cg, QPalette::HighlightedText)); } else { painter->setPen(option.palette.color(cg, QPalette::Text)); } r.translate(20,50); painter->drawText(r, tr("Empty file")); } painter->restore(); } plugins-1.5/generic/cleanerplugin/viewers.h000066400000000000000000000033331336777360500211640ustar00rootroot00000000000000/* * viewers.h - plugin * Copyright (C) 2009-2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef VIEWERS_H #define VIEWERS_H #include #include #include class IconFactoryAccessingHost; class ClearingViewer : public QTableView { Q_OBJECT public: ClearingViewer(QWidget *parent = 0) : QTableView(parent) {}; // virtual ~ClearingViewer() {}; void init(IconFactoryAccessingHost *iconHost); private: IconFactoryAccessingHost *iconHost_; protected: void keyPressEvent(QKeyEvent *e); void contextMenuEvent( QContextMenuEvent * e ); private slots: void itemClicked(const QModelIndex& index); }; class AvatarDelegate : public QItemDelegate { Q_OBJECT public: AvatarDelegate(QObject *parent) : QItemDelegate(parent) {}; virtual QSize sizeHint ( const QStyleOptionViewItem & option, const QModelIndex & index ) const; virtual void paint ( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const; }; #endif // VIEWERS_H plugins-1.5/generic/clientswitcherplugin/000077500000000000000000000000001336777360500207435ustar00rootroot00000000000000plugins-1.5/generic/clientswitcherplugin/CMakeLists.txt000066400000000000000000000026771336777360500235170ustar00rootroot00000000000000unset(_HDRS) unset(_UIS) unset(_SRCS) unset(_RSCS) unset(PLUGIN) set( PLUGIN clientswitcherplugin ) project(${PLUGIN}) cmake_minimum_required(VERSION 3.1.0) set( CMAKE_AUTOMOC TRUE ) IF( NOT WIN32 ) set( LIB_SUFFIX "" CACHE STRING "Define suffix of directory name (32/64)" ) set( PLUGINS_PATH "lib${LIB_SUFFIX}/psi-plus/plugins" CACHE STRING "Install suffix for plugins" ) ELSE() set( PLUGINS_PATH "psi-plus/plugins" CACHE STRING "Install suffix for plugins" ) ENDIF() add_definitions( -DQT_PLUGIN -DHAVE_QT5 ) include_directories( ${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ../../include . ) set( _HDRS ${PLUGIN}.h accountsettings.h viewer.h typeaheadfind.h ) set( _SRCS ${PLUGIN}.cpp accountsettings.cpp viewer.cpp typeaheadfind.cpp ) set( _UIS options.ui ) set( _RSCS resources.qrc ) find_package( Qt5 COMPONENTS Widgets Xml REQUIRED ) set(QT_DEPLIBS Qt5::Widgets Qt5::Xml ) qt5_wrap_ui(UIS ${_UIS}) qt5_add_resources(RSCS ${_RSCS}) add_library( ${PLUGIN} MODULE ${_SRCS} ${UIS} ${RSCS} ) target_link_libraries( ${PLUGIN} ${QT_DEPLIBS} ) if( UNIX AND NOT( APPLE OR CYGWIN ) ) install( TARGETS ${PLUGIN} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} ) endif() if( WIN32 ) install( TARGETS ${PLUGIN} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} ) endif() plugins-1.5/generic/clientswitcherplugin/accountsettings.cpp000066400000000000000000000130641336777360500246700ustar00rootroot00000000000000/* * accountsettings.cpp - Client Switcher plugin * Copyright (C) 2010 Aleksey Andreev * * 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. * * You can also redistribute and/or modify this program under the * terms of the Psi License, specified in the accompanied COPYING * file, as published by the Psi Project; either dated January 1st, * 2005, 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include "accountsettings.h" AccountSettings::AccountSettings() { init(); return; } AccountSettings::AccountSettings(const QString& set_str) { fromString(set_str); } AccountSettings::~AccountSettings() { } bool AccountSettings::isValid() { return !account_id.isEmpty(); } bool AccountSettings::isEmpty() { if (!enable_contacts && !enable_conferences && response_mode == RespAllow && !lock_time_requ && show_requ_mode == LogNever && log_mode == LogNever) { if (os_name.isEmpty() && client_name.isEmpty() && caps_node.isEmpty() && caps_version.isEmpty()) { return true; } } return false; } void AccountSettings::fromString(const QString& set_str) { QStringList set_list; int len = set_str.length(); unsigned int sl_cnt = 0; int st_pos = 0; for (int i = 0; i < len; i++) { QChar ch = set_str.at(i); if (ch == '\\') { sl_cnt++; } else if (ch == ';') { if ((sl_cnt & 1) == 0) { // четное кол-во слешей set_list.push_back(set_str.mid(st_pos, i - st_pos)); st_pos = i + 1; } sl_cnt = 0; } else { sl_cnt = 0; } } if (st_pos < len) { set_list.push_back(set_str.mid(st_pos)); } len = set_list.size(); for (int i = 0; i < len; i++) { QStringList param_list = set_list.at(i).split("="); if (param_list.size() >= 2) { QString param_name = param_list.takeFirst(); QString param_value = param_list.join("="); if (param_name == "acc_id") { account_id = stripSlashes(param_value); } else if (param_name == "en_cnt") { enable_contacts = (param_value == "true") ? true : false; } else if (param_name == "en_cnf") { enable_conferences = (param_value == "true") ? true : false; } else if (param_name == "l_req") { if (param_value == "true") response_mode = RespNotImpl; else if (param_value == "ignore") response_mode = RespIgnore; else response_mode = RespAllow; } else if (param_name == "l_treq") { lock_time_requ = (param_value == "true") ? true : false; } else if (param_name == "s_req") { show_requ_mode = LogNever; if (param_value == "true" || param_value == "if-repl") { show_requ_mode = LogIfReplace; } else if (param_value == "always") { show_requ_mode = LogAlways; } } else if (param_name == "os_nm") { os_name = stripSlashes(param_value); } else if (param_name == "cl_nm") { client_name = stripSlashes(param_value); } else if (param_name == "cl_ver") { client_version = stripSlashes(param_value); } else if (param_name == "cp_nd") { caps_node = stripSlashes(param_value); } else if (param_name == "cp_ver") { caps_version = stripSlashes(param_value); } else if (param_name == "log") { log_mode = LogNever; if (param_value == "true" || param_value == "if-repl") { log_mode = LogIfReplace; } else if (param_value == "always") { log_mode = LogAlways; } } } } } QString AccountSettings::toString() { QString s_res = "acc_id=" + addSlashes(account_id); s_res.append(";en_cnt=").append((enable_contacts) ? "true" : "false"); s_res.append(";en_cnf=").append((enable_conferences) ? "true" : "false"); QString str1; if (response_mode == RespNotImpl) str1 = "true"; else if (response_mode == RespIgnore) str1 = "ignore"; else str1 = "false"; s_res.append(";l_req=").append(str1); s_res.append(";l_treq=").append((lock_time_requ) ? "true" : "false"); if (show_requ_mode == LogIfReplace) { str1 = "if-repl"; } else if (show_requ_mode == LogAlways) { str1 = "always"; } else { str1 = "never"; } s_res.append(";s_req=").append(str1); s_res.append(";os_nm=").append(addSlashes(os_name)); s_res.append(";cl_nm=").append(addSlashes(client_name)); s_res.append(";cl_ver=").append(addSlashes(client_version)); s_res.append(";cp_nd=").append(addSlashes(caps_node)); s_res.append(";cp_ver=").append(addSlashes(caps_version)); if (log_mode == LogIfReplace) { str1 = "if-repl"; } else if (log_mode == LogAlways) { str1 = "always"; } else { str1 = "never"; } s_res.append(";log=").append(str1); return s_res; } void AccountSettings::init() { account_id = ""; enable_contacts = false; enable_conferences = false; response_mode = RespAllow; lock_time_requ = false; show_requ_mode = LogNever; os_name = ""; client_name = ""; client_version = ""; caps_node = ""; caps_version = ""; log_mode = LogNever; } QString AccountSettings::addSlashes(QString& str) { return str.replace("\\", "\\\\", Qt::CaseSensitive).replace(";", "\\;"); } QString AccountSettings::stripSlashes(QString& str) { return str.replace("\\;", ";").replace("\\\\", "\\"); } plugins-1.5/generic/clientswitcherplugin/accountsettings.h000066400000000000000000000035371336777360500243410ustar00rootroot00000000000000/* * accountsettings.h - Client Switcher plugin * Copyright (C) 2010 Aleksey Andreev * * 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. * * You can also redistribute and/or modify this program under the * terms of the Psi License, specified in the accompanied COPYING * file, as published by the Psi Project; either dated January 1st, * 2005, 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef ACCOUNTSETTINGS_H #define ACCOUNTSETTINGS_H #include class AccountSettings { public: enum {RespAllow = 0, RespNotImpl = 1, RespIgnore = 2}; // как номер индекса в combobox enum {LogNever = 0, LogIfReplace = 1, LogAlways = 2}; AccountSettings(); AccountSettings(const QString&); ~AccountSettings(); bool isValid(); bool isEmpty(); void fromString(const QString&); QString toString(); //-- QString account_id; bool enable_contacts; bool enable_conferences; int response_mode; bool lock_time_requ; int show_requ_mode; QString os_name; QString client_name; QString client_version; QString caps_node; QString caps_version; int log_mode; private: //-- void init(); QString addSlashes(QString&); QString stripSlashes(QString&); }; #endif // ACCOUNTSETTINGS_H plugins-1.5/generic/clientswitcherplugin/changelog.txt000066400000000000000000000107701336777360500234400ustar00rootroot000000000000002013-09-02 v0.0.18 - taurus * Использовать слово Groupchat вместо Conference 2013-08-13 v0.0.17 - taurus + Иконка плагина 2013-01-19 v0.0.16 * реализовано экранирование специальных символов xml при отображении всплавающего сообщения 2012-11-21 v0.0.15 * исправлено избыточное экранирование специальных символов xml при подмене данных о клиенте 2012-08-31 v0.0.14 + добавлена возможность игнорирования запроса версии + в шаблон добавлены MacOS и Android * незначительная оптимизация кода 2012-02-21 v0.0.13 * исправлена кодировка при отображении лога 2012-02-20 v0.0.12 * исправления для нового попап-интерфейса 2011-10-02 v0.0.11 + в настройках добавлена область прокрутки 2011-07-22 v0.0.10 + добавлена опция блокирования запросов времени 2011-07-13 v0.0.9 * исправлен цвет подсветки при поиске в логах, актуально для Windows систем 2011-06-20 v0.0.8 + добавлены новые шаблоны и обновлены старые * если в ответе клиента нет версии, наименования или ОС, то нужные элементы добавляются * небольшие исправления безопасности 2011-05-27 v0.0.7 * пересобрано с новым appHomeDir 2011-02-27 v0.0.6 * настройка времени показа всплывающего уведомления перенесена в настройки клиента * добавлена возможность показа всплывающего уведомления и записи в лог-файл даже если подмены версии не производилось * незначительные исправления формата записи в лог-файл * именения интерфейса настроек 2011-02-04 v0.0.5 + Добавлена возможность ведения лога запросов версии клиента. * Сделана попытка побороть блокировку передачи сообщений после смены настроек плагина в некоторых случаях. * Мелкие исправления. 2010-12-26 v0.0.4 + Добавлена опция длительности показа всплывающего сообщения. Настраивается отдельно для каждого аккаунта. + Добавлена ссылка на Wiki. + Теперь есть возможность указывать настройки для всех аккаунтов. * Мелкие исправления. * Чистка кода. 2010-12-22 v0.0.3 + Добавлены пара моделей телефонов в предустановленные ОС. * Настройки плагина теперь привязываются к аккаунтам. * Исправлено поведение при обработке запросов disco. - Убран фильтр. + Добавлены чекбоксы "Включить для конференций", "Включить для контактов" 2010-12-15 v0.0.2 * Исправлена ошибка, приводящая к невозможности переключения версии операционной системы и клиента. * Изменено поведение popup-а: окно появляется только в случае подмены или блокировании версии клиента. + Добавлен PluginInfo текст. * Мелкие исправления 2010-12-13 v0.0.1 ! initial version Плагин предназначен для подмены версии клиента, его имени и типа операционной системы. Имеется возможность выбирать эти значения из предустановленных в плагине. Плагин также подменяет значения caps node и caps version в сообщениях присутствия. plugins-1.5/generic/clientswitcherplugin/clientswitcher.png000066400000000000000000000065371336777360500245130ustar00rootroot00000000000000PNG  IHDRagAMA a DiCCPICC ProfilexwTl/]"e齷.H& KYe7D"V$(bh(+X "J F;'Nw>}w(!a@P"f'0D6p(h@_63u_ -Z[3C+K;?r!YLD)c#c1 ʪ2N|bO h{yIHD.VV>RV:|{ [RF ”"MF1L1[Te'Jx%C%_%RJ#4GcӸu:(G73%Ie%e{SC add1T4UT*TTTUzUUUoScemUkS{Q7UPWߣ~A}b}9Հ5L5"5iјi<9Ъ:5MvhWh~Tfz1U.椎NTgNΌ|ݵͺHz,T NI}mPw ,tӆF -5j4oL50^l\k|g24mr6u0M713fͱBZA EEŰ%2res+}VV(٬Ԗk[c{Îjgʮ=~mCNNb&q'}d]N,:+Uʺuv^|o]5˟[7wM׍mȝ}CǃQSϓY9eu빷ػ{^>*}7l6 8`k`f 7!p2)hEPW0%8*:Qi8# z<ἶ0-AQ#p5#m"GvGѢG.7xt~g|LbLCtOlyPU܊|BLB}&:$%Zh`EꋲJO$O&&N~ rRSvLrgIsKۖ6^>!` /22fLge̜͊j&d'g* 3]9Z99"3Qhh'\(wanLHyy5yoc( z.ٴdloaqu.Yf WB+SVv[UjtCkHk2zmWbuj.Y￾HH\4uލ6W|ĺ})76T}39usocٞ---zl=TX|d[ fEqūI/WWA!1TRվS疝ӫox4صin={j-n`[k k+x\S-ۆzEjpjh8qn6Ik:8w7ޜw[nn?uݼ3V/~ڟM~nr:53(ѽȳ_ry?ZrL{퓓~מ.x:LlfW_w=7~oLM˃_uNO=|zfڛCoYož_CgggI) pHYs  IDAT8uSMHTQ>ί?AY"B u.Hi!U"`XѦUϘ,I[((T΢qfy<{{yνG"BG %ĂCۂNM11n餒Qhd$6zY}"%8tZnrIvsɔ&3Ek*|Nq"a*R@N+i)ѝh8 "ۨn-/r|dgN4[FdY$. [DO}ۛU}z#O֝1~!%En/%ܰ.,czb(,%szGH|P{]"S&1{}] ^w8_L2zy="&F|!ktO˔DnT Ӌn|犘 ~Zer{' //#include #include #include "clientswitcherplugin.h" #include "viewer.h" #ifndef HAVE_QT5 Q_EXPORT_PLUGIN(ClientSwitcherPlugin) #endif #define cVer "0.0.18" #define constPluginShortName "clientswitcher" #define constPluginName "Client Switcher Plugin" #define constForAllAcc "for_all_acc" #define constAccSettingList "accsettlist" #define constShowLogHeight "showlogheight" #define constShowLogWidth "showlogwidth" #define constLastLogItem "lastlogview" #define constPopupDuration "popupduration" ClientSwitcherPlugin::ClientSwitcherPlugin() : sender_(0), psiOptions(0), psiPopup(0), psiInfo(0), psiAccount(0), psiAccountCtl(0), psiContactInfo(0), psiIcon(0), enabled(false), for_all_acc(false), def_os_name(""), def_client_name(""), def_client_version(""), def_caps_node(""), def_caps_version(""), heightLogsView(500), widthLogsView(600), lastLogItem(""), popupId(0) { settingsList.clear(); os_presets.clear(); client_presets.clear(); } ClientSwitcherPlugin::~ClientSwitcherPlugin() { //disable(); } QString ClientSwitcherPlugin::name() const { return constPluginName; } QString ClientSwitcherPlugin::shortName() const { return constPluginShortName; } QString ClientSwitcherPlugin::version() const { return cVer; } bool ClientSwitcherPlugin::enable() { if (!psiOptions) return false; enabled = true; os_presets.clear(); os_presets << OsStruct("Windows 98") << OsStruct("Windows ME") << OsStruct("Windows 2000"); os_presets << OsStruct("Windows XP") << OsStruct("Windows Server 2003") << OsStruct("Windows Server 2008"); os_presets << OsStruct("Windows Vista") << OsStruct("Windows 7, 32-bit") << OsStruct("Windows 7, 64-bit"); os_presets << OsStruct("Arch Linux") << OsStruct("Debian GNU/Linux 6.0.1 (squeeze)"); os_presets << OsStruct("Ubuntu 10.04.2 LTS") << OsStruct("RFRemix release 14.1 (Laughlin)"); os_presets << OsStruct("openSUSE 11.4") << OsStruct("Gentoo Base System release 2.0.3"); os_presets << OsStruct("Mac OS X") << OsStruct("Mac OS X 10.6"); os_presets << OsStruct("Android OS 2.3.6 (build XXLB1)"); os_presets << OsStruct("Plan9") << OsStruct("Solaris"); os_presets << OsStruct("FreeBSD") << OsStruct("NetBSD") << OsStruct("OpenBSD"); os_presets << OsStruct("Nokia5130c-2/07.91") << OsStruct("SonyEricssonW580i/R8BE001"); client_presets.clear(); client_presets << ClientStruct("Bombus", "0.7.1429M-Zlib", "http://bombus-im.org/java", "0.7.1429M-Zlib"); client_presets << ClientStruct("Gajim", "0.12.5", "http://gajim.org", "0.12.5"); client_presets << ClientStruct("Mcabber", "0.9.10", "http://mcabber.com/caps", "0.9.10"); client_presets << ClientStruct("Miranda", "0.9.16.0", "http://miranda-im.org/caps", "0.9.16.0"); client_presets << ClientStruct("Pidgin", "2.8.0", "http://pidgin.im", "2.8.0"); client_presets << ClientStruct("Psi", "0.14", "http://psi-im.org/caps", "0.14"); client_presets << ClientStruct("QIP Infium", "9034", "http://qip.ru/caps", "9034"); client_presets << ClientStruct("qutIM", "0.2", "http://qutim.org", "0.2"); client_presets << ClientStruct("Swift", "1.0", "http://swift.im", "1.0"); client_presets << ClientStruct("Talisman", "0.1.1.15", "http://jabrvista.net.ru", "0.1.1.15"); client_presets << ClientStruct("Tkabber", "0.11.1", "http://tkabber.jabber.ru", "0.11.1"); client_presets << ClientStruct("Talkonaut", "1.0.0.84", "http://www.google.com/xmpp/client/caps", "1.0.0.84"); client_presets << ClientStruct(QString::fromUtf8("Я.Онлайн"), "3.2.0.8873", "yandex-webchat", "3.2.0.8873"); // Флаг "для всех аккаунтов" for_all_acc = psiOptions->getPluginOption(constForAllAcc, QVariant(false)).toBool(); // Получаем настройки аккаунтов QStringList sett_list = psiOptions->getPluginOption(constAccSettingList, QVariant()).toStringList(); // Get and register popup option int popup_duration = psiOptions->getPluginOption(constPopupDuration, QVariant(5000)).toInt() / 1000; popupId = psiPopup->registerOption(constPluginName, popup_duration, "plugins.options." + shortName() + "." + constPopupDuration); // Формируем структуры int cnt = sett_list.size(); for (int i = 0; i < cnt; i++) { AccountSettings* ac = new AccountSettings(sett_list.at(i)); if (ac) { if (ac->isValid()) settingsList.push_back(ac); else delete ac; } } // Настройки для просмотра логов logsDir = psiInfo->appCurrentProfileDir(ApplicationInfoAccessingHost::DataLocation) + "/logs/clientswitcher"; QDir dir(logsDir); if (!dir.exists(logsDir)) dir.mkpath(logsDir); logsDir.append("/"); heightLogsView = psiOptions->getPluginOption(constShowLogHeight, QVariant(heightLogsView)).toInt(); widthLogsView = psiOptions->getPluginOption(constShowLogWidth, QVariant(widthLogsView)).toInt(); lastLogItem = psiOptions->getPluginOption(constLastLogItem, QVariant(widthLogsView)).toString(); return true; } bool ClientSwitcherPlugin::disable() { while (settingsList.size() != 0) { AccountSettings* as = settingsList.takeLast(); if (as) delete as; } enabled = false; psiPopup->unregisterOption(constPluginName); return true; } QWidget* ClientSwitcherPlugin::options() { if (!enabled) { return 0; } QWidget* optionsWid = new QWidget(); ui_options.setupUi(optionsWid); // Заполняем виджет пресетов ОС ui_options.cb_ospreset->addItem("default", "default"); ui_options.cb_ospreset->addItem("user defined", "user"); int cnt = os_presets.size(); for (int i = 0; i < cnt; i++) { ui_options.cb_ospreset->addItem(os_presets.at(i).name); } // Заполняем виджет пресетов клиента ui_options.cb_clientpreset->addItem("default", "default"); ui_options.cb_clientpreset->addItem("user defined", "user"); cnt = client_presets.size(); for (int i = 0; i < cnt; i++) { ui_options.cb_clientpreset->addItem(client_presets.at(i).name); } // Элементы для просмотра логов QDir dir(logsDir); int pos = -1; foreach(const QString &file, dir.entryList(QDir::Files)) { ui_options.cb_logslist->addItem(file); ++pos; if (file == lastLogItem) ui_options.cb_logslist->setCurrentIndex(pos); } if (pos < 0) ui_options.bt_viewlog->setEnabled(false); //-- connect(ui_options.cb_allaccounts, SIGNAL(stateChanged(int)), this, SLOT(enableAccountsList(int))); connect(ui_options.cb_accounts, SIGNAL(currentIndexChanged(int)), this, SLOT(restoreOptionsAcc(int))); connect(ui_options.cmb_lockrequ, SIGNAL(currentIndexChanged(int)), this, SLOT(enableMainParams(int))); connect(ui_options.cb_ospreset, SIGNAL(currentIndexChanged(int)), this, SLOT(enableOsParams(int))); connect(ui_options.cb_clientpreset, SIGNAL(currentIndexChanged(int)), this, SLOT(enableClientParams(int))); connect(ui_options.bt_viewlog, SIGNAL(released()), this, SLOT(viewFromOpt())); restoreOptions(); return optionsWid; } void ClientSwitcherPlugin::applyOptions() { bool caps_updated = false; // Аккаунт bool for_all_acc_old = for_all_acc; for_all_acc = ui_options.cb_allaccounts->isChecked(); if (for_all_acc != for_all_acc_old) { caps_updated = true; } int acc_index = ui_options.cb_accounts->currentIndex(); if (acc_index == -1 && !for_all_acc) return; QString acc_id = "all"; if (!for_all_acc) acc_id = ui_options.cb_accounts->itemData(acc_index).toString(); AccountSettings* as = getAccountSetting(acc_id); if (!as) { as = new AccountSettings(); as->account_id = acc_id; settingsList.push_back(as); } // Подмена/блокировка для контактов bool tmp_flag = ui_options.cb_contactsenable->isChecked(); if (as->enable_contacts != tmp_flag) { as->enable_contacts = tmp_flag; caps_updated = true; } // Подмена/блокировка для конференций tmp_flag = ui_options.cb_conferencesenable->isChecked(); if (as->enable_conferences != tmp_flag) { as->enable_conferences = tmp_flag; caps_updated = true; } // Блокировка запроса версии int respMode = ui_options.cmb_lockrequ->currentIndex(); if (as->response_mode != respMode) { if (as->response_mode == AccountSettings::RespAllow || respMode == AccountSettings::RespAllow) caps_updated = true; as->response_mode = respMode; } // Блокировка запроса времени tmp_flag = ui_options.cb_locktimerequ->isChecked(); if (as->lock_time_requ != tmp_flag) { as->lock_time_requ = tmp_flag; caps_updated = true; } // Уведомления при запросах версии as->show_requ_mode = ui_options.cmb_showrequ->currentIndex(); // Ведение лога as->log_mode = ui_options.cmb_savetolog->currentIndex(); // Наименование ОС if (ui_options.cb_ospreset->currentIndex() == 0) { as->os_name = ""; } else { as->os_name = ui_options.le_osname->text().trimmed(); } // Клиент if (ui_options.cb_clientpreset->currentIndex() == 0) { as->client_name = ""; as->client_version = ""; if (!as->caps_node.isEmpty()) { as->caps_node = ""; caps_updated = true; } if (!as->caps_version.isEmpty()) { as->caps_version = ""; caps_updated = true; } } else { // Название клиента as->client_name = ui_options.le_clientname->text().trimmed(); // Версия клиента as->client_version = ui_options.le_clientversion->text().trimmed(); // Caps node клиента QString str1 = ui_options.le_capsnode->text().trimmed(); if (as->caps_node != str1) { as->caps_node = str1; caps_updated = true; } // Caps version клиента str1 = ui_options.le_capsversion->text().trimmed(); if (as->caps_version != str1) { as->caps_version = str1; caps_updated = true; } } // Сохраняем опции psiOptions->setPluginOption(constForAllAcc, QVariant(for_all_acc)); QStringList sett_list; int cnt = settingsList.size(); for (int i = 0; i < cnt; i++) { AccountSettings* as = settingsList.at(i); if (as->isValid() && !as->isEmpty()) { QString acc_id = as->account_id; if ((!for_all_acc && acc_id != "all") || (for_all_acc && acc_id == "all")) sett_list.push_back(as->toString()); } } psiOptions->setPluginOption(constAccSettingList, QVariant(sett_list)); // Если капсы изменились, отсылаем новые пресентсы if (caps_updated) { if (!for_all_acc && !for_all_acc_old) { int acc = getAccountById(acc_id); if (acc != -1) QMetaObject::invokeMethod(this, "setNewCaps", Qt::QueuedConnection, Q_ARG(int, acc)); } else { // Отправляем новые капсы всем активным аккам QMetaObject::invokeMethod(this, "setNewCaps", Qt::QueuedConnection, Q_ARG(int, -1)); } } } void ClientSwitcherPlugin::restoreOptions() { // Заполняем флаг "для всех аккаунтов" ui_options.cb_allaccounts->setChecked(for_all_acc); // Заполняем виджет аккаунтов ui_options.cb_accounts->clear(); if (!psiAccount) return; int cnt = 0; for (int i = 0; ; i++) { QString id = psiAccount->getId(i); if (id == "-1") break; if (!id.isEmpty()) { QString name = psiAccount->getName(i); if (name.isEmpty()) name = "?"; ui_options.cb_accounts->addItem(QString("%1 (%2)").arg(name).arg(psiAccount->getJid(i)), QVariant(id)); cnt++; } } int acc_idx = -1; if (cnt > 0) { if (!for_all_acc) acc_idx = 0; } ui_options.cb_accounts->setCurrentIndex(acc_idx); //-- restoreOptionsAcc(acc_idx); } QPixmap ClientSwitcherPlugin::icon() const { return QPixmap(":/icons/clientswitcher.png"); } //-- OptionAccessor ------------------------------------------------- void ClientSwitcherPlugin::setOptionAccessingHost(OptionAccessingHost* host) { psiOptions = host; } void ClientSwitcherPlugin::optionChanged(const QString& /*option*/) { } //-- StanzaSender --------------------------------------------------- void ClientSwitcherPlugin::setStanzaSendingHost(StanzaSendingHost *host) { sender_ = host; } // ----------------------- StanzaFilter ------------------------------ bool ClientSwitcherPlugin::incomingStanza(int account, const QDomElement& stanza) { if (!enabled) return false; QString acc_id = (for_all_acc) ? "all" : psiAccount->getId(account); AccountSettings *as = getAccountSetting(acc_id); if (!as) return false; if (!as->enable_contacts && !as->enable_conferences) return false; int respMode = as->response_mode; if (respMode != AccountSettings::RespAllow || as->lock_time_requ || !as->caps_node.isEmpty() || !as->caps_version.isEmpty()) { if (stanza.tagName() == "iq" && stanza.attribute("type") == "get") { const QString s_to = stanza.attribute("from"); if (isSkipStanza(as, account, s_to)) return false; QDomNode s_child = stanza.firstChild(); while (!s_child.isNull()) { const QString xmlns = s_child.toElement().attribute("xmlns"); if (s_child.toElement().tagName() == "query") { if (xmlns == "http://jabber.org/protocol/disco#info") { QString node = s_child.toElement().attribute("node"); if (!node.isEmpty()) { QString new_node = def_caps_node; QStringList split_node = node.split("#"); if (split_node.size() > 1) { split_node.removeFirst(); QString node_ver = split_node.join("#"); if (node_ver == ((respMode == AccountSettings::RespAllow) ? as->caps_version : "n/a")) { node_ver = def_caps_version; } new_node.append("#" + node_ver); } s_child.toElement().setAttribute("node", new_node); } } else if (xmlns == "jabber:iq:version") { if (respMode == AccountSettings::RespIgnore) { // Showing popup if it is necessary if (as->show_requ_mode == AccountSettings::LogAlways) showPopup(jidToNick(account, s_to)); // Write log if it is necessary if (as->log_mode == AccountSettings::LogAlways) saveToLog(account, s_to, "ignored"); return true; } } } s_child = s_child.nextSibling(); } } } return false; } bool ClientSwitcherPlugin::outgoingStanza(int account, QDomElement& stanza) { if(!enabled) return false; QString acc_id = (for_all_acc) ? "all" : psiAccount->getId(account); AccountSettings *as = getAccountSetting(acc_id); if (!as) return false; if (as->response_mode != AccountSettings::RespAllow || !as->caps_node.isEmpty() || !as->caps_version.isEmpty()) { // --------------- presence --------------- if (stanza.tagName() == "presence") { if (!as->enable_contacts && !as->enable_conferences) return false; // Анализ сообщения о присутствии bool skipFlag = isSkipStanza(as, account, stanza.attribute("to")); if (skipFlag && !as->enable_conferences) // Конференция не определяется при входе в нее, проверим позже return false; short unsigned int found_flag = 0; // Чтобы исключить перебор лишних элементов QDomNode s_child = stanza.firstChild(); QDomNode caps_node; while (!s_child.isNull()) { if (((found_flag & 1) == 0) && s_child.toElement().tagName() == "c") { // Подмена будет отложенной caps_node = s_child; found_flag |= 1; if (found_flag == 3) break; s_child = s_child.nextSibling(); continue; } if (((found_flag & 2) == 0) && s_child.toElement().tagName() == "x") { if (s_child.namespaceURI() == "http://jabber.org/protocol/muc") { found_flag |= 2; if (found_flag == 3) break; } } s_child = s_child.nextSibling(); } if ((found_flag == 1 && as->enable_contacts) || (found_flag == 3 && as->enable_conferences)) { // Подменяем капс if (as->response_mode != AccountSettings::RespNotImpl) { caps_node.toElement().setAttribute("node", as->caps_node); caps_node.toElement().setAttribute("ver", as->caps_version); } else { caps_node.toElement().setAttribute("node", "unknown"); caps_node.toElement().setAttribute("ver", "n/a"); } } return false; } } if (stanza.tagName() == "iq" && stanza.attribute("type") == "result") { bool is_version_query = false; bool is_version_replaced = false; QString s_to = stanza.attribute("to"); QStringList send_ver_list; QDomNode s_child = stanza.firstChild(); int respMode = as->response_mode; while (!s_child.isNull()) { if (s_child.toElement().tagName() == "query") { QString xmlns_str = s_child.namespaceURI(); if (xmlns_str == "http://jabber.org/protocol/disco#info") { // --- Ответ disco if (isSkipStanza(as, account, s_to)) return false; if (respMode == AccountSettings::RespAllow && !as->lock_time_requ && as->caps_node.isEmpty() && as->caps_version.isEmpty()) return false; // Подменяем ноду, если она есть QString node = s_child.toElement().attribute("node"); if (!node.isEmpty()) { QString new_node = (respMode == AccountSettings::RespAllow) ? as->caps_node : "unknown"; QStringList split_node = node.split("#"); if (split_node.size() > 1) { split_node.removeFirst(); QString new_ver = split_node.join("#"); if (new_ver == def_caps_version) new_ver = (respMode == AccountSettings::RespAllow) ? as->caps_version : "n/a"; new_node.append("#" + new_ver); } s_child.toElement().setAttribute("node", new_node); } // Подменяем identity и удаляем feature для версии, если есть блокировка int update = 0; if (respMode == AccountSettings::RespAllow) ++update; if (!as->lock_time_requ) ++update; QDomNode ver_domnode; QDomNode time_domnode; QDomNode q_child = s_child.firstChild(); while (!q_child.isNull()) { QString tag_name = q_child.toElement().tagName(); if (tag_name == "feature") { if (respMode != AccountSettings::RespAllow && q_child.toElement().attribute("var") == "jabber:iq:version") { ver_domnode = q_child; if (++update >= 3) break; } else if (as->lock_time_requ && q_child.toElement().attribute("var") == "urn:xmpp:time") { time_domnode = q_child; if (++update >= 3) break; } } else if (tag_name == "identity") { if (!q_child.toElement().attribute("name").isEmpty()) q_child.toElement().setAttribute("name", (respMode == AccountSettings::RespAllow) ? as->client_name : "unknown"); if (++update >= 3) break; } q_child = q_child.nextSibling(); } if (!s_child.isNull()) { if (!ver_domnode.isNull()) s_child.removeChild(ver_domnode); if (!time_domnode.isNull()) s_child.removeChild(time_domnode); } } else if (xmlns_str == "jabber:iq:version") { // Ответ version is_version_query = true; bool skip_stanza = isSkipStanza(as, account, s_to); if (skip_stanza && as->log_mode != AccountSettings::LogAlways) break; QDomDocument xmldoc = stanza.ownerDocument(); if (respMode == AccountSettings::RespAllow) { // Подменяем ответ bool f_os_name = false; bool f_client_name = false; bool f_client_ver = false; QDomNode q_child = s_child.firstChild(); while(!q_child.isNull()) { QString tag_name = q_child.toElement().tagName().toLower(); if (tag_name == "os") { QString str1; if (!skip_stanza && !as->os_name.isEmpty()) { str1 = as->os_name; q_child.toElement().replaceChild(xmldoc.createTextNode(str1), q_child.firstChild()); is_version_replaced = true; } else { str1 = q_child.toElement().text(); } send_ver_list.push_back("OS: " + str1); f_os_name = true; } else if (tag_name == "name") { QString str1; if (!skip_stanza && !as->client_name.isEmpty()) { str1 = as->client_name; q_child.toElement().replaceChild(xmldoc.createTextNode(str1), q_child.firstChild()); is_version_replaced = true; } else { str1 = q_child.toElement().text(); } send_ver_list.push_back("Client name: " + str1); f_client_name = true; } else if (tag_name == "version") { QString str1; if (!skip_stanza && !as->caps_version.isEmpty()) { str1 = as->client_version; q_child.toElement().replaceChild(xmldoc.createTextNode(str1), q_child.firstChild()); is_version_replaced = true; } else { str1 = q_child.toElement().text(); } send_ver_list.push_back("Client version: " + str1); f_client_ver = true; } q_child = q_child.nextSibling(); } // Создаем теги, если их нет в ответе QDomDocument doc; if (!f_client_name && !as->client_name.isEmpty()) { doc = s_child.ownerDocument(); QDomElement cl_name = doc.createElement("name"); cl_name.appendChild(doc.createTextNode(as->client_name)); s_child.appendChild(cl_name); } if (!f_client_ver && !as->client_version.isEmpty()) { if (doc.isNull()) doc = s_child.ownerDocument(); QDomElement cl_ver = doc.createElement("version"); cl_ver.appendChild(doc.createTextNode(as->client_version)); s_child.appendChild(cl_ver); } if (!f_os_name && !as->os_name.isEmpty()) { if (doc.isNull()) doc = s_child.ownerDocument(); QDomElement os_name = doc.createElement("os"); os_name.appendChild(doc.createTextNode(as->os_name)); s_child.appendChild(os_name); } } else if (respMode == AccountSettings::RespNotImpl) { // Отклонение запроса, как будто не реализовано stanza.setAttribute("type", "error"); QDomNode q_child = s_child.firstChild(); while (!q_child.isNull()) { s_child.removeChild(q_child); q_child = s_child.firstChild(); } QDomElement err = xmldoc.createElement("error"); err.setAttribute("type", "cancel"); err.setAttribute("code", "501"); stanza.appendChild(err); QDomElement not_imp = xmldoc.createElement("feature-not-implemented"); not_imp.setAttribute("xmlns", "urn:ietf:params:xml:ns:xmpp-stanzas"); err.appendChild(not_imp); send_ver_list.push_back("feature-not-implemented"); } } break; } else if (s_child.toElement().tagName() == "time") { QString xmlns_str = s_child.namespaceURI(); if (xmlns_str == "urn:xmpp:time") { // Ответ time if (isSkipStanza(as, account, s_to)) break; if (as->lock_time_requ) { QDomDocument xmldoc = stanza.ownerDocument(); // Отклонение запроса, как будто не реализовано stanza.setAttribute("type", "error"); QDomNode q_child = s_child.firstChild(); while (!q_child.isNull()) { s_child.removeChild(q_child); q_child = s_child.firstChild(); } QDomElement err = xmldoc.createElement("error"); err.setAttribute("type", "cancel"); err.setAttribute("code", "501"); stanza.appendChild(err); QDomElement not_imp = xmldoc.createElement("feature-not-implemented"); not_imp.setAttribute("xmlns", "urn:ietf:params:xml:ns:xmpp-stanzas"); err.appendChild(not_imp); } } } s_child = s_child.nextSibling(); } // Showing popup if it is necessary if (is_version_query && as->show_requ_mode != AccountSettings::LogNever && (as->show_requ_mode == AccountSettings::LogAlways || is_version_replaced)) showPopup(jidToNick(account, s_to)); // Write log if it is necessary if (is_version_query && as->log_mode != AccountSettings::LogNever && (as->log_mode == AccountSettings::LogAlways || is_version_replaced)) saveToLog(account, s_to, send_ver_list.join(", ")); } return false; } QString ClientSwitcherPlugin::pluginInfo() { return tr("Authors: ") + "Liuch\n\n" + trUtf8("The plugin is intended for substitution of the client version, his name and operating system type.\n" "You can specify the version of the client and OS or to select them from the preset list.\n"); } void ClientSwitcherPlugin::setPopupAccessingHost(PopupAccessingHost* host) { psiPopup = host; } // ----------------------- ApplicationInfoAccessor ------------------------------ void ClientSwitcherPlugin::setApplicationInfoAccessingHost(ApplicationInfoAccessingHost* host) { psiInfo = host; if (psiInfo) { // def_os_name = ; def_client_name = psiInfo->appName(); def_client_version = psiInfo->appVersion(); def_caps_node = psiInfo->appCapsNode(); def_caps_version = psiInfo->appCapsVersion(); def_os_name = psiInfo->appOsName(); } } // ----------------------- AccountInfoAccessing ------------------------------ void ClientSwitcherPlugin::setAccountInfoAccessingHost(AccountInfoAccessingHost* host) { psiAccount = host; } // ----------------------- PsiAccountController ---------------------------------- void ClientSwitcherPlugin::setPsiAccountControllingHost(PsiAccountControllingHost* host) { psiAccountCtl = host; } // ----------------------- ContactInfoAccessor ----------------------- void ClientSwitcherPlugin::setContactInfoAccessingHost(ContactInfoAccessingHost* host) { psiContactInfo = host; } // ----------------------- IconFactoryAccessor ----------------------- void ClientSwitcherPlugin::setIconFactoryAccessingHost(IconFactoryAccessingHost* host) { psiIcon = host; } // ----------------------- Private ------------------------------ int ClientSwitcherPlugin::getOsTemplateIndex(QString &os_name) { if (os_name.isEmpty()) return 0; // default int cnt = os_presets.size(); for (int i = 0; i < cnt; i++) { if (os_name == os_presets.at(i).name) { i += 2; // Т.к. впереди default и user defined return i; } } return 1; // user defined } int ClientSwitcherPlugin::getClientTemplateIndex(QString &cl_name, QString &cl_ver, QString &cp_node, QString &cp_ver) { if (cl_name.isEmpty() && cl_ver.isEmpty() && cp_node.isEmpty() && cp_ver.isEmpty()) return 0; // default int cnt = client_presets.size(); for (int i = 0; i < cnt; i++) { if (cl_name == client_presets.at(i).name && cl_ver == client_presets.at(i).version) { if (cp_node == client_presets.at(i).caps_node && cp_ver == client_presets.at(i).caps_version) { i += 2; // есть еще default и user defined return i; } } } return 1; // user defined } int ClientSwitcherPlugin::getAccountById(QString &acc_id) { if (!psiAccount || acc_id.isEmpty()) return -1; for (int i = 0; ; i++) { QString id = psiAccount->getId(i); if (id == "-1") break; if (id == acc_id) return i; } return -1; } AccountSettings* ClientSwitcherPlugin::getAccountSetting(const QString &acc_id) { int cnt = settingsList.size(); for (int i = 0; i < cnt; i++) { AccountSettings* as = settingsList.at(i); if (as && as->account_id == acc_id) return as; } return NULL; } /** * Отсылка пресентса с новыми капсами от имени указанного аккаунта * Если account == -1, то капсы посылаются всем активным аккаунтам */ void ClientSwitcherPlugin::setNewCaps(int account) { if (!enabled || !psiAccount || !psiAccountCtl) return; int acc = account; if (acc == -1) acc = 0; for (; ; acc++) { QString acc_id = psiAccount->getId(acc); if (acc_id == "-1") break; if (!acc_id.isEmpty()) { QString acc_status = psiAccount->getStatus(acc); if (!acc_status.isEmpty() && acc_status != "offline" && acc_status != "invisible") { // Отсылаем тот же статус, а капсы заменим в outgoingStanza() psiAccountCtl->setStatus(acc, acc_status, psiAccount->getStatusMessage(acc)); } } if (account != -1) break; } } bool ClientSwitcherPlugin::isSkipStanza(AccountSettings* as, int account, QString to) { if (to.isEmpty()) { // Широковещательный if (!as->enable_contacts) return true; } else { // Адресный QString to_jid = to.split("/").takeFirst(); if (!to_jid.contains("@")) { if (as->enable_contacts) { if (!to.contains("/")) return false; // Предполагаем что это сервер return true; // Ошибочный запрос } } if (psiContactInfo->isConference(account, to_jid) || psiContactInfo->isPrivate(account, to)) { //if (to.contains("conference.")) { if (!as->enable_conferences) return true; } else { if (!as->enable_contacts) return true; } } return false; } // ----------------------- Slots ------------------------------ void ClientSwitcherPlugin::enableAccountsList(int all_acc_mode) { bool all_acc_flag = (all_acc_mode == Qt::Checked) ? true : false; ui_options.cb_accounts->setEnabled(!all_acc_flag); ui_options.cb_accounts->setCurrentIndex(-1); restoreOptionsAcc(-1); } void ClientSwitcherPlugin::restoreOptionsAcc(int acc_index) { // Блокировка виджета акка, при установленной галке "для всех акков" bool all_acc_flag = ui_options.cb_allaccounts->isChecked(); ui_options.cb_accounts->setEnabled(!all_acc_flag); //-- if (all_acc_flag || acc_index >= 0) { QString acc_id; if (!all_acc_flag) { acc_id = ui_options.cb_accounts->itemData(acc_index).toString(); } else { acc_id = "all"; } if (!acc_id.isEmpty()) { AccountSettings* as = getAccountSetting(acc_id); if (!as) { as = new AccountSettings(); // Сразу заполняется дефолтными настройками as->account_id = acc_id; settingsList.push_back(as); } // Подмена/блокировка для контактов ui_options.cb_contactsenable->setChecked(as->enable_contacts); // Подмена/блокировка для конференций ui_options.cb_conferencesenable->setChecked(as->enable_conferences); // Блокировка запроса версии ui_options.cmb_lockrequ->setCurrentIndex(as->response_mode); // Блокировка запроса времени ui_options.cb_locktimerequ->setChecked(as->lock_time_requ); // Уведомления при запросах версии ui_options.cmb_showrequ->setCurrentIndex(as->show_requ_mode); // Ведение лога ui_options.cmb_savetolog->setCurrentIndex(as->log_mode); // Виджет шаблона ОС QString os_name = as->os_name; int os_templ = getOsTemplateIndex(os_name); ui_options.cb_ospreset->setCurrentIndex(os_templ); // Название ОС ui_options.le_osname->setText(os_name); // Виджет шаблона клиента QString cl_name = as->client_name; QString cl_ver = as->client_version; QString cp_node = as->caps_node; QString cp_ver = as->caps_version; int cl_templ = getClientTemplateIndex(cl_name, cl_ver, cp_node, cp_ver); ui_options.cb_clientpreset->setCurrentIndex(cl_templ); // Название клиента ui_options.le_clientname->setText(cl_name); // Версия клиента ui_options.le_clientversion->setText(cl_ver); // Caps node клиента ui_options.le_capsnode->setText(cp_node); // Caps version клиента ui_options.le_capsversion->setText(cp_ver); // Блокировка/снятие блокировки виджетов ui_options.gb_enablefor->setEnabled(true); ui_options.cmb_lockrequ->setEnabled(true); enableMainParams(as->response_mode); enableOsParams(os_templ); enableClientParams(cl_templ); return; } } // Блокировка виджетов при отсутствии валидного акка ui_options.cb_contactsenable->setChecked(false); ui_options.cb_conferencesenable->setChecked(false); ui_options.gb_enablefor->setEnabled(false); ui_options.cmb_lockrequ->setCurrentIndex(AccountSettings::RespAllow); ui_options.cmb_lockrequ->setEnabled(false); ui_options.cb_ospreset->setCurrentIndex(0); ui_options.gb_os->setEnabled(false); ui_options.cb_clientpreset->setCurrentIndex(0); ui_options.gb_client->setEnabled(false); enableOsParams(0); enableClientParams(0); } void ClientSwitcherPlugin::enableMainParams(int lock_mode) { bool enableFlag = (lock_mode == AccountSettings::RespAllow); ui_options.gb_os->setEnabled(enableFlag); ui_options.gb_client->setEnabled(enableFlag); } void ClientSwitcherPlugin::enableOsParams(int mode) { if (mode == 1) { // user defined ui_options.le_osname->setEnabled(true); } else { if (mode == 0) { // default os ui_options.le_osname->setText(def_os_name); } else { int pres_index = mode - 2; if (pres_index >= 0 && pres_index < os_presets.size()) { ui_options.le_osname->setText(os_presets.at(pres_index).name); } } ui_options.le_osname->setEnabled(false); } } void ClientSwitcherPlugin::enableClientParams(int mode) { if (mode == 1) { // user defined ui_options.le_clientname->setEnabled(true); ui_options.le_clientversion->setEnabled(true); ui_options.le_capsnode->setEnabled(true); ui_options.le_capsversion->setEnabled(true); } else { if (mode == 0) { // default client ui_options.le_clientname->setText(def_client_name); ui_options.le_clientversion->setText(def_client_version); ui_options.le_capsnode->setText(def_caps_node); ui_options.le_capsversion->setText(def_caps_version); } else { int pres_index = mode - 2; if (pres_index >= 0 && pres_index < client_presets.size()) { ui_options.le_clientname->setText(client_presets.at(pres_index).name); ui_options.le_clientversion->setText(client_presets.at(pres_index).version); ui_options.le_capsnode->setText(client_presets.at(pres_index).caps_node); ui_options.le_capsversion->setText(client_presets.at(pres_index).caps_version); } } ui_options.le_clientname->setEnabled(false); ui_options.le_clientversion->setEnabled(false); ui_options.le_capsnode->setEnabled(false); ui_options.le_capsversion->setEnabled(false); } } void ClientSwitcherPlugin::viewFromOpt() { lastLogItem = ui_options.cb_logslist->currentText(); if (lastLogItem.isEmpty()) return; psiOptions->setPluginOption(constLastLogItem, QVariant(lastLogItem)); showLog(lastLogItem); } QString ClientSwitcherPlugin::jidToNick(int account, const QString &jid) { QString nick; if (psiContactInfo) nick = psiContactInfo->name(account, jid); if (nick.isEmpty()) nick = jid; return nick; } void ClientSwitcherPlugin::showPopup(const QString &nick) { int msecs = psiPopup->popupDuration(constPluginName); if (msecs > 0) psiPopup->initPopup(tr("%1 has requested your version").arg(sender_->escape(nick)), constPluginName, "psi/headline", popupId); } void ClientSwitcherPlugin::showLog(QString filename) { QString fullname = logsDir + filename; Viewer *v = new Viewer(fullname, psiIcon); v->resize(widthLogsView, heightLogsView); if(!v->init()) { delete(v); return; } connect(v, SIGNAL(onClose(int,int)), this, SLOT(onCloseView(int,int))); v->show(); } void ClientSwitcherPlugin::saveToLog(int account, QString to_jid, QString ver_str) { QString acc_jid = psiAccount->getJid(account); if (acc_jid.isEmpty() || acc_jid == "-1") return; QFile file(logsDir + acc_jid.replace("@", "_at_") + ".log"); if (file.open(QIODevice::WriteOnly | QIODevice::Append)) { QString time_str = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss"); QTextStream out(&file); out.setCodec("UTF-8"); out.setGenerateByteOrderMark(false); out << time_str << " " << to_jid << " <-- " << ver_str << endl; } } void ClientSwitcherPlugin::onCloseView(int w, int h) { if (widthLogsView != w) { widthLogsView = w; psiOptions->setPluginOption(constShowLogWidth, QVariant(w)); } if (heightLogsView != h) { heightLogsView = h; psiOptions->setPluginOption(constShowLogHeight, QVariant(h)); } } plugins-1.5/generic/clientswitcherplugin/clientswitcherplugin.h000066400000000000000000000125221336777360500253640ustar00rootroot00000000000000/* * clientswitcherplugin.h - Client Switcher plugin * Copyright (C) 2010 Aleksey Andreev * * 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. * * You can also redistribute and/or modify this program under the * terms of the Psi License, specified in the accompanied COPYING * file, as published by the Psi Project; either dated January 1st, * 2005, 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef PLUGIN_MAIN_H #define PLUGIN_MAIN_H #include #include #include #include "ui_options.h" #include "psiplugin.h" #include "optionaccessor.h" #include "optionaccessinghost.h" #include "stanzasender.h" #include "stanzasendinghost.h" #include "stanzafilter.h" #include "plugininfoprovider.h" #include "applicationinfoaccessor.h" #include "applicationinfoaccessinghost.h" #include "popupaccessor.h" #include "popupaccessinghost.h" #include "accountinfoaccessor.h" #include "accountinfoaccessinghost.h" #include "psiaccountcontroller.h" #include "psiaccountcontrollinghost.h" #include "contactinfoaccessor.h" #include "contactinfoaccessinghost.h" #include "iconfactoryaccessor.h" #include "iconfactoryaccessinghost.h" #include "accountsettings.h" class ClientSwitcherPlugin: public QObject, public PsiPlugin, public OptionAccessor, public StanzaSender, public StanzaFilter, public PluginInfoProvider, public PopupAccessor, public ApplicationInfoAccessor, public AccountInfoAccessor, public PsiAccountController, public ContactInfoAccessor, public IconFactoryAccessor { Q_OBJECT #ifdef HAVE_QT5 Q_PLUGIN_METADATA(IID "com.psi-plus.ClientSwitcherPlugin") #endif Q_INTERFACES(PsiPlugin OptionAccessor StanzaSender StanzaFilter PluginInfoProvider PopupAccessor ApplicationInfoAccessor AccountInfoAccessor PsiAccountController ContactInfoAccessor IconFactoryAccessor) public: ClientSwitcherPlugin(); ~ClientSwitcherPlugin(); virtual QString name() const; virtual QString shortName() const; virtual QString version() const; virtual bool enable(); virtual bool disable(); virtual QWidget* options(); virtual void applyOptions(); virtual void restoreOptions(); virtual QPixmap icon() const; // OptionAccessor virtual void setOptionAccessingHost(OptionAccessingHost*); virtual void optionChanged(const QString&); // StanzaSender virtual void setStanzaSendingHost(StanzaSendingHost*); // StanzaFilter virtual bool incomingStanza(int, const QDomElement&); virtual bool outgoingStanza(int, QDomElement&); // EventFilter virtual QString pluginInfo(); // PopupAccessor virtual void setPopupAccessingHost(PopupAccessingHost*); // ApplicationInfoAccessor virtual void setApplicationInfoAccessingHost(ApplicationInfoAccessingHost*); // AccountInfoAccessing virtual void setAccountInfoAccessingHost(AccountInfoAccessingHost*); // PsiAccountController virtual void setPsiAccountControllingHost(PsiAccountControllingHost*); // ContactInfoAccessor virtual void setContactInfoAccessingHost(ContactInfoAccessingHost*); // IconFactoryAccessor virtual void setIconFactoryAccessingHost(IconFactoryAccessingHost* host); private: struct OsStruct { QString name; OsStruct(const QString &n) : name(n) {} }; struct ClientStruct { QString name; QString version; QString caps_node; QString caps_version; ClientStruct(const QString &n, const QString &v, const QString &cn, const QString &cv) : name(n), version(v), caps_node(cn), caps_version(cv) {} }; Ui::OptionsWidget ui_options; StanzaSendingHost* sender_; OptionAccessingHost* psiOptions; PopupAccessingHost* psiPopup; ApplicationInfoAccessingHost* psiInfo; AccountInfoAccessingHost* psiAccount; PsiAccountControllingHost* psiAccountCtl; ContactInfoAccessingHost* psiContactInfo; IconFactoryAccessingHost* psiIcon; //-- bool enabled; bool for_all_acc; QList settingsList; //-- QString def_os_name; QString def_client_name; QString def_client_version; QString def_caps_node; QString def_caps_version; QList os_presets; QList client_presets; QString logsDir; int heightLogsView; int widthLogsView; QString lastLogItem; int popupId; //-- int getOsTemplateIndex(QString&); int getClientTemplateIndex(QString&, QString&, QString&, QString&); int getAccountById(QString&); AccountSettings* getAccountSetting(const QString&); bool isSkipStanza(AccountSettings*, int, QString); QString jidToNick(int account, const QString &jid); void showPopup(const QString &nick); void showLog(QString filename); void saveToLog(int, QString, QString); private slots: void enableAccountsList(int); void restoreOptionsAcc(int); void enableMainParams(int); void enableOsParams(int); void enableClientParams(int); void setNewCaps(int); void viewFromOpt(); void onCloseView(int, int); }; #endif plugins-1.5/generic/clientswitcherplugin/clientswitcherplugin.pro000066400000000000000000000005371336777360500257400ustar00rootroot00000000000000isEmpty(PSISDK) { include(../../psiplugin.pri) } else { include($$PSISDK/plugins/psiplugin.pri) } HEADERS += clientswitcherplugin.h \ accountsettings.h \ viewer.h \ typeaheadfind.h SOURCES += clientswitcherplugin.cpp \ accountsettings.cpp \ viewer.cpp \ typeaheadfind.cpp RESOURCES += resources.qrc FORMS += options.ui plugins-1.5/generic/clientswitcherplugin/options.ui000066400000000000000000000352261336777360500230050ustar00rootroot00000000000000 OptionsWidget 0 0 494 515 Form 0 1 General Account: 141 0 For all accounts Qt::Horizontal 40 20 true 0 0 434 437 Response mode allow not implemented ignore Deny iq time request Qt::Horizontal QSizePolicy::Expanding 18 20 true OS Template OS name Client Template Client name Client version Caps node Caps version 0 0 Enable for: Contacts Qt::Horizontal QSizePolicy::Maximum 30 20 Groupchats Qt::Horizontal QSizePolicy::Expanding 18 20 Show popup at version iq never if iq replaced always Save queries to log never if iq replaced always Logs 1 0 View log Qt::Vertical 20 471 <a href="http://psi-plus.com/wiki/plugins#client_switcher_plugin">Wiki (Online)</a> true Qt::Vertical 20 0 tabWidget cb_accounts cb_allaccounts scrollArea cmb_lockrequ cb_locktimerequ cb_ospreset le_osname cb_clientpreset le_clientname le_clientversion le_capsnode le_capsversion cb_contactsenable cb_conferencesenable cmb_showrequ cmb_savetolog cb_logslist bt_viewlog plugins-1.5/generic/clientswitcherplugin/resources.qrc000066400000000000000000000001461336777360500234650ustar00rootroot00000000000000 clientswitcher.png plugins-1.5/generic/clientswitcherplugin/typeaheadfind.cpp000066400000000000000000000123311336777360500242540ustar00rootroot00000000000000/* * typeaheadfind.cpp - plugin * Copyright (C) 2009-2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "typeaheadfind.h" #include #include #include #include using namespace ClientSwitcher; class TypeAheadFindBar::Private { public: void doFind(bool backward = false) { QTextDocument::FindFlags options; if (caseSensitive) options |= QTextDocument::FindCaseSensitively; if (backward) { options |= QTextDocument::FindBackward; QTextCursor cursor = te->textCursor(); cursor.setPosition(cursor.selectionStart()); cursor.movePosition(QTextCursor::Left); te->setTextCursor(cursor); } if (find(text, options)) { le_find->setStyleSheet(""); } else { le_find->setStyleSheet("QLineEdit { background: #ff6666; color: #ffffff }"); } } bool find(const QString &str, QTextDocument::FindFlags options, QTextCursor::MoveOperation start = QTextCursor::NoMove) { Q_UNUSED(str); if (start != QTextCursor::NoMove) { QTextCursor cursor = te->textCursor(); cursor.movePosition(start); te->setTextCursor(cursor); } bool found = te->find(text, options); if (!found) { if (start == QTextCursor::NoMove) return find(text, options, options & QTextDocument::FindBackward ? QTextCursor::End : QTextCursor::Start); return false; } return true; } QString text; bool caseSensitive; QTextEdit *te; QLineEdit *le_find; QPushButton *but_next; QPushButton *but_prev; QPushButton *first_page, *next_page, *last_page, *prev_page; QCheckBox *cb_case; }; TypeAheadFindBar::TypeAheadFindBar(IconFactoryAccessingHost *IcoHost, QTextEdit *textedit, const QString &title, QWidget *parent) : QToolBar(title, parent) , icoHost_(IcoHost) { d = new Private(); d->te = textedit; init(); } void TypeAheadFindBar::init() { d->caseSensitive = false; d->text = ""; addWidget(new QLabel(tr("Search: "), this)); d->le_find = new QLineEdit(this); d->le_find->setMaximumWidth(128); connect(d->le_find, SIGNAL(textEdited(const QString &)), SLOT(textChanged(const QString &))); addWidget(d->le_find); d->but_prev = new QPushButton(this); d->but_prev->setFixedSize(25,25); d->but_prev->setIcon(icoHost_->getIcon("psi/arrowUp")); d->but_prev->setEnabled(false); connect(d->but_prev, SIGNAL(released()), SLOT(findPrevious())); addWidget(d->but_prev); d->but_next = new QPushButton(this); d->but_next->setFixedSize(25,25); d->but_next->setIcon(icoHost_->getIcon("psi/arrowDown")); d->but_next->setEnabled(false); connect(d->but_next, SIGNAL(released()), SLOT(findNext())); addWidget(d->but_next); d->cb_case = new QCheckBox(tr("&Case sensitive"), this); connect(d->cb_case, SIGNAL(clicked()), SLOT(caseToggled())); addWidget(d->cb_case); addSeparator(); d->first_page = new QPushButton(this); d->first_page->setToolTip(tr("First page")); connect(d->first_page, SIGNAL(released()), SIGNAL(firstPage())); d->first_page->setFixedSize(25,25); d->first_page->setIcon(icoHost_->getIcon("psi/doubleBackArrow")); addWidget(d->first_page); d->prev_page = new QPushButton(this); d->prev_page->setToolTip(tr("Previous page")); connect(d->prev_page, SIGNAL(released()), SIGNAL(prevPage())); d->prev_page->setFixedSize(25,25); d->prev_page->setIcon(icoHost_->getIcon("psi/arrowLeft")); addWidget(d->prev_page); d->next_page = new QPushButton(this); d->next_page->setToolTip(tr("Next page")); connect(d->next_page, SIGNAL(released()), SIGNAL(nextPage())); d->next_page->setFixedSize(25,25); d->next_page->setIcon(icoHost_->getIcon("psi/arrowRight")); addWidget(d->next_page); d->last_page = new QPushButton(this); d->last_page->setToolTip(tr("Last page")); connect(d->last_page, SIGNAL(released()), SIGNAL(lastPage())); d->last_page->setFixedSize(25,25); d->last_page->setIcon(icoHost_->getIcon("psi/doubleNextArrow")); addWidget(d->last_page); } TypeAheadFindBar::~TypeAheadFindBar() { delete d; d = 0; } void TypeAheadFindBar::textChanged(const QString &str) { QTextCursor cursor = d->te->textCursor(); if (str.isEmpty()) { d->but_next->setEnabled(false); d->but_prev->setEnabled(false); d->le_find->setStyleSheet(""); cursor.clearSelection(); d->te->setTextCursor(cursor); } else { d->but_next->setEnabled(true); d->but_prev->setEnabled(true); cursor.setPosition(cursor.selectionStart()); d->te->setTextCursor(cursor); d->text = str; d->doFind(); } } void TypeAheadFindBar::findNext() { d->doFind(); } void TypeAheadFindBar::findPrevious() { d->doFind(true); } void TypeAheadFindBar::caseToggled() { d->caseSensitive = d->cb_case->checkState(); } plugins-1.5/generic/clientswitcherplugin/typeaheadfind.h000066400000000000000000000026701336777360500237260ustar00rootroot00000000000000/* * typeaheadfind.h - plugin * Copyright (C) 2009-2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef TYPEAHEADFIND_H #define TYPEAHEADFIND_H #include #include #include "iconfactoryaccessinghost.h" namespace ClientSwitcher { class TypeAheadFindBar : public QToolBar { Q_OBJECT public: TypeAheadFindBar(IconFactoryAccessingHost *IcoHost, QTextEdit *textedit, const QString &title, QWidget *parent = 0); ~TypeAheadFindBar(); void init(); signals: void firstPage(); void lastPage(); void nextPage(); void prevPage(); private slots: void textChanged(const QString &); void findNext(); void findPrevious(); void caseToggled(); private: class Private; Private *d; IconFactoryAccessingHost *icoHost_; }; } #endif plugins-1.5/generic/clientswitcherplugin/viewer.cpp000066400000000000000000000123471336777360500227570ustar00rootroot00000000000000/* * viewer.cpp - plugin * Copyright (C) 2009-2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "viewer.h" #include #include #include #include #include #include Viewer::Viewer(QString filename, IconFactoryAccessingHost *IcoHost, QWidget *parent) : QDialog(parent) , icoHost_(IcoHost) , fileName_(filename) { setAttribute(Qt::WA_DeleteOnClose); setWindowTitle(filename); QVBoxLayout *layout = new QVBoxLayout(this); textWid = new QTextEdit(); QPalette pal = textWid->palette(); pal.setColor(QPalette::Inactive, QPalette::Highlight, pal.color(QPalette::Active, QPalette::Highlight)); pal.setColor(QPalette::Inactive, QPalette::HighlightedText, pal.color(QPalette::Active, QPalette::HighlightedText)); textWid->setPalette(pal); layout->addWidget(textWid); findBar = new ClientSwitcher::TypeAheadFindBar(icoHost_, textWid, tr("Find"), this); QPushButton *Close = new QPushButton(icoHost_->getIcon("psi/quit"), tr("Close")); QPushButton *Save = new QPushButton(icoHost_->getIcon("psi/save"), tr("Save Changes")); QPushButton *Delete = new QPushButton(icoHost_->getIcon("psi/remove"), tr("Delete Log")); QPushButton *Update = new QPushButton(icoHost_->getIcon("psi/reload"), tr("Update Log")); QHBoxLayout *butLayout = new QHBoxLayout(); butLayout->addWidget(Delete); butLayout->addStretch(); butLayout->addWidget(Update); butLayout->addWidget(Save); butLayout->addWidget(Close); layout->addWidget(findBar); layout->addLayout(butLayout); connect(Close, SIGNAL(released()), this, SLOT(close())); connect(Delete, SIGNAL(released()), this, SLOT(deleteLog())); connect(Save, SIGNAL(released()), this, SLOT(saveLog())); connect(Update, SIGNAL(released()), this, SLOT(updateLog())); connect(findBar, SIGNAL(firstPage()), this, SLOT(firstPage())); connect(findBar, SIGNAL(lastPage()), this, SLOT(lastPage())); connect(findBar, SIGNAL(prevPage()), this, SLOT(prevPage())); connect(findBar, SIGNAL(nextPage()), this, SLOT(nextPage())); } void Viewer::closeEvent(QCloseEvent *e) { emit onClose(width(), height()); QDialog::closeEvent(e); e->accept(); } void Viewer::deleteLog() { int ret = QMessageBox::question(this, tr("Delete log file"), tr("Are you sure?"), QMessageBox::Yes, QMessageBox::Cancel); if(ret == QMessageBox::Cancel) { return; } close(); QFile file(fileName_); if(file.open(QIODevice::ReadWrite)) { file.remove(); } } void Viewer::saveLog() { QDateTime Modified = QFileInfo(fileName_).lastModified(); if(lastModified_ < Modified) { QMessageBox msgBox; msgBox.setWindowTitle(tr("Save log")); msgBox.setText(tr("New messages has been added to log. If you save your changes, you will lose them")); msgBox.setInformativeText(tr("Do you want to save your changes?")); msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Cancel); msgBox.setDefaultButton(QMessageBox::Cancel); int ret = msgBox.exec(); if(ret == QMessageBox::Cancel) { return; } } else { int ret = QMessageBox::question(this, tr("Save log"), tr("Are you sure?"), QMessageBox::Yes, QMessageBox::Cancel); if(ret == QMessageBox::Cancel) { return; } } QFile file(fileName_); if(file.open(QIODevice::ReadWrite)) { file.remove(); } if(file.open(QIODevice::ReadWrite)) { QTextStream out(&file); out.setCodec("UTF-8"); QString Text = textWid->toPlainText(); pages_.insert(currentPage_, Text); for(int i = 0; i < pages_.size(); i++) { out.setGenerateByteOrderMark(false); out << pages_.value(i); } } } void Viewer::updateLog() { pages_.clear(); init(); } bool Viewer::init() { bool b = false; QFile file(fileName_); if(file.open(QIODevice::ReadOnly)) { QString page; int numPage = 0; QTextStream in(&file); in.setCodec("UTF-8"); while(!in.atEnd()) { page = ""; for(int i = 0; i < 500; i++) { if(in.atEnd()) break; page += in.readLine() + "\n"; } pages_.insert(numPage++, page); } currentPage_ = pages_.size()-1; lastModified_ = QDateTime::currentDateTime(); setPage(); b = true; } return b; } void Viewer::setPage() { QString text = pages_.value(currentPage_); textWid->setText(text); QTextCursor cur = textWid->textCursor(); cur.setPosition(text.length()); textWid->setTextCursor(cur); } void Viewer::nextPage() { if(currentPage_ < pages_.size()-1) currentPage_++; setPage(); } void Viewer::prevPage() { if(currentPage_ > 0) currentPage_--; setPage(); } void Viewer::lastPage() { currentPage_ = pages_.size()-1; setPage(); } void Viewer::firstPage() { currentPage_ = 0; setPage(); } plugins-1.5/generic/clientswitcherplugin/viewer.h000066400000000000000000000031001336777360500224070ustar00rootroot00000000000000/* * viewer.h - plugin * Copyright (C) 2009-2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef VIEWER_H #define VIEWER_H #include #include #include #include #include "iconfactoryaccessinghost.h" #include "typeaheadfind.h" class Viewer : public QDialog { Q_OBJECT public: Viewer(QString filename, IconFactoryAccessingHost *IcoHost, QWidget *parent = 0); bool init(); private: IconFactoryAccessingHost *icoHost_; QString fileName_; QDateTime lastModified_; QTextEdit *textWid; ClientSwitcher::TypeAheadFindBar *findBar; QMap pages_; int currentPage_; void setPage(); private slots: void saveLog(); void updateLog(); void deleteLog(); void nextPage(); void prevPage(); void firstPage(); void lastPage(); protected: void closeEvent(QCloseEvent *e); signals: void onClose(int,int); }; #endif // VIEWER_H plugins-1.5/generic/conferenceloggerplugin/000077500000000000000000000000001336777360500212235ustar00rootroot00000000000000plugins-1.5/generic/conferenceloggerplugin/CMakeLists.txt000066400000000000000000000025201336777360500237620ustar00rootroot00000000000000unset(_HDRS) unset(_UIS) unset(_SRCS) unset(_RSCS) unset(PLUGIN) set( PLUGIN conferenceloggerplugin ) project(${PLUGIN}) cmake_minimum_required(VERSION 3.1.0) set( CMAKE_AUTOMOC ON ) IF( NOT WIN32 ) set( LIB_SUFFIX "" CACHE STRING "Define suffix of directory name (32/64)" ) set( PLUGINS_PATH "lib${LIB_SUFFIX}/psi-plus/plugins" CACHE STRING "Install suffix for plugins" ) ELSE() set( PLUGINS_PATH "psi-plus/plugins" CACHE STRING "Install suffix for plugins" ) ENDIF() add_definitions( -DQT_PLUGIN -DHAVE_QT5 ) include_directories( ${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ../../include . ) set( _HDRS typeaheadfind.h viewer.h ) set( _SRCS ${PLUGIN}.cpp typeaheadfind.cpp viewer.cpp ) set( _RSCS ${PLUGIN}.qrc ) find_package( Qt5 COMPONENTS Widgets Xml REQUIRED ) set(QT_DEPLIBS Qt5::Widgets Qt5::Xml ) qt5_add_resources(RSCS ${_RSCS}) add_library( ${PLUGIN} MODULE ${_SRCS} ${RSCS} ) target_link_libraries( ${PLUGIN} ${QT_DEPLIBS} ) if( UNIX AND NOT( APPLE OR CYGWIN ) ) install( TARGETS ${PLUGIN} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} ) endif() if( WIN32 ) install( TARGETS ${PLUGIN} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} ) endif() plugins-1.5/generic/conferenceloggerplugin/changelog.txt000066400000000000000000000105401336777360500237130ustar00rootroot000000000000002013-09-02 v0.2.2 - taurus * Использовать слово Groupchat вместо Conference 2013-08-13 v0.2.1 - taurus + Иконка плагина 2011-07-13 v0.2.0 * исправлен цвет подсветки при поиске в логах, актуально для Windows систем 2011-01-12 v0.1.9 * небольшие исправления 2010-09-11 v0.1.7 * обновлена ссылка на wiki ( http://psi-plus.com/wiki/plugins#conference_logger_plugin ) 2010-08-25 v0.1.6 * совместимость с последней версией Psi+ 2010-05-17 v0.1.5 + добавлена информация о плагине 2010-05-04 v0.1.4 * исправлена ссылка на wiki 2010-04-25 v0.1.3 * исправлено сохранение изменённого лога 2010-04-24 v0.1.2 + логи большого размера разбиваются на страницы * различные оптимизации кода 2010-03-19 v0.1.1 + добавлены иконки + при открытии лога курсор располагается в конце лога + несколько изменены запросы на подтверждение удаления и сохранения лога 2009-12-23 v0.1.0 + добавлена кнопка на тулбаре в окне конференции для вызова лога - убрана горячая клавиша 2009-12-08 v0.0.9 * горячая клавиша теперь работает во всех режимах отображения табов * по горячей клавише теперь открывается нужный лог * багфиксы + в настройки плагина добавлена ссылка на wiki ВНИМАНИЕ! Для работы этой версии необходимо использовать Psi+ r1451 и старше 2009-12-01 v0.0.7 + добавлен поиск в логе конференции + добавлены возможности обновить лог, редактировать лог, сохранить отредактированный лог и удалить лог 2009-11-30 v0.0.6 * хоткей теперь должен работать и для транспортов * для ОС семейства Windows логи принудительно будут писаться в utf-8 ВНИМАНИЕ! Старые логи, сохранённые в кодировке cp1251, будут отображаться нечитаемыми символами. Рекомендуется вручную сконвертировать их в utf-8. 2009-11-26 v0.0.5 + добавлена возможность назначить горячую клавишу для открытия лога текущей конференции (имеется ввиду, для активной текущей вкладки) ВНИМАНИЕ! На данный момент горячая клавиша работает только в режиме табов! Также, если вы заходили в конференцию с нескольких аккаунтов, то будет открыт лог, который идёт первым в списке логов. 2009-11-24 v0.0.4 * теперь в настройках запоминается последний выбранный лог 2009-11-24 v0.0.3 + добавлена возможность просматривать логи непосредственно из настроек плагина 2009-11-02 v0.0.2 + в настройки плагина добавлена метка, в которой указан путь расположения логов 2009-10-31 v0.0.1 !Initial version Плагин предназначен для сохранения логов конференций. Логи сохраняются в папку с историей в файл вида "yourname_at_yoourserver_in_room_at_server". Т.к. в момент подключения к комнате выводится некоторое количество старых сообщений, то возможно, что в логе сообщения будут продублированы (в случае частых переподключений). plugins-1.5/generic/conferenceloggerplugin/conferencelogger.png000066400000000000000000000025351336777360500252450ustar00rootroot00000000000000PNG  IHDRW?gAMA asRGB cHRMz&u0`:pQ<PLTE_``deeSUVph^v[yRueWgggV[_fa]xbfʙgd}`}kZ_\X_`agb\w_hңvժߦrӗ^_{hvf[VPd`\u_ÖcܨqקyҠtϠtԧzث{ѡmWydwikd[g`\s_”g׫xԬ}ΣwӟrѡvĘmaĕbϦuҬvǑWtZUY\hb\u^aԤtӥxΡwϡxԤw^h9R$S&m?۫uyMmWF:>@lg`ybe֟m֧wПtОuРu”dg3W'Y.T*|GyPbF.7-% "$]__{ck٥uզtџrץz͜oq?~OpBia\.H3L2H9-,/0eefZȗgӣ{ը{ըvԥuܭǘkW#T$f黎ŽȝmW3{bQTWeffF=,f?k9Нn֪֭}٬ΡsvHvDn<֣n٩{J*xX=k[Q%()fefTE1eM2x^FsS5i3ʗdܱڲ̠ryLtN'jD͠t٥q}^8TH<)((ffgbD{Xnp[HtU:_=sEƒ^٪~P=$M6UgeVF%%#__`oSi|lxkgT@nJ+]7xPtB8#C/cAmaR%&)e^Zog`t\[Ȟryu]RLP0s]|dBlV6TH7!%%%%A>;vnetb]țfxz``SD "#::9C?;pg\|e`kf[O)(&7;@NKHo]LuZi\P9;>OSU%')G ]tRNS@fbKGDH pHYsHHFk>GIDATc`F&ft*/ ($&,"*&.!)%-# WPTRVQUS҆[XZYll]\=<}|CB#"cb}USR32sr }KJ+*kj[|Z;:{z'L4yi}f̜5{y,\xeW\˰zu7lܴymwܵ{A{?p#G?q3gN?wK\v[}s=~xvt>mwPogY.L֖%tEXtdate:create2013-04-12T03:33:51+06:00%tEXtdate:modify2013-04-12T03:33:51+06:00B1IENDB`plugins-1.5/generic/conferenceloggerplugin/conferenceloggerplugin.cpp000066400000000000000000000244561336777360500264700ustar00rootroot00000000000000/* * conferenceloggerplugin.cpp - plugin * Copyright (C) 2009-2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include #include #include #include #include #include #include #include "psiplugin.h" #include "stanzafilter.h" #include "accountinfoaccessor.h" #include "accountinfoaccessinghost.h" #include "applicationinfoaccessor.h" #include "applicationinfoaccessinghost.h" #include "optionaccessor.h" #include "optionaccessinghost.h" #include "activetabaccessinghost.h" #include "activetabaccessor.h" #include "iconfactoryaccessor.h" #include "iconfactoryaccessinghost.h" #include "gctoolbariconaccessor.h" #include "plugininfoprovider.h" #include "viewer.h" #define cVer "0.2.2" #define constHeight "Height" #define constWidth "Width" #define constlastItem "lastItem" #define constShortCut "shortcut" class ConferenceLogger: public QObject, public PsiPlugin, public StanzaFilter, public AccountInfoAccessor, public ApplicationInfoAccessor, public OptionAccessor, public ActiveTabAccessor, public GCToolbarIconAccessor, public IconFactoryAccessor, public PluginInfoProvider { Q_OBJECT #ifdef HAVE_QT5 Q_PLUGIN_METADATA(IID "com.psi-plus.ConferenceLogger") #endif Q_INTERFACES(PsiPlugin StanzaFilter AccountInfoAccessor ApplicationInfoAccessor OptionAccessor ActiveTabAccessor GCToolbarIconAccessor IconFactoryAccessor PluginInfoProvider) public: ConferenceLogger(); virtual QString name() const; virtual QString shortName() const; virtual QString version() const; virtual QWidget* options(); virtual bool enable(); virtual bool disable(); virtual void applyOptions(); virtual void restoreOptions(){}; virtual bool incomingStanza(int account, const QDomElement& xml); virtual bool outgoingStanza(int account, QDomElement& xml); virtual void setAccountInfoAccessingHost(AccountInfoAccessingHost* host); virtual void setApplicationInfoAccessingHost(ApplicationInfoAccessingHost* host); virtual void setOptionAccessingHost(OptionAccessingHost* host); virtual void optionChanged(const QString& /*option*/){}; virtual void setActiveTabAccessingHost(ActiveTabAccessingHost* host); virtual void setIconFactoryAccessingHost(IconFactoryAccessingHost* host); virtual QList < QVariantHash > getGCButtonParam(); virtual QAction* getGCAction(QObject* , int , const QString& ) { return 0; }; virtual QString pluginInfo(); virtual QPixmap icon() const; private: bool enabled; AccountInfoAccessingHost *AccInfoHost; ApplicationInfoAccessingHost *AppInfoHost; OptionAccessingHost *psiOptions; ActiveTabAccessingHost* activeTab; IconFactoryAccessingHost *IcoHost; QString HistoryDir; void Logger(QString room, QString from, QString MyJid, QString Text, QString Stamp); QComboBox *FilesBox; QPushButton *viewButton; int Height; int Width; QString lastItem; void showLog(QString filename); private slots: void view(); void viewFromOpt(); void onClose(int, int); }; #ifndef HAVE_QT5 Q_EXPORT_PLUGIN(ConferenceLogger); #endif ConferenceLogger::ConferenceLogger() { enabled = false; AppInfoHost = 0; AccInfoHost = 0; psiOptions = 0; IcoHost = 0; activeTab = 0; HistoryDir = ""; FilesBox = 0; viewButton = 0; Height = 500; Width = 600; lastItem = ""; } QString ConferenceLogger::name() const { return "Conference Logger Plugin"; } QString ConferenceLogger::shortName() const { return "logger"; } QString ConferenceLogger::version() const { return cVer; } bool ConferenceLogger::enable() { QFile file(":/conferenceloggerplugin/conferencelogger.png"); if ( file.open(QIODevice::ReadOnly) ) { QByteArray image = file.readAll(); IcoHost->addIcon("loggerplugin/openlog",image); file.close(); } else { enabled = false; return enabled; } if(psiOptions) { enabled = true; HistoryDir = AppInfoHost->appHistoryDir(); Height = psiOptions->getPluginOption(constHeight, QVariant(Height)).toInt(); Width = psiOptions->getPluginOption(constWidth, QVariant(Width)).toInt(); lastItem = psiOptions->getPluginOption(constlastItem, QVariant(lastItem)).toString(); } return enabled; } bool ConferenceLogger::disable() { enabled = false; return true; } QWidget* ConferenceLogger::options() { if(!enabled) { return 0; } QWidget *options = new QWidget(); QVBoxLayout *layout = new QVBoxLayout(options); QLabel *label = new QLabel(tr("You can find your logs here:")); QLineEdit *path = new QLineEdit; path->setText(HistoryDir); path->setEnabled(false); FilesBox = new QComboBox(); QDir dir(HistoryDir); foreach(QString file, dir.entryList(QDir::Files)) { if(file.contains("_in_")) { FilesBox->addItem(file); } } for(int i = FilesBox->count(); i > 0; --i) { if(FilesBox->itemText(i) == lastItem) { FilesBox->setCurrentIndex(i); } } QHBoxLayout *filesLayout = new QHBoxLayout(); filesLayout->addWidget(new QLabel(tr("Logs:"))); filesLayout->addWidget(FilesBox); filesLayout->addStretch(); viewButton = new QPushButton(IcoHost->getIcon("psi/search"), tr("View Log")); connect(viewButton, SIGNAL(released()), SLOT(viewFromOpt())); QLabel *wikiLink = new QLabel(tr("Wiki (Online)")); wikiLink->setOpenExternalLinks(true); filesLayout->addWidget(viewButton); layout->addWidget(label); layout->addWidget(path); layout->addLayout(filesLayout); layout->addStretch(); layout->addWidget(wikiLink); return options; } bool ConferenceLogger::incomingStanza(int account, const QDomElement& stanza) { if (enabled) { if(stanza.tagName() == "message") { if(stanza.attribute("type") == "groupchat") { QString from = stanza.attribute("from"); QStringList List = from.split("/"); QString room = List.takeFirst(); from = ""; if(!List.isEmpty()) { from = List.join("/"); } QString Stamp = ""; Stamp = stanza.firstChildElement("x").attribute("stamp"); QDomElement body = stanza.firstChildElement("body"); if(!body.isNull()) { QString Text = body.text(); QString MyJid = AccInfoHost->getJid(account); MyJid = MyJid.replace("@", "_at_"); Logger(room, from, MyJid, Text, Stamp); } } } } return false; } bool ConferenceLogger::outgoingStanza(int /*account*/, QDomElement& /*xml*/) { return false; } void ConferenceLogger::setAccountInfoAccessingHost(AccountInfoAccessingHost* host) { AccInfoHost = host; } void ConferenceLogger::setApplicationInfoAccessingHost(ApplicationInfoAccessingHost* host) { AppInfoHost = host; } void ConferenceLogger::Logger(QString room, QString from, QString MyJid, QString Text, QString Stamp) { room = room.replace("@", "_at_"); room = "_in_" + room; if(Stamp == "") { Stamp = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss"); } else { Stamp.insert(4, "-"); Stamp.insert(7, "-"); Stamp.replace("T", " "); } QFile file(HistoryDir + QDir::separator() + MyJid + room); if(file.open(QIODevice::WriteOnly | QIODevice::Append)) { QTextStream out(&file); //out.seek(file.size()); out.setCodec("UTF-8"); out.setGenerateByteOrderMark(false); out << Stamp << " " << from << ": " << Text << endl; } } void ConferenceLogger::applyOptions() { if (FilesBox == 0) return; QVariant vlastItem(FilesBox->currentText()); lastItem = vlastItem.toString(); psiOptions->setPluginOption(constlastItem, vlastItem); } void ConferenceLogger::setOptionAccessingHost(OptionAccessingHost* host) { psiOptions = host; } void ConferenceLogger::viewFromOpt() { lastItem = FilesBox->currentText(); psiOptions->setPluginOption(constlastItem, QVariant(lastItem)); showLog(lastItem); } void ConferenceLogger::view() { if(!enabled) return; QString Jid = activeTab->getJid(); QString YourJid = activeTab->getYourJid(); if(Jid == "" || YourJid == "") { return; } Jid = Jid.replace("@", "_at_"); QStringList List = YourJid.split("/"); YourJid = List.takeFirst(); YourJid = YourJid.replace("@", "_at_"); QString FName = YourJid + "_in_" + Jid; QDir dir(HistoryDir); foreach(QString file, dir.entryList(QDir::Files)) { if(file == FName) { showLog(file); break; } } } void ConferenceLogger::showLog(QString filename) { filename = HistoryDir + "/" + filename; Viewer *v = new Viewer(filename, IcoHost); v->resize(Width, Height); if(!v->init()) { delete(v); return; } connect(v, SIGNAL(onClose(int,int)), this, SLOT(onClose(int,int))); v->show(); } void ConferenceLogger::onClose(int w, int h) { Width = w; Height = h; psiOptions->setPluginOption(constWidth, QVariant(Width)); psiOptions->setPluginOption(constHeight, QVariant(Height)); } void ConferenceLogger::setActiveTabAccessingHost(ActiveTabAccessingHost* host) { activeTab = host; } void ConferenceLogger::setIconFactoryAccessingHost(IconFactoryAccessingHost *host) { IcoHost = host; } QList < QVariantHash > ConferenceLogger::getGCButtonParam() { QList< QVariantHash > l; QVariantHash hash; hash["tooltip"] = QVariant(tr("Groupchat History")); hash["icon"] = QVariant(QString("loggerplugin/openlog")); hash["reciver"] = qVariantFromValue(qobject_cast(this)); hash["slot"] = QVariant(SLOT(view())); l.push_back(hash); return l; } QString ConferenceLogger::pluginInfo() { return tr("Author: ") + "Dealer_WeARE\n" + tr("Email: ") + "wadealer@gmail.com\n\n" + trUtf8("This plugin is designed to save groupchat logs in which the Psi+ user sits.\n" "Groupchats logs can be viewed from the plugin settings or by clicking on the appropriate button on the toolbar in the active window/tab with groupchat.\n\n" "Note: To work correctly, the the Groupchat Toolbar must be enabled."); } QPixmap ConferenceLogger::icon() const { return QPixmap(":/conferenceloggerplugin/conferencelogger.png"); } #include "conferenceloggerplugin.moc" plugins-1.5/generic/conferenceloggerplugin/conferenceloggerplugin.pro000066400000000000000000000004141336777360500264720ustar00rootroot00000000000000isEmpty(PSISDK) { include(../../psiplugin.pri) } else { include($$PSISDK/plugins/psiplugin.pri) } RESOURCES = conferenceloggerplugin.qrc SOURCES += conferenceloggerplugin.cpp \ typeaheadfind.cpp \ viewer.cpp HEADERS += typeaheadfind.h \ viewer.h plugins-1.5/generic/conferenceloggerplugin/conferenceloggerplugin.qrc000066400000000000000000000001721336777360500264600ustar00rootroot00000000000000 conferencelogger.png plugins-1.5/generic/conferenceloggerplugin/typeaheadfind.cpp000066400000000000000000000121601336777360500245340ustar00rootroot00000000000000/* * typeaheadfind.cpp - plugin * Copyright (C) 2009-2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "typeaheadfind.h" #include #include #include #include using namespace ConfLogger; class TypeAheadFindBar::Private { public: void doFind(bool backward = false) { QTextDocument::FindFlags options; if (caseSensitive) options |= QTextDocument::FindCaseSensitively; if (backward) { options |= QTextDocument::FindBackward; QTextCursor cursor = te->textCursor(); cursor.setPosition(cursor.selectionStart()); cursor.movePosition(QTextCursor::Left); te->setTextCursor(cursor); } if (find(text, options)) { le_find->setStyleSheet(""); } else { le_find->setStyleSheet("QLineEdit { background: #ff6666; color: #ffffff }"); } } bool find(const QString &str, QTextDocument::FindFlags options, QTextCursor::MoveOperation start = QTextCursor::NoMove) { Q_UNUSED(str); if (start != QTextCursor::NoMove) { QTextCursor cursor = te->textCursor(); cursor.movePosition(start); te->setTextCursor(cursor); } bool found = te->find(text, options); if (!found) { if (start == QTextCursor::NoMove) return find(text, options, options & QTextDocument::FindBackward ? QTextCursor::End : QTextCursor::Start); return false; } return true; } QString text; bool caseSensitive; QTextEdit *te; QLineEdit *le_find; QPushButton *but_next; QPushButton *but_prev; QPushButton *first_page, *next_page, *last_page, *prev_page; QCheckBox *cb_case; }; TypeAheadFindBar::TypeAheadFindBar(IconFactoryAccessingHost *IcoHost, QTextEdit *textedit, const QString &title, QWidget *parent) : QToolBar(title, parent), icoHost_(IcoHost) { d = new Private(); d->te = textedit; init(); } void TypeAheadFindBar::init() { d->caseSensitive = false; d->text = ""; addWidget(new QLabel(tr("Search: "), this)); d->le_find = new QLineEdit(this); d->le_find->setMaximumWidth(128); connect(d->le_find, &QLineEdit::textEdited, this, &TypeAheadFindBar::textChanged); addWidget(d->le_find); d->but_prev = new QPushButton(this); d->but_prev->setFixedSize(25,25); d->but_prev->setIcon(icoHost_->getIcon("psi/arrowUp")); d->but_prev->setEnabled(false); connect(d->but_prev, &QPushButton::released, [this]{d->doFind(true);}); addWidget(d->but_prev); d->but_next = new QPushButton(this); d->but_next->setFixedSize(25,25); d->but_next->setIcon(icoHost_->getIcon("psi/arrowDown")); d->but_next->setEnabled(false); connect(d->but_next, &QPushButton::released, [this]{d->doFind();}); addWidget(d->but_next); d->cb_case = new QCheckBox(tr("&Case sensitive"), this); connect(d->cb_case, &QCheckBox::clicked, [this]{d->caseSensitive = d->cb_case->checkState();}); addWidget(d->cb_case); addSeparator(); d->first_page = new QPushButton(this); d->first_page->setToolTip(tr("First page")); connect(d->first_page, &QPushButton::released, this, &TypeAheadFindBar::firstPage); d->first_page->setFixedSize(25,25); d->first_page->setIcon(icoHost_->getIcon("psi/doubleBackArrow")); addWidget(d->first_page); d->prev_page = new QPushButton(this); d->prev_page->setToolTip(tr("Previous page")); connect(d->prev_page, &QPushButton::released, this, &TypeAheadFindBar::prevPage); d->prev_page->setFixedSize(25,25); d->prev_page->setIcon(icoHost_->getIcon("psi/arrowLeft")); addWidget(d->prev_page); d->next_page = new QPushButton(this); d->next_page->setToolTip(tr("Next page")); connect(d->next_page, &QPushButton::released, this, &TypeAheadFindBar::nextPage); d->next_page->setFixedSize(25,25); d->next_page->setIcon(icoHost_->getIcon("psi/arrowRight")); addWidget(d->next_page); d->last_page = new QPushButton(this); d->last_page->setToolTip(tr("Last page")); connect(d->last_page, &QPushButton::released, this, &TypeAheadFindBar::lastPage); d->last_page->setFixedSize(25,25); d->last_page->setIcon(icoHost_->getIcon("psi/doubleNextArrow")); addWidget(d->last_page); } TypeAheadFindBar::~TypeAheadFindBar() { delete d; d = 0; } void TypeAheadFindBar::textChanged(const QString &str) { QTextCursor cursor = d->te->textCursor(); if (str.isEmpty()) { d->but_next->setEnabled(false); d->but_prev->setEnabled(false); d->le_find->setStyleSheet(""); cursor.clearSelection(); d->te->setTextCursor(cursor); } else { d->but_next->setEnabled(true); d->but_prev->setEnabled(true); cursor.setPosition(cursor.selectionStart()); d->te->setTextCursor(cursor); d->text = str; d->doFind(); } } plugins-1.5/generic/conferenceloggerplugin/typeaheadfind.h000066400000000000000000000025661336777360500242120ustar00rootroot00000000000000/* * typeaheadfind.h - plugin * Copyright (C) 2009-2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef TYPEAHEADFIND_H #define TYPEAHEADFIND_H #include #include #include "iconfactoryaccessinghost.h" namespace ConfLogger { class TypeAheadFindBar : public QToolBar { Q_OBJECT public: TypeAheadFindBar(IconFactoryAccessingHost *IcoHost, QTextEdit *textedit, const QString &title, QWidget *parent = 0); ~TypeAheadFindBar(); void init(); signals: void firstPage(); void lastPage(); void nextPage(); void prevPage(); private slots: void textChanged(const QString &); private: class Private; Private *d; IconFactoryAccessingHost *icoHost_; }; } #endif plugins-1.5/generic/conferenceloggerplugin/viewer.cpp000077500000000000000000000126161336777360500232410ustar00rootroot00000000000000/* * viewer.cpp - plugin * Copyright (C) 2009-2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "viewer.h" #include #include #include #include #include #include Viewer::Viewer(QString filename, IconFactoryAccessingHost *IcoHost, QWidget *parent) : QDialog(parent) , icoHost_(IcoHost) , fileName_(filename) { setAttribute(Qt::WA_DeleteOnClose); setWindowTitle(filename); QVBoxLayout *layout = new QVBoxLayout(this); textWid = new QTextEdit(); QPalette pal = textWid->palette(); pal.setColor(QPalette::Inactive, QPalette::Highlight, pal.color(QPalette::Active, QPalette::Highlight)); pal.setColor(QPalette::Inactive, QPalette::HighlightedText, pal.color(QPalette::Active, QPalette::HighlightedText)); textWid->setPalette(pal); layout->addWidget(textWid); findBar = new ConfLogger::TypeAheadFindBar(icoHost_, textWid, tr("Find"), this); QPushButton *Close = new QPushButton(icoHost_->getIcon("psi/quit"), tr("Close")); QPushButton *Save = new QPushButton(icoHost_->getIcon("psi/save"), tr("Save Changes")); QPushButton *Delete = new QPushButton(icoHost_->getIcon("psi/remove"), tr("Delete Log")); QPushButton *Update = new QPushButton(icoHost_->getIcon("psi/reload"), tr("Update Log")); QHBoxLayout *butLayout = new QHBoxLayout(); butLayout->addWidget(Delete); butLayout->addStretch(); butLayout->addWidget(Update); butLayout->addWidget(Save); butLayout->addWidget(Close); layout->addWidget(findBar); layout->addLayout(butLayout); connect(Close, &QPushButton::released, this, &Viewer::close); connect(Delete, &QPushButton::released, this, &Viewer::deleteLog); connect(Save, &QPushButton::released, this, &Viewer::saveLog); connect(Update, &QPushButton::released, this, &Viewer::updateLog); connect(findBar, &ConfLogger::TypeAheadFindBar::firstPage, this, &Viewer::firstPage); connect(findBar, &ConfLogger::TypeAheadFindBar::lastPage, this, &Viewer::lastPage); connect(findBar, &ConfLogger::TypeAheadFindBar::prevPage, this, &Viewer::prevPage); connect(findBar, &ConfLogger::TypeAheadFindBar::nextPage, this, &Viewer::nextPage); } void Viewer::closeEvent(QCloseEvent *e) { emit onClose(width(), height()); QDialog::closeEvent(e); e->accept(); } void Viewer::deleteLog() { int ret = QMessageBox::question(this, tr("Delete log file"), tr("Are you sure?"), QMessageBox::Yes, QMessageBox::Cancel); if(ret == QMessageBox::Cancel) { return; } close(); QFile file(fileName_); if(file.open(QIODevice::ReadWrite)) { file.remove(); } } void Viewer::saveLog() { QDateTime Modified = QFileInfo(fileName_).lastModified(); if(lastModified_ < Modified) { QMessageBox msgBox; msgBox.setWindowTitle(tr("Save log")); msgBox.setText(tr("New messages has been added to log. If you save your changes, you will lose them")); msgBox.setInformativeText(tr("Do you want to save your changes?")); msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Cancel); msgBox.setDefaultButton(QMessageBox::Cancel); int ret = msgBox.exec(); if(ret == QMessageBox::Cancel) { return; } } else { int ret = QMessageBox::question(this, tr("Save log"), tr("Are you sure?"), QMessageBox::Yes, QMessageBox::Cancel); if(ret == QMessageBox::Cancel) { return; } } QFile file(fileName_); if(file.open(QIODevice::ReadWrite)) { file.remove(); } if(file.open(QIODevice::ReadWrite)) { QTextStream out(&file); out.setCodec("UTF-8"); QString Text = textWid->toPlainText(); pages_.insert(currentPage_, Text); for(int i = 0; i < pages_.size(); i++) { out.setGenerateByteOrderMark(false); out << pages_.value(i); } } } void Viewer::updateLog() { pages_.clear(); init(); } bool Viewer::init() { bool b = false; QFile file(fileName_); if(file.open(QIODevice::ReadOnly)) { QString page; int numPage = 0; QTextStream in(&file); in.setCodec("UTF-8"); while(!in.atEnd()) { show(); page = ""; for(int i = 0; i < 500; i++) { if(in.atEnd()) break; page += in.readLine() + "\n"; } pages_.insert(numPage++, page); } currentPage_ = pages_.size()-1; lastModified_ = QDateTime::currentDateTime(); setPage(); b = true; } return b; } void Viewer::setPage() { QString text = pages_.value(currentPage_); textWid->setText(text); QTextCursor cur = textWid->textCursor(); cur.setPosition(text.length()); textWid->setTextCursor(cur); } void Viewer::nextPage() { if(currentPage_ < pages_.size()-1) currentPage_++; setPage(); } void Viewer::prevPage() { if(currentPage_ > 0) currentPage_--; setPage(); } void Viewer::lastPage() { currentPage_ = pages_.size()-1; setPage(); } void Viewer::firstPage() { currentPage_ = 0; setPage(); } plugins-1.5/generic/conferenceloggerplugin/viewer.h000077500000000000000000000030741336777360500227040ustar00rootroot00000000000000/* * viewer.h - plugin * Copyright (C) 2009-2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef VIEWER_H #define VIEWER_H #include #include #include #include #include "iconfactoryaccessinghost.h" #include "typeaheadfind.h" class Viewer : public QDialog { Q_OBJECT public: Viewer(QString filename, IconFactoryAccessingHost *IcoHost, QWidget *parent = 0); bool init(); private: IconFactoryAccessingHost *icoHost_; QString fileName_; QDateTime lastModified_; QTextEdit *textWid; ConfLogger::TypeAheadFindBar *findBar; QMap pages_; int currentPage_; void setPage(); private slots: void saveLog(); void updateLog(); void deleteLog(); void nextPage(); void prevPage(); void firstPage(); void lastPage(); protected: void closeEvent(QCloseEvent *e); signals: void onClose(int,int); }; #endif // VIEWER_H plugins-1.5/generic/contentdownloaderplugin/000077500000000000000000000000001336777360500214455ustar00rootroot00000000000000plugins-1.5/generic/contentdownloaderplugin/CMakeLists.txt000066400000000000000000000027251336777360500242130ustar00rootroot00000000000000unset(_HDRS) unset(_UIS) unset(_SRCS) unset(_RSCS) unset(PLUGIN) set( PLUGIN contentdownloaderplugin ) project(${PLUGIN}) cmake_minimum_required(VERSION 3.1.0) set( CMAKE_AUTOMOC TRUE ) IF( NOT WIN32 ) set( LIB_SUFFIX "" CACHE STRING "Define suffix of directory name (32/64)" ) set( PLUGINS_PATH "lib${LIB_SUFFIX}/psi-plus/plugins" CACHE STRING "Install suffix for plugins" ) ELSE() set( PLUGINS_PATH "psi-plus/plugins" CACHE STRING "Install suffix for plugins" ) ENDIF() add_definitions( -DQT_PLUGIN -DHAVE_QT5 ) include_directories( ${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ../../include . ) set( _HDRS contentdownloader.h cditemmodel.h form.h contentitem.h ) set( _SRCS contentdownloader.cpp cditemmodel.cpp form.cpp contentitem.cpp ) set( _UIS form.ui ) set( _RSCS resources.qrc ) find_package( Qt5 COMPONENTS Widgets Xml Network REQUIRED ) set(QT_DEPLIBS Qt5::Widgets Qt5::Xml Qt5::Network ) qt5_wrap_ui(UIS ${_UIS}) qt5_add_resources(RSCS ${_RSCS}) add_library( ${PLUGIN} MODULE ${_SRCS} ${UIS} ${RSCS} ) target_link_libraries( ${PLUGIN} ${QT_DEPLIBS} ) if( UNIX AND NOT( APPLE OR CYGWIN ) ) install( TARGETS ${PLUGIN} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} ) endif() if( WIN32 ) install( TARGETS ${PLUGIN} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} ) endif() plugins-1.5/generic/contentdownloaderplugin/README000066400000000000000000000006641336777360500223330ustar00rootroot00000000000000Content Downloader Plugin for Psi+ The plugin allows you to download and install some content. In the current state only images smileys. Install 1. Download source. 2. Copy contentdownloader folder to src/plugins/generic folder in Psi+ root. 3. cd /src/plugins/generic/contentdownloader 4. Run qmake-qt4 (or qmake). 5. Run make (or gmake). 6. Copy binary library to /usr/lib(64)/psi/plugins or run make install to install in ~/.psi plugins-1.5/generic/contentdownloaderplugin/cditemmodel.cpp000066400000000000000000000157571336777360500244560ustar00rootroot00000000000000/* * cditemmodel.cpp - model for contents tree * Copyright (C) 2010 Ivan Romanov * * 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 #include #include "cditemmodel.h" CDItemModel::CDItemModel(QObject *parent) : QAbstractItemModel(parent) , rootItem_(new ContentItem("")) { } CDItemModel::~CDItemModel() { delete rootItem_; } int CDItemModel::columnCount(const QModelIndex &parent) const { Q_UNUSED(parent) // in our model always only 1 column return 1; } QVariant CDItemModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) { return QVariant(); } if(role == Qt::DisplayRole) { ContentItem *item = static_cast(index.internalPointer()); return item->name(); } ContentItem *item = (ContentItem*)index.internalPointer(); if(role == Qt::CheckStateRole) { if(item->isInstalled()) { return 1; } else if(item->toInstall()) { return 2; } else { return 0; } } return QVariant(); } bool CDItemModel::setData(const QModelIndex &index, const QVariant &value, int role) { if(!index.isValid()) { return false; } if(role == Qt::CheckStateRole) { ContentItem *item = (ContentItem*)index.internalPointer(); item->setToInstall(value.toBool()); // set the same for the descends int i = 0; while(index.child(i, 0).isValid()) { setData(index.child(i++, 0), value, role); } if(index.parent().isValid()) { if(value.toBool() == false) { ((ContentItem*)(index.parent().internalPointer()))->setToInstall(false); } else { int i = 0; bool b = true; while(index.sibling(i, 0).isValid()) { b = data(index.sibling(i++, 0), role).toBool(); if(!b) { break; } } ((ContentItem*)(index.parent().internalPointer()))->setToInstall(b); } } emit dataChanged(index, index); emit dataChanged(index.parent(), index.parent()); return true; } return false; } Qt::ItemFlags CDItemModel::flags(const QModelIndex &index) const { if (!index.isValid()) { return 0; } return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable; } QVariant CDItemModel::headerData(int section, Qt::Orientation orientation, int role) const { Q_UNUSED(section) Q_UNUSED(orientation) Q_UNUSED(role) return QVariant(); } QModelIndex CDItemModel::index(int row, int column, const QModelIndex &parent) const { if (!hasIndex(row, column, parent)) { return QModelIndex(); } ContentItem *parentItem; if (!parent.isValid()) { parentItem = rootItem_; } else { parentItem = static_cast(parent.internalPointer()); } ContentItem *childItem = parentItem->child(row); if (childItem) { return createIndex(row, column, childItem); } else { return QModelIndex(); } } QModelIndex CDItemModel::parent(const QModelIndex &index) const { if (!index.isValid()) { return QModelIndex(); } ContentItem *childItem = static_cast(index.internalPointer()); ContentItem *parentItem = childItem->parent(); if (parentItem == rootItem_) { return QModelIndex(); } return createIndex(parentItem->row(), 0, parentItem); } int CDItemModel::rowCount(const QModelIndex &parent) const { ContentItem *parentItem; if (parent.column() > 0) { return 0; } if (!parent.isValid()) { parentItem = rootItem_; } else { parentItem = static_cast(parent.internalPointer()); } return parentItem->childCount(); } void CDItemModel::addRecord(QString group, QString name, QString url, QString html) { ContentItem *parent = rootItem_; QStringList subGroups = group.split("/"); while(!subGroups.isEmpty()) { ContentItem *newParent = NULL; for(int i = parent->childCount() - 1; i >= 0; i--) { if(parent->child(i)->name() == subGroups.first()) { newParent = parent->child(i); break; } } if(newParent == NULL) { newParent = new ContentItem(subGroups.first(), parent); parent->appendChild(newParent); } parent = newParent; subGroups.removeFirst(); } ContentItem *item = new ContentItem(name, parent); item->setGroup(group); item->setUrl(url); item->setHtml(html); parent->appendChild(item); } QList CDItemModel::getToInstall() const { QList listItems; QModelIndex index = this->index(0, 0); while(index.isValid()) { if(index.child(0, 0).isValid()) { // Descent index = index.child(0, 0); } else { while(index.isValid()) { ContentItem *item = (ContentItem*)index.internalPointer(); if(item->toInstall()) { listItems << item; } if(!index.sibling(index.row() + 1, 0).isValid()) { index = index.parent(); break; } index = index.sibling(index.row() + 1, 0); } while(index.parent().isValid() && !index.sibling(index.row() + 1, 0).isValid()) { index = index.parent(); } index = index.sibling(index.row() + 1, 0); } } return listItems; } void CDItemModel::setDataDir(const QString &dataDir) { dataDir_ = dataDir; } void CDItemModel::setResourcesDir(const QString &resourcesDir) { resourcesDir_ = resourcesDir; } void CDItemModel::update() { QModelIndex index = this->index(0, 0); while(index.isValid()) { if(index.child(0, 0).isValid()) { // Descent index = index.child(0, 0); } else { bool allInstalled = true; while(true) { ContentItem *item = (ContentItem*)index.internalPointer(); QString filename = item->url().section("/", -1); QString fullFileNameH = QDir::toNativeSeparators(QString("%1/%2/%3"). arg(dataDir_). arg(item->group()). arg(filename)); QString fullFileNameR = QDir::toNativeSeparators(QString("%1/%2/%3"). arg(resourcesDir_). arg(item->group()). arg(filename)); if(QFile::exists(fullFileNameH) || QFile::exists(fullFileNameR)) { item->setToInstall(false); item->setIsInstalled(true); emit dataChanged(index, index); } else { allInstalled = false; } if(!index.sibling(index.row() + 1, 0).isValid()) { index = index.parent(); if(allInstalled) { item->parent()->setIsInstalled(true); emit dataChanged(index, index); } break; } index = index.sibling(index.row() + 1, 0); } while(index.parent().isValid() && !index.sibling(index.row() + 1, 0).isValid()) { index = index.parent(); } index = index.sibling(index.row() + 1, 0); } } } plugins-1.5/generic/contentdownloaderplugin/cditemmodel.h000066400000000000000000000036471336777360500241160ustar00rootroot00000000000000/* * cditemmodel.h - model for contents tree * Copyright (C) 2010 Ivan Romanov * * 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. */ #ifndef CDITEMMODEL_H #define CDITEMMODEL_H #include #include "contentitem.h" class CDItemModel : public QAbstractItemModel { Q_OBJECT public: CDItemModel(QObject *parent = NULL); ~CDItemModel(); QVariant data(const QModelIndex &index, int role) const; bool setData(const QModelIndex &index, const QVariant &value, int role); Qt::ItemFlags flags(const QModelIndex &index) const; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const; QModelIndex parent(const QModelIndex &index) const; int rowCount(const QModelIndex &parent = QModelIndex()) const; int columnCount(const QModelIndex &parent = QModelIndex()) const; void addRecord(QString group, QString name, QString url, QString html); QList getToInstall() const; void setDataDir(const QString &dataDir); void setResourcesDir(const QString &resourcesDir); void update(); private: ContentItem *rootItem_; QString dataDir_; QString resourcesDir_; }; #endif // CDITEMMODEL_H plugins-1.5/generic/contentdownloaderplugin/changelog.txt000066400000000000000000000060301336777360500241340ustar00rootroot000000000000002014-05-02 zet v0.2.5 * https://raw.githubusercontent.com/psi-plus/contentdownloader/master/content.list 2013-08-13 taurus v0.2.4 + Иконка плагина 2013-07-31 taurus v0.2.3 * кликабельные ссылки в описании набора иконок 2012-02-09 v0.2.2 * ещё поправка после переезда 2012-01-24 zet v0.2.1 * проект переехал с http://psi-dev.googlecode.com/svn/trunk/ на https://github.com/psi-plus/ 2011-05-27 v0.1.11 * пересобрано с новым appHomeDir 2010-12-22 v0.1.10 * добавлена кнопка загрузки списка ресурсов 2010-12-07 v0.1.9 * теперь также учитываются ресурсы в системной папке 2010-12-05 v0.1.8 * корректное отображение русских символов v0.1.7 * настройки прокси берутся из настроек приложения 2010-10-21 v0.1.6 * файл списка проверяется из основного репозитория 2010-09-29 v0.1.5 * кнопка Download and Install теперь неактивна, если ничего не выбрано * поправлено отображение описаний (раньше необходимо было выбирать мышкой) 2010-09-19 v0.1.4 * исправлено скачивание ресурсов в windows 2010-09-11 v0.1.3 * файл списка перемещён на psi-plus.com * в html могут быть относительные адреса картинок 2010-09-11 v0.1.2 * обновлены ссылки на wiki 2010-09-10 v0.1.1 * прокси работает на Linux (для сборки необходима библиотека libproxy) 2010-09-08 v0.1.0 + первый релиз + добавлена поддержка прокси 2010-09-08 v0.0.8 - убрана привязка к webkit * QWebView заменён на QTextEdit 2010-09-07 v0.0.7 * исправлено падение Psi+ при отключении плагина 2010-09-07 v0.0.6 + добавлено кеширование информации из интернета 2010-09-05 v0.0.5 + добавлено отображение странички со скриншотом и описанием иконпака 2010-09-05 v0.0.4 * исправлено сворачивание списка после загрузки + дерево теперь имеет узел iconsets 2010-09-05 v0.0.3 + добавлен changelog * плагин теперь работает * прогресс-бар скрывается когда не нужен * прогресс-бар показывает имя загружаемого файла + в файл списка добавлены иконки группы roster * теперь группы называются так же, как и папки в iconsets - убрано поле Name - убрана вкладка Proxy plugins-1.5/generic/contentdownloaderplugin/contentdownloader.cpp000066400000000000000000000060241336777360500257040ustar00rootroot00000000000000/* * contentdownloader.cpp - plugin interface * Copyright (C) 2010 Ivan Romanov * * 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 #include #include #include #include "contentdownloader.h" #include "form.h" #ifndef HAVE_QT5 Q_EXPORT_PLUGIN(ContentDownloader); #endif ContentDownloader::ContentDownloader() : enabled(false) , form_(NULL) { } ContentDownloader::~ContentDownloader() { } // PsiPlugin QString ContentDownloader::name() const { return "Content Downloader Plugin"; } QString ContentDownloader::shortName() const { return "cdownloader"; } QString ContentDownloader::version() const { return "0.2.5"; } QWidget *ContentDownloader::options() { if ( !enabled ) { return 0; } if ( !appInfoHost || !psiOptions ) { return 0; } Proxy psiProxy = appInfoHost->getProxyFor(name()); QNetworkProxy::ProxyType type; if(psiProxy.type == "socks") { type = QNetworkProxy::Socks5Proxy; } else { type = QNetworkProxy::HttpProxy; } QNetworkProxy proxy(type, psiProxy.host, psiProxy.port, psiProxy.user, psiProxy.pass); form_ = new Form(); form_->setDataDir(appInfoHost->appHomeDir(ApplicationInfoAccessingHost::DataLocation)); form_->setCacheDir(appInfoHost->appHomeDir(ApplicationInfoAccessingHost::CacheLocation)); form_->setResourcesDir(appInfoHost->appResourcesDir()); form_->setPsiOption(psiOptions); form_->setProxy(proxy); return qobject_cast(form_); } bool ContentDownloader::enable() { if ( psiOptions ) { enabled = true; } appInfoHost->getProxyFor(name()); return enabled; } bool ContentDownloader::disable() { enabled = false; return true; } void ContentDownloader::applyOptions() { } void ContentDownloader::restoreOptions() { } QPixmap ContentDownloader::icon() const { return QPixmap(":/icons/download.png"); } void ContentDownloader::setOptionAccessingHost(OptionAccessingHost *host) { psiOptions = host; } void ContentDownloader::optionChanged(const QString &option) { Q_UNUSED(option); } void ContentDownloader::setApplicationInfoAccessingHost(ApplicationInfoAccessingHost *host) { appInfoHost = host; } QString ContentDownloader::pluginInfo() { return tr("Author: ") + "Ivan Romanov\n" + tr("e-mail: ") + "drizt@land.ru\n\n" + tr("This plugin is designed to make it easy to download and install iconsets and other resources for Psi+."); } plugins-1.5/generic/contentdownloaderplugin/contentdownloader.h000066400000000000000000000042001336777360500253430ustar00rootroot00000000000000/* * contentdownloader.h - plugin interface * Copyright (C) 2010 Ivan Romanov * * 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. */ #ifndef CONTENTDOWLOADER_H #define CONTENTDOWLOADER_H #include #include "psiplugin.h" #include "applicationinfoaccessor.h" #include "applicationinfoaccessinghost.h" #include "optionaccessor.h" #include "optionaccessinghost.h" #include "plugininfoprovider.h" #include "cditemmodel.h" class Form; class ContentDownloader : public QObject, public PsiPlugin, public OptionAccessor, public ApplicationInfoAccessor , public PluginInfoProvider { Q_OBJECT #ifdef HAVE_QT5 Q_PLUGIN_METADATA(IID "com.psi-plus.ContentDownloader") #endif Q_INTERFACES(PsiPlugin OptionAccessor ApplicationInfoAccessor PluginInfoProvider) public: ContentDownloader(); ~ContentDownloader(); // from PsiPlugin QString name() const; QString shortName() const; QString version() const; QWidget *options(); bool enable(); bool disable(); void applyOptions(); void restoreOptions(); QPixmap icon() const; // from OptionAccessor void setOptionAccessingHost(OptionAccessingHost* host); void optionChanged(const QString& option); // from ApplicationInfoAccessor void setApplicationInfoAccessingHost(ApplicationInfoAccessingHost *host); // from PluginInfoProvider QString pluginInfo(); private: bool enabled; OptionAccessingHost *psiOptions; ApplicationInfoAccessingHost *appInfoHost; QString texto; Form *form_; }; #endif // CONTENTDOWLOADER_H plugins-1.5/generic/contentdownloaderplugin/contentdownloaderplugin.pro000066400000000000000000000006171336777360500271430ustar00rootroot00000000000000isEmpty(PSISDK) { include(../../psiplugin.pri) } else { include($$PSISDK/plugins/psiplugin.pri) } QT += network xml SOURCES += contentdownloader.cpp \ cditemmodel.cpp \ form.cpp \ contentitem.cpp HEADERS += contentdownloader.h \ cditemmodel.h \ form.h \ contentitem.h RESOURCES += resources.qrc FORMS += form.ui OBJECTS_DIR = build MOC_DIR = build UI_DIR = build plugins-1.5/generic/contentdownloaderplugin/contentitem.cpp000066400000000000000000000045111336777360500245030ustar00rootroot00000000000000/* * contentitem.cpp - item model for contents tree * Copyright (C) 2010 Ivan Romanov * * 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 #include #include "contentitem.h" ContentItem::ContentItem(const QString &name, ContentItem *parent) : parentItem_(parent) , name_(name) , url_("") , html_("") , toInstall_(false) , isInstalled_(false) { } ContentItem::~ContentItem() { qDeleteAll(childItems_); } void ContentItem::appendChild(ContentItem *item) { childItems_.append(item); } ContentItem *ContentItem::child(int row) { return childItems_.value(row); } int ContentItem::childCount() const { return childItems_.count(); } ContentItem *ContentItem::parent() { return parentItem_; } int ContentItem::row() const { if (parentItem_) { return parentItem_->childItems_.indexOf(const_cast(this)); } return 0; } QString ContentItem::group() const { return group_; } void ContentItem::setGroup(const QString &group) { group_ = group; } QString ContentItem::name() const { return name_; } void ContentItem::setName(const QString &name) { name_ = name; } QString ContentItem::url() const { return url_; } void ContentItem::setUrl(const QString &url) { url_ = url; } QString ContentItem::html() const { return html_; } void ContentItem::setHtml(const QString &html) { html_ = html; } bool ContentItem::toInstall() const { return toInstall_; } void ContentItem::setToInstall(bool b) { if(!isInstalled_) { toInstall_ = b; } } bool ContentItem::isInstalled() const { return isInstalled_; } void ContentItem::setIsInstalled(bool b) { isInstalled_ = b; toInstall_ = b ? false : toInstall_; } plugins-1.5/generic/contentdownloaderplugin/contentitem.h000066400000000000000000000032701336777360500241510ustar00rootroot00000000000000/* * contentitem.h - item model for contents tree * Copyright (C) 2010 Ivan Romanov * * 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. */ #ifndef CONTENTITEM_H #define CONTENTITEM_H #include #include #include class ContentItem { public: ContentItem(const QString &name, ContentItem *parent = NULL); ~ContentItem(); void appendChild(ContentItem *child); ContentItem* child(int row); int childCount() const; int row() const; ContentItem *parent(); QString group() const; void setGroup(const QString &name); QString name() const; void setName(const QString &name); QString url() const; void setUrl(const QString &url); QString html() const; void setHtml(const QString &html); bool toInstall() const; void setToInstall(bool b); bool isInstalled() const; void setIsInstalled(bool b); private: ContentItem *parentItem_; QList childItems_; QString group_; QString name_; QString url_; QString html_; bool toInstall_; bool isInstalled_; }; #endif plugins-1.5/generic/contentdownloaderplugin/download.png000066400000000000000000000023771336777360500237730ustar00rootroot00000000000000PNG  IHDR(-S pHYs  gAMA|Q cHRMz%u0`:o_FPLTE4/YQ3.̎՟1-yp@9iaA:xx~À1-+~+̋u|՞^\0-՚y50xpƻxpͫ>7.,ƻBF̩@BPPACZ\TU;4yw}QO[S2/NQ1y5Ԛ=6ǻ.,ldXQyv}ɉY\71SS`a1.wsyab,~+v}ު;<;<{zVT_b:2.,>7̎h`iaqh2y6F~K _ zzz{{{|||}}}~~~ѷztRNS?&IDATxbd``VҗC s004ϼ?c_\:7̟Zҿ~I (~gb b,~YO9k,j/=dgbgG W7o2c``!ϑALIk7.͏md? /,Xu-_"G8 #U ]=AgIENDB`plugins-1.5/generic/contentdownloaderplugin/form.cpp000066400000000000000000000260151336777360500231200ustar00rootroot00000000000000/* * form.cpp - options widget of Content Downloader Plugin * Copyright (C) 2010 Ivan Romanov * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include "form.h" #include "cditemmodel.h" #include "contentitem.h" #include "applicationinfoaccessinghost.h" #include "ui_form.h" #define LIST_URL "https://raw.githubusercontent.com/psi-plus/contentdownloader/master/content.list" Form::Form(QWidget *parent) : QWidget(parent) , ui(new Ui::Form) , listUrl_(LIST_URL) { ui->setupUi(this); ui->progressBar->hide(); nam_ = new QNetworkAccessManager(this); CDItemModel *model = new CDItemModel(this); ui->treeView->setModel(model); connect(ui->treeView->selectionModel(), SIGNAL(currentChanged(const QModelIndex&, const QModelIndex&)), SLOT(modelSelectionChanged(const QModelIndex&, const QModelIndex&))); connect(model, SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&)), SLOT(modelSelectedItem())); ui->widgetContent->hide(); } Form::~Form() { toDownload_.clear(); delete ui; } void Form::setDataDir(const QString &path) { dataDir_ = path; CDItemModel *model = qobject_cast(ui->treeView->model()); model->setDataDir(path); } void Form::setCacheDir(const QString &path) { // Create directory for caching if not exist tmpDir_ = QDir::toNativeSeparators(QString("%1/tmp-contentdownloader"). arg(path)); QDir dir(tmpDir_); if(!dir.exists()) { dir.mkpath("."); } // Setup disk cache QNetworkDiskCache *diskCache = new QNetworkDiskCache(this); diskCache->setCacheDirectory(dir.path()); nam_->setCache(diskCache); } void Form::setResourcesDir(const QString &path) { CDItemModel *model = qobject_cast(ui->treeView->model()); model->setResourcesDir(path); } void Form::setPsiOption(OptionAccessingHost *host) { psiOptions_ = host; } void Form::setProxy(const QNetworkProxy &proxy) { if(!proxy.hostName().isEmpty()) { nam_->setProxy(proxy); } } void Form::on_btnInstall_clicked() { startDownload(); } void Form::on_btnLoadList_clicked() { ui->btnLoadList->setEnabled(false); toDownload_.clear(); ui->btnInstall->setEnabled(false); QString url(LIST_URL); QNetworkRequest request(url); request.setRawHeader("User-Agent", "Content Downloader Plugin (Psi+)"); QNetworkReply *reply = nam_->get(request); // State of progress connect(reply, SIGNAL(downloadProgress(qint64, qint64)), SLOT(downloadContentListProgress(qint64, qint64))); // Content list have beign downloaded connect(reply, SIGNAL(finished()), SLOT(downloadContentListFinished())); ui->progressBar->show(); ui->progressBar->setFormat(url.section(QDir::separator(), -1) + " %v Kb (%p%)"); ui->progressBar->setMaximum(reply->size()); } void Form::changeEvent(QEvent *e) { QWidget::changeEvent(e); switch (e->type()) { case QEvent::LanguageChange: ui->retranslateUi(this); break; default: break; } } void Form::parseContentList(const QString &text) { CDItemModel *model = qobject_cast(ui->treeView->model()); int position = 0; QStringList list; QRegExp rx("\\[([^\\]]*)\\]([^\\[]*)"); while(position < text.length()) { position = rx.indexIn(text, position); if(position == -1) { break; } QString group; QString name; QString url; QString html; group = rx.cap(1); list = rx.cap(2).split("\n", QString::SkipEmptyParts); for(int i = list.size() - 1; i >= 0; i--) { QString left, right; left = list[i].section("=", 0, 0).trimmed(); right = list[i].section("=", 1, 1).trimmed(); if(left == "name") { name = right; } else if(left == "url") { url = right; } else if(left == "html") { html = right; } } if(name.isEmpty() || group.isEmpty()) { continue; } model->addRecord(group, name, url, html); position += rx.matchedLength(); } } void Form::downloadContentListProgress(qint64 bytesReceived, qint64 bytesTotal) { ui->progressBar->setMaximum(bytesTotal / 1024); ui->progressBar->setValue(bytesReceived / 1024); } void Form::downloadContentListFinished() { QNetworkReply *reply = qobject_cast(sender()); ui->progressBar->hide(); // Occurs erros if(reply->error() != QNetworkReply::NoError) { qDebug() << "Content Downloader Plugin:" << reply->errorString(); ui->progressBar->hide(); ui->btnInstall->setEnabled(false); reply->close(); return; } // No error ui->widgetContent->show(); ui->widgetLoadList->hide(); parseContentList(reply->readAll()); reply->close(); ui->btnInstall->setEnabled(false); CDItemModel *model = qobject_cast(ui->treeView->model()); model->update(); ui->treeView->reset(); } void Form::downloadContentProgress(qint64 bytesReceived, qint64 bytesTotal) { ui->progressBar->setMaximum(bytesTotal / 1024); ui->progressBar->setValue(bytesReceived / 1024); } void Form::downloadContentFinished() { QNetworkReply *reply = qobject_cast(sender()); // Occurs erros if(reply->error() != QNetworkReply::NoError) { qDebug() << "Content Downloader Plugin:" << reply->errorString(); ui->progressBar->hide(); reply->close(); toDownload_.removeFirst(); startDownload(); return; } // No error ContentItem *item = toDownload_.first(); QString filename = item->url().section("/", -1); toDownload_.removeFirst(); if(filename.endsWith(".jisp")) { QDir dir(QDir::toNativeSeparators(QString("%1/%2"). arg(dataDir_). arg(item->group()))); if(!dir.exists()) { dir.mkpath("."); } QString fullFileName = QDir::toNativeSeparators(QString("%1/%2"). arg(dir.absolutePath()). arg(filename)); QFile fd(fullFileName); if(!fd.open(QIODevice::WriteOnly) || fd.write(reply->readAll()) == -1) { qDebug() << "Content Downloader Plugin:" << fd.errorString() << fullFileName; } fd.close(); CDItemModel *model = qobject_cast(ui->treeView->model()); model->update(); } reply->close(); startDownload(); } void Form::downloadHtmlFinished() { QNetworkReply *reply = qobject_cast(sender()); // Occurs erros if(reply->error() != QNetworkReply::NoError) { qDebug() << "Content Downloader Plugin:" << reply->errorString(); reply->close(); return; } if(reply == replyLastHtml_) { QString html = QString::fromUtf8(reply->readAll()); QDomDocument doc("html"); QString errorMsg; int errorLine, errorColumn; if(doc.setContent(html, &errorMsg, &errorLine, &errorColumn)) { QString imgsdir = tmpDir_ + QDir::separator() + "imgs"; QDir dir(imgsdir); QFileSystemModel *model = new QFileSystemModel(); if(model->index(dir.path()).isValid()) { model->remove(model->index(dir.path())); } delete model; dir.mkpath("."); QDomNodeList imgs = doc.elementsByTagName("img"); QDomNode node; QVector text; for(int i = 0; i < imgs.size(); i++) { QDomElement el = imgs.at(i).toElement(); QString urlStr(el.attribute("src")); if(!urlStr.isEmpty() && !(urlStr.startsWith("http://") || urlStr.startsWith("http://"))) { urlStr = reply->url().toString().section('/', 0, -2) + '/' + urlStr; } QUrl url(urlStr); if(!url.isValid()) { continue; } QString filename = url.toString().section("/", -1); el.setAttribute("src", imgsdir + QDir::separator() + filename); QNetworkRequest request(url); request.setRawHeader("User-Agent", "Content Downloader Plugin (Psi+)"); request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache); QNetworkReply *reply = nam_->get(request); connect(reply, SIGNAL(finished()), SLOT(downloadImgFinished())); } html = doc.toString(); } else { // Error occurs in parse of yandex.xml qDebug() << "Content Downloader Plugin:" << " line: " << errorLine << ", column: " << errorColumn; } ui->textEdit->setHtml(html); } reply->close(); } void Form::downloadImgFinished() { QNetworkReply *reply = qobject_cast(sender()); // Occurs erros if(reply->error() != QNetworkReply::NoError) { qDebug() << "Content Downloader Plugin:" << reply->errorString(); reply->close(); return; } QString filename = reply->url().toString().section("/", -1); QString fullFileName = QDir::toNativeSeparators(QString("%1/imgs/%2"). arg(tmpDir_). arg(filename)); QFile fd(fullFileName); if(!fd.open(QIODevice::WriteOnly) || fd.write(reply->readAll()) == -1) { qDebug() << "Content Downloader Plugin:" << fd.errorString(); } ui->textEdit->setHtml(ui->textEdit->toHtml()); } void Form::startDownload() { if(toDownload_.isEmpty()) { ui->btnInstall->setEnabled(true); ui->progressBar->hide(); return; } ui->btnInstall->setEnabled(false); QNetworkRequest request; request.setUrl(QUrl(toDownload_.first()->url())); request.setRawHeader("User-Agent", "Content Downloader Plugin (Psi+)"); QNetworkReply *reply = nam_->get(request); // State of progress connect(reply, SIGNAL(downloadProgress(qint64, qint64)), SLOT(downloadContentProgress(qint64, qint64))); // Content list have beign downloaded connect(reply, SIGNAL(finished()), SLOT(downloadContentFinished())); ui->progressBar->show(); ui->progressBar->setFormat(toDownload_.first()->url().section("/", -1) + " %v Kb (%p%)"); ui->progressBar->setMaximum(reply->size()); } void Form::modelSelectionChanged(const QModelIndex ¤t, const QModelIndex &previous) { Q_UNUSED(previous); ContentItem *item = (ContentItem*)current.internalPointer(); ui->textEdit->setHtml(""); QUrl url(item->html()); if(url.isValid()) { QNetworkRequest request(url); request.setRawHeader("User-Agent", "Content Downloader Plugin (Psi+)"); request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache); replyLastHtml_ = nam_->get(request); // Content list have beign downloaded connect(replyLastHtml_, SIGNAL(finished()), SLOT(downloadHtmlFinished())); } } void Form::modelSelectedItem() { CDItemModel *model = qobject_cast(ui->treeView->model()); toDownload_ = model->getToInstall(); if(toDownload_.isEmpty()) { ui->btnInstall->setEnabled(false); } else { ui->btnInstall->setEnabled(true); } } plugins-1.5/generic/contentdownloaderplugin/form.h000066400000000000000000000043151336777360500225640ustar00rootroot00000000000000/* * form.h - options widget of Content Downloader Plugin * Copyright (C) 2010 Ivan Romanov * * 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. */ #ifndef FORM_H #define FORM_H #include #include #include class QNetworkAccessManager; class ContentItem; class OptionAccessingHost; class QNetworkReply; class QAuthenticator; class QDialog; namespace Ui { class Form; } class Form : public QWidget { Q_OBJECT public: Form(QWidget *parent = 0); ~Form(); void setDataDir(const QString &path); void setCacheDir(const QString &path); void setResourcesDir(const QString &path); void setPsiOption(OptionAccessingHost *host); void setProxy(const QNetworkProxy &proxy); public slots: void on_btnInstall_clicked(); void on_btnLoadList_clicked(); protected: void changeEvent(QEvent *e); private: void parseContentList(const QString &text); void startDownload(); Ui::Form *ui; QNetworkAccessManager *nam_; QString dataDir_; QString tmpDir_; QString listUrl_; QList toDownload_; OptionAccessingHost *psiOptions_; QNetworkReply *replyLastHtml_; private slots: void downloadContentListProgress(qint64 bytesReceived, qint64 bytesTotal); void downloadContentListFinished(); void downloadContentProgress(qint64 bytesReceived, qint64 bytesTotal); void downloadContentFinished(); void downloadHtmlFinished(); void downloadImgFinished(); void modelSelectionChanged(const QModelIndex ¤t, const QModelIndex &previous); void modelSelectedItem(); }; #endif // FORM_H plugins-1.5/generic/contentdownloaderplugin/form.ui000066400000000000000000000140411336777360500227470ustar00rootroot00000000000000 Form 0 0 568 448 0 0 Proxy Authentication Required 0 0 0 0 0 Load Content List Qt::Vertical 120 64 Qt::Horizontal 40 20 0 0 0 0 Qt::Horizontal 9 0 0 0 false false Download and Install 1 0 true <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Liberation Serif'; font-size:12pt; font-weight:400; font-style:normal;"> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> Qt::TextBrowserInteraction true Qt::AlignCenter true false 0 <a href="http://psi-plus.com/wiki/plugins#content_downloader_plugin">Wiki (Online)</a> true plugins-1.5/generic/contentdownloaderplugin/iconshot.sh000077500000000000000000000011251336777360500236310ustar00rootroot00000000000000#!/bin/sh iconslimit=63 # max number of icons on screenshot die() { echo "$@"; exit 1; } case "$1" in *.jisp) iconset="$1"; ;; *) die "First argument has to be jisp file"; ;; esac; dir=$(mktemp -d); unzip "$iconset" -d $dir &>/dev/null imgdir="${dir}/$(basename "$iconset" .jisp)" # xmlstarlet IFS=$'\n' icons=($(xml sel -t -v "//icondef/icon/object/text()" $imgdir/icondef.xml | sed 's|gif$|gif[0]|' | head -n $iconslimit)) unset IFS # imagemagick cd $imgdir; magick montage -background '#ffffff00' -geometry +1+1 "${icons[@]}" $dir/screenshot.png rm -rf $imgdir echo $dir/screenshot.png plugins-1.5/generic/contentdownloaderplugin/resources.qrc000066400000000000000000000001401336777360500241610ustar00rootroot00000000000000 download.png plugins-1.5/generic/contentdownloaderplugin/test.html000066400000000000000000000012121336777360500233060ustar00rootroot00000000000000

Test html

plugins-1.5/generic/enummessagesplugin/000077500000000000000000000000001336777360500204105ustar00rootroot00000000000000plugins-1.5/generic/enummessagesplugin/CMakeLists.txt000066400000000000000000000025611336777360500231540ustar00rootroot00000000000000unset(_HDRS) unset(_UIS) unset(_SRCS) unset(_RSCS) unset(PLUGIN) set( PLUGIN enummessagesplugin ) project(${PLUGIN}) cmake_minimum_required(VERSION 3.1.0) set( CMAKE_AUTOMOC TRUE ) IF( NOT WIN32 ) set( LIB_SUFFIX "" CACHE STRING "Define suffix of directory name (32/64)" ) set( PLUGINS_PATH "lib${LIB_SUFFIX}/psi-plus/plugins" CACHE STRING "Install suffix for plugins" ) ELSE() set( PLUGINS_PATH "psi-plus/plugins" CACHE STRING "Install suffix for plugins" ) ENDIF() add_definitions( -DQT_PLUGIN -DHAVE_QT5 ) include_directories( ${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ../../include . ) set( _HDRS ${PLUGIN}.h defines.h ) set( _SRCS ${PLUGIN}.cpp ) set( _UIS options.ui ) set( _RSCS resources.qrc ) find_package( Qt5 COMPONENTS Widgets Xml REQUIRED ) set(QT_DEPLIBS Qt5::Widgets Qt5::Xml ) qt5_wrap_ui(UIS ${_UIS}) qt5_add_resources(RSCS ${_RSCS}) add_library( ${PLUGIN} MODULE ${_SRCS} defines.h ${UIS} ${RSCS} ) target_link_libraries( ${PLUGIN} ${QT_DEPLIBS} ) if( UNIX AND NOT( APPLE OR CYGWIN ) ) install( TARGETS ${PLUGIN} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} ) endif() if( WIN32 ) install( TARGETS ${PLUGIN} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} ) endif() plugins-1.5/generic/enummessagesplugin/changelog.txt000066400000000000000000000002301336777360500230730ustar00rootroot0000000000000017.02.16 ver 0.0.03 + add tollbar button + add settings 16.02.16 ver 0.0.02 * use new plugin interface 15.02.16 ver 0.0.01 *initial version plugins-1.5/generic/enummessagesplugin/defines.h000066400000000000000000000020771336777360500222040ustar00rootroot00000000000000/* * defines.h - plugin * Copyright (C) 2016 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef DEFINES_H #define DEFINES_H #define constVersion "0.0.03" #define constPluginName "Enum Messages Plugin" #define constEnumsFileName "/enum_messages_jids" #define constInColor "in_color" #define constOutColor "out_color" #define constDefaultAction "default_action" #endif // DEFINES_H plugins-1.5/generic/enummessagesplugin/em.png000066400000000000000000000005221336777360500215160ustar00rootroot00000000000000PNG  IHDRaIDATx^P=NP\~Z `($ !zg7!h-ņ|jdvgOX8/iBQ Nxض uGFUUwa~l0 9N}׿4)QI08Du]iͲ Oxq,ˁ pſYe˲0 8XI&K3f{m§SEQ\:fms7\@4l]Ie4 A<}<|U( >  pNP#JEIENDB`plugins-1.5/generic/enummessagesplugin/enummessagesplugin.cpp000066400000000000000000000263521336777360500250370ustar00rootroot00000000000000/* * Copyright (C) 2016 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include #include #include #include #include #include #include //#include #include "enummessagesplugin.h" #include "optionaccessinghost.h" #include "activetabaccessinghost.h" #include "applicationinfoaccessinghost.h" #include "psiaccountcontrollinghost.h" #include "defines.h" static const char* propAcc = "em_account"; static const char* propJid = "em_jid"; static const QString emIdName = "psi_em_id"; static const QString htmlimNS = "http://www.w3.org/1999/xhtml"; static const QString xhtmlProtoNS = "http://jabber.org/protocol/xhtml-im"; EnumMessagesPlugin::EnumMessagesPlugin() : enabled(false) , _psiOptions(0) , _activeTab(0) , _applicationInfo(0) , _accContrller(0) , _inColor(QColor(Qt::red)) , _outColor(QColor(Qt::green)) , _defaultAction(true) , _options(0) { } QString EnumMessagesPlugin::name() const { return constPluginName; } QString EnumMessagesPlugin::shortName() const { return "enummessages"; } QString EnumMessagesPlugin::version() const { return constVersion; } QWidget* EnumMessagesPlugin::options() { if(!enabled) { return 0; } _options = new QWidget(); _ui.setupUi(_options); _ui.hack->hide(); connect(_ui.tb_inColor, SIGNAL(clicked()), SLOT(getColor())); connect(_ui.tb_outColor, SIGNAL(clicked()), SLOT(getColor())); restoreOptions(); return _options; } bool EnumMessagesPlugin::enable() { enabled = true; QFile f(_applicationInfo->appCurrentProfileDir(ApplicationInfoAccessingHost::DataLocation) + QString(constEnumsFileName)); if(f.exists() && f.open(QFile::ReadOnly)) { QDataStream s(&f); s >>_enumsIncomming >> _jidActions; } _inColor = _psiOptions->getPluginOption(constInColor, _inColor).value(); _outColor = _psiOptions->getPluginOption(constOutColor, _outColor).value(); _defaultAction = _psiOptions->getPluginOption(constDefaultAction, _defaultAction).toBool(); return true; } bool EnumMessagesPlugin::disable() { enabled = false; QFile f(_applicationInfo->appCurrentProfileDir(ApplicationInfoAccessingHost::DataLocation) + QString(constEnumsFileName)); if(f.open(QFile::WriteOnly | QFile::Truncate)) { QDataStream s(&f); s << _enumsIncomming << _jidActions; } return true; } void EnumMessagesPlugin::applyOptions() { _defaultAction = _ui.rb_enabled->isChecked(); _inColor = _ui.tb_inColor->property("psi_color").value(); _outColor = _ui.tb_outColor->property("psi_color").value(); _psiOptions->setPluginOption(constInColor, _inColor); _psiOptions->setPluginOption(constOutColor, _outColor); _psiOptions->setPluginOption(constDefaultAction, _defaultAction); } void EnumMessagesPlugin::restoreOptions() { if (_defaultAction) { _ui.rb_enabled->setChecked(true); } else { _ui.rb_disabled->setChecked(true); } _ui.tb_inColor->setStyleSheet(QString("background-color: %1;").arg(_inColor.name())); _ui.tb_inColor->setProperty("psi_color", _inColor); _ui.tb_outColor->setStyleSheet(QString("background-color: %1;").arg(_outColor.name())); _ui.tb_outColor->setProperty("psi_color", _outColor); } QPixmap EnumMessagesPlugin::icon() const { return QPixmap(":/icons/em.png"); } void EnumMessagesPlugin::setOptionAccessingHost(OptionAccessingHost* host) { _psiOptions = host; } void EnumMessagesPlugin::setActiveTabAccessingHost(ActiveTabAccessingHost* host) { _activeTab = host; } void EnumMessagesPlugin::setApplicationInfoAccessingHost(ApplicationInfoAccessingHost* host) { _applicationInfo = host; } void EnumMessagesPlugin::setPsiAccountControllingHost(PsiAccountControllingHost *host) { _accContrller = host; } bool EnumMessagesPlugin::incomingStanza(int account, const QDomElement& stanza) { if(!enabled) return false; if (stanza.tagName() == "message" ) { QString type = stanza.attribute("type"); if(type != "chat") return false; if(stanza.firstChildElement("body").isNull()) return false; if (!stanza.hasAttribute(emIdName)) return false; const QString jid(stanza.attribute("from").split('/').first()); if(!isEnabledFor(account, jid)) return false; quint16 num = stanza.attribute(emIdName,"1").toUShort(); quint16 myNum = 0; JidEnums jids; if (_enumsIncomming.contains(account)) { jids = _enumsIncomming.value(account); if(jids.contains(jid)) { myNum = jids.value(jid); } } if (num > myNum+1) { QString missed; while (num > myNum+1) { missed += QString("%1 ").arg(numToFormatedStr(myNum+1)); ++myNum; } _accContrller->appendSysMsg(account, jid, tr("Missed messages: %1").arg(missed)); } jids.insert(jid, num); _enumsIncomming.insert(account, jids); QDomDocument doc = stanza.ownerDocument(); QDomElement& nonConst = const_cast(stanza); addMessageNum(&doc, &nonConst, num, _inColor); } return false; } bool EnumMessagesPlugin::outgoingStanza(int account, QDomElement &stanza) { if(!enabled) return false; if (stanza.tagName() == "message" ) { QString type = stanza.attribute("type"); if(type != "chat") return false; if(stanza.firstChildElement("body").isNull()) return false; const QString jid(stanza.attribute("to").split('/').first()); if(!isEnabledFor(account, jid)) return false; quint16 num = 1; JidEnums jids; if (_enumsOutgoing.contains(account)) { jids = _enumsOutgoing.value(account); if(jids.contains(jid)) { num = jids.value(jid); ++num; } } jids.insert(jid, num); _enumsOutgoing.insert(account, jids); stanza.setAttribute(emIdName, num); } return false; } QAction *EnumMessagesPlugin::getAction(QObject *parent, int account, const QString &contact) { QAction* act = new QAction(icon(), tr("Enum Messages"), parent); act->setCheckable(true); const QString jid = contact.split("/").first(); act->setProperty("account", account); act->setProperty("contact", jid); connect(act, SIGNAL(triggered(bool)), SLOT(onActionActivated(bool))); act->setChecked(_defaultAction); if(_jidActions.contains(account)) { JidActions a = _jidActions.value(account); if(a.contains(jid)) { act->setChecked(a.value(jid)); } } return act; } void EnumMessagesPlugin::setupChatTab(QWidget* tab, int account, const QString &contact) { tab->setProperty(propAcc, account); tab->setProperty(propJid, contact); connect(tab, SIGNAL(destroyed()), SLOT(removeWidget())); } bool EnumMessagesPlugin::appendingChatMessage(int account, const QString &contact, QString &body, QDomElement &html, bool local) { if(!enabled || !local) return false; if(body.isEmpty()) return false; const QString jid(contact.split('/').first()); if(!isEnabledFor(account, jid)) return false; quint16 num = 0; JidEnums jids; if (_enumsOutgoing.contains(account)) { jids = _enumsOutgoing.value(account); if(jids.contains(jid)) { num = jids.value(jid); } } if (num == 0) return false; QDomNode bodyNode; QDomDocument doc = html.ownerDocument(); // QString s; // QTextStream str(&s, QIODevice::WriteOnly); // html.save(str, 2); // qDebug() << s; if(html.isNull()) { html = doc.createElement("body"); html.setAttribute("xmlns", htmlimNS); doc.appendChild(html); } else { bodyNode = html.firstChild(); } if(bodyNode.isNull()) { nl2br(&html, &doc, body); } QDomElement msgNum = doc.createElement("span"); msgNum.setAttribute("style", "color: " + _outColor.name()); msgNum.appendChild(doc.createTextNode(QString("%1 ").arg(numToFormatedStr(num)))); QDomNode n = html.firstChild(); html.insertBefore(msgNum,n); return false; } void EnumMessagesPlugin::removeWidget() { QWidget* w = static_cast(sender()); int account = w->property(propAcc).toInt(); QString jid = w->property(propJid).toString(); if(_enumsOutgoing.contains(account)) { JidEnums jids = _enumsOutgoing.value(account); if(jids.contains(jid.split('/').first())) { jids.remove(jid); _enumsOutgoing[account] = jids; } } } void EnumMessagesPlugin::getColor() { QToolButton *button = static_cast(sender()); QColor c(button->property("psi_color").value()); c = QColorDialog::getColor(c); if(c.isValid()) { button->setProperty("psi_color", c); button->setStyleSheet(QString("background-color: %1").arg(c.name())); //HACK _ui.hack->toggle(); } } void EnumMessagesPlugin::onActionActivated(bool checked) { QAction* act = static_cast(sender()); const int account = act->property("account").toInt(); const QString jid = act->property("contact").toString(); JidActions acts; if(_jidActions.contains(account)) { acts = _jidActions.value(account); } acts[jid] = checked; _jidActions[account] = acts; } void EnumMessagesPlugin::addMessageNum(QDomDocument *doc, QDomElement *stanza, quint16 num, const QColor& color) { bool appendBody = false; QDomElement body; QDomElement element = stanza->firstChildElement("html"); if(element.isNull()) { element = doc->createElement("html"); element.setAttribute("xmlns", xhtmlProtoNS); } else { body = element.firstChildElement("body"); } if(body.isNull()) { body = doc->createElement("body"); body.setAttribute("xmlns", htmlimNS); appendBody = true; } QDomElement msgNum = doc->createElement("span"); msgNum.setAttribute("style", "color: " + color.name()); msgNum.appendChild(doc->createTextNode(QString("%1 ").arg(numToFormatedStr(num)))); if(appendBody) { body.appendChild(msgNum); nl2br(&body, doc, stanza->firstChildElement("body").text()); } else { QDomNode n = body.firstChild(); body.insertBefore(msgNum,n); } element.appendChild(body); stanza->appendChild(element); } QString EnumMessagesPlugin::numToFormatedStr(int number) { return QString("%1").arg(number, 5, 10, QChar('0')); } void EnumMessagesPlugin::nl2br(QDomElement *body, QDomDocument *doc, const QString &msg) { foreach (const QString& str, msg.split("\n")) { body->appendChild(doc->createTextNode(str)); body->appendChild(doc->createElement("br")); } body->removeChild(body->lastChild()); } bool EnumMessagesPlugin::isEnabledFor(int account, const QString &jid) const { bool res = _defaultAction; if(_jidActions.contains(account)) { JidActions acts = _jidActions.value(account); if(acts.contains(jid)) { res = acts.value(jid); } } return res; } QString EnumMessagesPlugin::pluginInfo() { return tr("Authors: ") + "Dealer_WeARE\n\n" + tr("The plugin is designed to enumerate messages, adding the messages numbers in chat logs " "and notification of missed messages. \n" "Supports per contact on / off message enumeration via the buttons on the chats toolbar."); } #ifndef HAVE_QT5 Q_EXPORT_PLUGIN(EnumMessagesPlugin) #endif plugins-1.5/generic/enummessagesplugin/enummessagesplugin.h000066400000000000000000000077011336777360500245010ustar00rootroot00000000000000/* * Copyright (C) 2016 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef ENUMMESSAGESPLUGIN_H #define ENUMMESSAGESPLUGIN_H #include "psiplugin.h" #include "stanzafilter.h" #include "optionaccessor.h" #include "activetabaccessor.h" #include "plugininfoprovider.h" #include "chattabaccessor.h" #include "applicationinfoaccessor.h" #include "psiaccountcontroller.h" #include "toolbariconaccessor.h" #include "ui_options.h" #include #include class OptionAccessingHost; class ActiveTabAccessingHost; class ApplicationInfoAccessingHost; class QDomDocument; class EnumMessagesPlugin : public QObject, public PsiPlugin, public OptionAccessor, public ActiveTabAccessor, public StanzaFilter, public ApplicationInfoAccessor, public PluginInfoProvider, public ChatTabAccessor, public PsiAccountController, public ToolbarIconAccessor { Q_OBJECT #ifdef HAVE_QT5 Q_PLUGIN_METADATA(IID "com.psi-plus.EnumMessagesPlugin") #endif Q_INTERFACES(PsiPlugin OptionAccessor ActiveTabAccessor StanzaFilter ApplicationInfoAccessor PluginInfoProvider ChatTabAccessor PsiAccountController ToolbarIconAccessor) public: EnumMessagesPlugin(); virtual QString name() const; virtual QString shortName() const; virtual QString version() const; virtual QWidget* options(); virtual bool enable(); virtual bool disable(); virtual void applyOptions(); virtual void restoreOptions(); virtual QPixmap icon() const; virtual void setOptionAccessingHost(OptionAccessingHost* host); virtual void optionChanged(const QString& ) {} virtual void setActiveTabAccessingHost(ActiveTabAccessingHost* host); virtual void setApplicationInfoAccessingHost(ApplicationInfoAccessingHost* host); virtual void setPsiAccountControllingHost(PsiAccountControllingHost* host); virtual QString pluginInfo(); // ChatTabAccessor void setupChatTab(QWidget* tab, int account, const QString& contact); void setupGCTab(QWidget* /*tab*/, int /*account*/, const QString& /*contact*/) { /* do nothing*/ } virtual bool appendingChatMessage(int account, const QString& contact, QString& body, QDomElement& html, bool local); //stanza filter virtual bool incomingStanza(int account, const QDomElement& stanza); virtual bool outgoingStanza(int , QDomElement& ); //ToolbarIconAccessor virtual QList < QVariantHash > getButtonParam() { return QList < QVariantHash >(); } virtual QAction* getAction(QObject* parent, int account, const QString& contact); private slots: void removeWidget(); void getColor(); void onActionActivated(bool); private: void addMessageNum(QDomDocument* doc, QDomElement* stanza, quint16 num, const QColor& color); static QString numToFormatedStr(int number); static void nl2br(QDomElement *body,QDomDocument* doc, const QString& msg); bool isEnabledFor(int account, const QString& jid) const; private: bool enabled; OptionAccessingHost* _psiOptions; ActiveTabAccessingHost* _activeTab; ApplicationInfoAccessingHost* _applicationInfo; PsiAccountControllingHost* _accContrller; typedef QMap JidEnums; QMap _enumsIncomming, _enumsOutgoing; QColor _inColor, _outColor; bool _defaultAction; Ui::Options _ui; QPointer _options; typedef QMap JidActions; QMap _jidActions; }; #endif // ENUMMESSAGESPLUGIN_H plugins-1.5/generic/enummessagesplugin/enummessagesplugin.pro000066400000000000000000000004461336777360500250510ustar00rootroot00000000000000isEmpty(PSISDK) { include(../../psiplugin.pri) } else { include($$PSISDK/plugins/psiplugin.pri) } SOURCES += \ enummessagesplugin.cpp HEADERS += \ defines.h \ enummessagesplugin.h RESOURCES += resources.qrc OTHER_FILES += \ changelog.txt FORMS += \ options.ui plugins-1.5/generic/enummessagesplugin/options.ui000066400000000000000000000057511336777360500224520ustar00rootroot00000000000000 Options 0 0 266 194 Form Color for incoming messages numbers Color for outgoing messages numbers Qt::Horizontal 40 20 Default plugin action Disabled Enabled Qt::Horizontal 89 20 Qt::Vertical 20 34 plugins-1.5/generic/enummessagesplugin/resources.qrc000066400000000000000000000001321336777360500231250ustar00rootroot00000000000000 em.png plugins-1.5/generic/extendedmenuplugin/000077500000000000000000000000001336777360500204015ustar00rootroot00000000000000plugins-1.5/generic/extendedmenuplugin/CMakeLists.txt000066400000000000000000000025011336777360500231370ustar00rootroot00000000000000unset(_HDRS) unset(_UIS) unset(_SRCS) unset(_RSCS) unset(PLUGIN) set( PLUGIN extendedmenuplugin ) project(${PLUGIN}) cmake_minimum_required(VERSION 3.1.0) set( CMAKE_AUTOMOC TRUE ) IF( NOT WIN32 ) set( LIB_SUFFIX "" CACHE STRING "Define suffix of directory name (32/64)" ) set( PLUGINS_PATH "lib${LIB_SUFFIX}/psi-plus/plugins" CACHE STRING "Install suffix for plugins" ) ELSE() set( PLUGINS_PATH "psi-plus/plugins" CACHE STRING "Install suffix for plugins" ) ENDIF() add_definitions( -DQT_PLUGIN -DHAVE_QT5 ) include_directories( ${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ../../include . ) set( _SRCS ${PLUGIN}.cpp ) set( _UIS options.ui ) set( _RSCS ${PLUGIN}.qrc ) find_package( Qt5 COMPONENTS Widgets Xml REQUIRED ) set(QT_DEPLIBS Qt5::Widgets Qt5::Xml ) qt5_wrap_ui(UIS ${_UIS}) qt5_add_resources(RSCS ${_RSCS}) add_library( ${PLUGIN} MODULE ${_SRCS} ${UIS} ${RSCS} ) target_link_libraries( ${PLUGIN} ${QT_DEPLIBS} ) if( UNIX AND NOT( APPLE OR CYGWIN ) ) install( TARGETS ${PLUGIN} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} ) endif() if( WIN32 ) install( TARGETS ${PLUGIN} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} ) endif() plugins-1.5/generic/extendedmenuplugin/changelog.txt000066400000000000000000000043731336777360500231000ustar00rootroot000000000000002014-03-15 v0.1.3 tehnick * Show messages in chat instead of using popups. Popups will be used only if chat is not opened yet. * Show message dialogs when popups are disabled. 2013-08-13 v0.1.2 taurus + Иконка плагина 2012-02-20 v0.1.1 * исправления для нового попап-интерфейса 2011-05-18 v0.1.0 * исправлена ошибка, в результате которой нельзя было узнать последнюю активность оффлайн контакта + если ваш аккаунт в оффлайне, некоторые пункты меню будут недоступны 2011-05-16 v0.0.9 * различные исправления и улучшения 2011-02-10 v0.0.7 * подправлен текст всплывающего сообщения для Last Activity для некоторых случаев + css для меню 2011-02-09 v0.0.6 + добавлена кнопка в окно чата + в настройках можно включать\отключать кнопку в окне чата и подменю в меню контакта - настроки попапов перенесены в опции приложения + добавлен запрос XEP-0202: Entity Time + добавлен запрос XEP-0012: Last Activity * различные исправления и улучшения 2011-01-16 v0.0.5 + добавлены иконки * изменено сообщение во всплывающем уведомлении * исправлен пинг приватов из конференции * некоторые улучшения 2011-01-15 v0.0.4 * исправлены опечатки 2011-01-14 v0.0.3 + добавлены команды "Copy Status Message" и "Ping" + добавлены настройки задержки всплывающего уведомления 2011-01-13 v0.0.1 !initial version Данный плагин добавляет в контекстное меню контакта ростера подменю "Extended Actions". На данный момент там имеется два пункта: "Скопировать JID" и "Скопировать ник". plugins-1.5/generic/extendedmenuplugin/extendedmenu.png000066400000000000000000000012241336777360500235730ustar00rootroot00000000000000PNG  IHDRasBIT|d pHYs+6IDAT8_HSala'%f jd^ AB!EEBWER7ݏhZI-M$p)3m,bxt)T^}<<=g /^ O5M(I]Z#Fs(HjZRմ> $ QRbezz EI!6\.׮ v9u+̛CEIQYyx|̽{͋= zK,ۈǗeE`M7L>KVS$& XJ7CZ%j-36<%$? sȒCUXgTr Hzv|[sE #include #include #include #include #include "psiplugin.h" #include "accountinfoaccessor.h" #include "accountinfoaccessinghost.h" #include "optionaccessor.h" #include "optionaccessinghost.h" #include "iconfactoryaccessor.h" #include "iconfactoryaccessinghost.h" #include "popupaccessor.h" #include "popupaccessinghost.h" #include "menuaccessor.h" #include "plugininfoprovider.h" #include "contactinfoaccessinghost.h" #include "contactinfoaccessor.h" #include "stanzafilter.h" #include "stanzasender.h" #include "stanzasendinghost.h" #include "toolbariconaccessor.h" #include "psiaccountcontroller.h" #include "psiaccountcontrollinghost.h" #include "ui_options.h" #define cVer "0.1.3" #define constInterval "intrvl" #define constAction "action" #define constMenu "menu" #define POPUP_OPTION_NAME "Extended Menu Plugin" static const QString pingString = ""; static const QString lastSeenString = ""; static const QString timeString = ""; enum ActionType { NoAction = 0, CopyJid, CopyNick, CopyStatusMessage, RequestPing, RequestLastSeen, RequestTime }; class ExtendedMenuPlugin: public QObject, public PsiPlugin, public OptionAccessor, public AccountInfoAccessor, public IconFactoryAccessor, public PopupAccessor, public MenuAccessor, public PluginInfoProvider, public ContactInfoAccessor, public StanzaSender, public StanzaFilter, public ToolbarIconAccessor, public PsiAccountController { Q_OBJECT #ifdef HAVE_QT5 Q_PLUGIN_METADATA(IID "com.psi-plus.ExtendedMenuPlugin") #endif Q_INTERFACES(PsiPlugin AccountInfoAccessor OptionAccessor IconFactoryAccessor PopupAccessor MenuAccessor ContactInfoAccessor PluginInfoProvider StanzaFilter StanzaSender ToolbarIconAccessor PsiAccountController) public: ExtendedMenuPlugin(); virtual QString name() const; virtual QString shortName() const; virtual QString version() const; virtual QWidget* options(); virtual Priority priority(); virtual bool enable(); virtual bool disable(); virtual void applyOptions(); virtual void restoreOptions(); virtual void setAccountInfoAccessingHost(AccountInfoAccessingHost* host); virtual void setOptionAccessingHost(OptionAccessingHost* host); virtual void optionChanged(const QString& ) {} virtual void setIconFactoryAccessingHost(IconFactoryAccessingHost* host); virtual void setPopupAccessingHost(PopupAccessingHost* host); virtual void setPsiAccountControllingHost(PsiAccountControllingHost* host); virtual QList < QVariantHash > getAccountMenuParam(); virtual QList < QVariantHash > getContactMenuParam(); virtual QAction* getContactAction(QObject* , int , const QString& ); virtual QAction* getAccountAction(QObject* , int ) { return 0; } virtual QList < QVariantHash > getButtonParam(); virtual QAction* getAction(QObject* parent, int account, const QString& contact); virtual void setContactInfoAccessingHost(ContactInfoAccessingHost* host); virtual void setStanzaSendingHost(StanzaSendingHost *host); virtual bool incomingStanza(int account, const QDomElement& xml); virtual bool outgoingStanza(int , QDomElement &) { return false; } virtual QString pluginInfo(); virtual QPixmap icon() const; private slots: void menuActivated(); void toolbarActionActivated(); private: bool enabled; OptionAccessingHost* psiOptions; AccountInfoAccessingHost *accInfo; IconFactoryAccessingHost *icoHost; PsiAccountControllingHost* accountHost; PopupAccessingHost* popup; ContactInfoAccessingHost* contactInfo; StanzaSendingHost* stanzaSender; bool enableMenu, enableAction; int popupId; Ui::Options ui_; struct Request { Request(const QString& id_, ActionType type_, const QTime& t = QTime::currentTime()) : id(id_), time(t), type(type_) { } bool operator==(const Request& other) { return id == other.id; } QString id; QTime time; ActionType type; }; typedef QList Requests; QHash requestList_; void showMessage(int account, const QString& contact, const QString& text, const QString& title); void showPopup(const QString& text, const QString& title); void showDialog(const QString& text, const QString& title); void fillMenu(QMenu* m, int account, const QString& jid); void addRequest(int account, const Request& r); void doCommand(int account, const QString &jid, const QString& command, ActionType type_); }; #ifndef HAVE_QT5 Q_EXPORT_PLUGIN(ExtendedMenuPlugin) #endif ExtendedMenuPlugin::ExtendedMenuPlugin() : enabled(false) , psiOptions(0) , accInfo(0) , icoHost(0) , accountHost(0) , popup(0) , contactInfo(0) , stanzaSender(0) , enableMenu(true) , enableAction(false) , popupId(0) { } QString ExtendedMenuPlugin::name() const { return "Extended Menu Plugin"; } QString ExtendedMenuPlugin::shortName() const { return "extmenu"; } QString ExtendedMenuPlugin::version() const { return cVer; } PsiPlugin::Priority ExtendedMenuPlugin::priority() { return PsiPlugin::PriorityLow; } bool ExtendedMenuPlugin::enable() { enabled = true; requestList_.clear(); enableMenu = psiOptions->getPluginOption(constMenu, enableMenu).toBool(); enableAction = psiOptions->getPluginOption(constAction, enableAction).toBool(); int interval = psiOptions->getPluginOption(constInterval, QVariant(5000)).toInt()/1000; popupId = popup->registerOption(POPUP_OPTION_NAME, interval, "plugins.options."+shortName()+"."+constInterval); QFile f(":/icons/icons/ping.png"); f.open(QIODevice::ReadOnly); icoHost->addIcon("menu/ping", f.readAll()); f.close(); f.setFileName(":/icons/icons/copyjid.png"); f.open(QIODevice::ReadOnly); icoHost->addIcon("menu/copyjid", f.readAll()); f.close(); f.setFileName(":/icons/icons/copynick.png"); f.open(QIODevice::ReadOnly); icoHost->addIcon("menu/copynick", f.readAll()); f.close(); f.setFileName(":/icons/icons/copystatusmsg.png"); f.open(QIODevice::ReadOnly); icoHost->addIcon("menu/copystatusmsg", f.readAll()); f.close(); f.setFileName(":/icons/extendedmenu.png"); f.open(QIODevice::ReadOnly); icoHost->addIcon("menu/extendedmenu", f.readAll()); f.close(); return enabled; } bool ExtendedMenuPlugin::disable() { enabled = false; requestList_.clear(); popup->unregisterOption(POPUP_OPTION_NAME); return true; } QWidget* ExtendedMenuPlugin::options() { if(enabled) { QWidget *w = new QWidget(); ui_.setupUi(w); restoreOptions(); return w; } return 0; } void ExtendedMenuPlugin::applyOptions() { enableMenu = ui_.cb_menu->isChecked(); psiOptions->setPluginOption(constMenu, enableMenu); enableAction = ui_.cb_action->isChecked(); psiOptions->setPluginOption(constAction, enableAction); } void ExtendedMenuPlugin::restoreOptions() { ui_.cb_action->setChecked(enableAction); ui_.cb_menu->setChecked(enableMenu); } void ExtendedMenuPlugin::setAccountInfoAccessingHost(AccountInfoAccessingHost* host) { accInfo = host; } void ExtendedMenuPlugin::setOptionAccessingHost(OptionAccessingHost* host) { psiOptions = host; } void ExtendedMenuPlugin::setIconFactoryAccessingHost(IconFactoryAccessingHost *host) { icoHost = host; } void ExtendedMenuPlugin::setPopupAccessingHost(PopupAccessingHost* host) { popup = host; } void ExtendedMenuPlugin::setPsiAccountControllingHost(PsiAccountControllingHost* host) { accountHost = host; } void ExtendedMenuPlugin::setContactInfoAccessingHost(ContactInfoAccessingHost *host) { contactInfo = host; } void ExtendedMenuPlugin::setStanzaSendingHost(StanzaSendingHost *host) { stanzaSender = host; } static const QString secondsToString(ulong seconds) { QString res; int sec = seconds%60; int min = ((seconds-sec)/60)%60; int h = ((((seconds-sec)/60)-min)/60)%24; int day = (((((seconds-sec)/60)-min)/60)-h)/24; if(day) { res += QObject::tr("%n day(s) ", "", day); } if(h) { res += QObject::tr("%n hour(s) ", "", h); } if(min) { res += QObject::tr("%n minute(s) ", "", min); } if(sec) { res += QObject::tr("%n second(s) ", "", sec); } return res; } static int stringToInt(const QString& str) { int sign = (str.at(0) == '-') ? -1 : 1; int result = str.mid(1,2).toInt()*sign; return result; } static QDomElement getFirstChildElement(const QDomElement &elem) { QDomElement newElem; QDomNode node = elem.firstChild(); while(!node.isNull()) { if(!node.isElement()) { node = node.nextSibling(); continue; } newElem = node.toElement(); break; } return newElem; } bool ExtendedMenuPlugin::incomingStanza(int account, const QDomElement &xml) { if(enabled) { if(xml.tagName() == "iq" && xml.hasAttribute("id")) { if(requestList_.contains(account)) { Requests rl = requestList_.value(account); foreach(const Request& r, rl) { if(r.id == xml.attribute("id")) { const QString jid = xml.attribute("from"); QString name; if(contactInfo->isPrivate(account, jid)) { name = jid; } else { name = contactInfo->name(account, jid.split("/").first()); } switch(r.type) { case(RequestPing): { const QString title = tr("Ping %1").arg(name); if(xml.attribute("type") == "result") { double msecs = ((double)r.time.msecsTo(QTime::currentTime()))/1000; showMessage(account, jid, tr("Pong from %1 after %2 secs") .arg(jid) .arg(QString::number(msecs, 'f', 3)), title); } else { showMessage(account, jid, tr("Feature not implemented"), title); } break; } case(RequestLastSeen): { const QString title = tr("%1 Last Activity").arg(name); QDomElement query = xml.firstChildElement("query"); if(!query.isNull() && query.attribute("xmlns") == "jabber:iq:last" && query.hasAttribute("seconds")) { ulong secs = query.attribute("seconds").toInt(); QString text; if(secs) { if(jid.contains("@")) { if(jid.contains("/")) { text = tr("%1 Last Activity was %2 ago").arg(jid, secondsToString(secs)); } else { text = tr("%1 went offline %2 ago").arg(jid, secondsToString(secs)); } } else { text = tr("%1 uptime is %2").arg(jid, secondsToString(secs)); } } else { text = tr("%1 is online!").arg(jid); } showMessage(account, jid, text, title); } else { QDomElement error = xml.firstChildElement("error"); if(!error.isNull()) { QString text = tr("Unknown error!"); QString tagName = getFirstChildElement(error).tagName(); if(!tagName.isEmpty()) { if(tagName == "service-unavailable") { text = tr("Service unavailable"); } else if(tagName == "feature-not-implemented") { text = tr("Feature not implemented"); } else if(tagName == "not-allowed" || tagName == "forbidden") { text = tr("You are not authorized to retrieve Last Activity information"); } } showMessage(account, jid, text, title); } } break; } case(RequestTime): { QDomElement time = xml.firstChildElement("time"); if(!time.isNull()) { const QString title = tr("%1 Time").arg(name); QDomElement utc = time.firstChildElement("utc"); if(!utc.isNull()) { QString zone = time.firstChildElement("tzo").text(); QDateTime dt = QDateTime::fromString(utc.text(), Qt::ISODate); dt = dt.addSecs(stringToInt(zone)*3600); showMessage(account, jid, tr("%1 time is %2").arg(jid, dt.toString("yyyy-MM-dd hh:mm:ss")), title); } else if(!xml.firstChildElement("error").isNull()) { showMessage(account, jid, tr("Feature not implemented"), title); } } break; } default: break; } rl.removeAll(r); if(!rl.isEmpty()) { requestList_.insert(account, rl); } else { requestList_.remove(account); } break; } } } } } return false; } void ExtendedMenuPlugin::showMessage(int account, const QString& contact, const QString &text, const QString &title) { if(!accountHost->appendSysMsg(account, contact, text)) { showPopup(text, title); } } void ExtendedMenuPlugin::showPopup(const QString &text, const QString &title) { QString popupOption = "options.ui.notifications.passive-popups.enabled"; bool popupsEnabled = psiOptions->getGlobalOption(popupOption).toBool(); if(popupsEnabled) { int interval = popup->popupDuration(POPUP_OPTION_NAME); if(interval) { popup->initPopup(text, title, "psi/headline", popupId); } } else { showDialog(text, title); } } void ExtendedMenuPlugin::showDialog(const QString &text, const QString &title) { QMessageBox mb(QMessageBox::Information, title, text, QMessageBox::Ok, NULL, Qt::Dialog | Qt::MSWindowsFixedSizeDialogHint); mb.exec(); } QList < QVariantHash > ExtendedMenuPlugin::getButtonParam() { return QList < QVariantHash >(); } QAction* ExtendedMenuPlugin::getAction(QObject *parent, int account, const QString &contact) { if(!enableAction) { return 0; } QAction* act = new QAction(icoHost->getIcon("menu/extendedmenu"), tr("Extended Actions"), parent); act->setProperty("account", account); act->setProperty("jid", contact); connect(act, SIGNAL(triggered()), SLOT(toolbarActionActivated())); return act; } QList < QVariantHash > ExtendedMenuPlugin::getAccountMenuParam() { return QList < QVariantHash >(); } QList < QVariantHash > ExtendedMenuPlugin::getContactMenuParam() { return QList < QVariantHash >(); } QAction* ExtendedMenuPlugin::getContactAction(QObject* obj, int account, const QString& jid) { if(!enableMenu) { return 0; } QMenu *parent = qobject_cast(obj); if(parent) { QMenu *menu = parent->addMenu(icoHost->getIcon("menu/extendedmenu"), tr("Extended Actions")); fillMenu(menu, account, jid); } return 0; } inline void setupAction(QAction* act, int account, const QString& jid, ActionType type) { act->setProperty("jid", jid); act->setProperty("account", account); act->setProperty("type", type); } void ExtendedMenuPlugin::fillMenu(QMenu *menu, int account, const QString& jid) { bool isOnline = (accInfo->getStatus(account) != "offline"); QAction *copyJidAction = menu->addAction(icoHost->getIcon("menu/copyjid"), tr("Copy JID"), this, SLOT(menuActivated())); setupAction(copyJidAction, account, jid, CopyJid); QAction *copyNickAction = menu->addAction(icoHost->getIcon("menu/copynick"), tr("Copy Nick"), this, SLOT(menuActivated())); setupAction(copyNickAction, account, jid, CopyNick); QAction *copyStatusMessageAction = menu->addAction(icoHost->getIcon("menu/copystatusmsg"), tr("Copy Status Message"), this, SLOT(menuActivated())); setupAction(copyStatusMessageAction, account, jid, CopyStatusMessage); QAction *pingAction = menu->addAction(icoHost->getIcon("menu/ping"), tr("Ping"), this, SLOT(menuActivated())); setupAction(pingAction, account, jid, RequestPing); pingAction->setEnabled(isOnline); QAction *lastSeenAction = menu->addAction(icoHost->getIcon("psi/search"), tr("Last Activity"), this, SLOT(menuActivated())); setupAction(lastSeenAction, account, jid, RequestLastSeen); lastSeenAction->setEnabled(isOnline); QAction *timeAction = menu->addAction(icoHost->getIcon("psi/notification_chat_time"), tr("Entity Time"), this, SLOT(menuActivated())); setupAction(timeAction, account, jid, RequestTime); timeAction->setEnabled(isOnline); } void ExtendedMenuPlugin::toolbarActionActivated() { QAction *act = static_cast(sender()); const QString jid = act->property("jid").toString(); int account = act->property("account").toInt(); QMenu m; m.setStyleSheet(((QWidget*)(act->parent()))->styleSheet()); fillMenu(&m, account, jid); m.exec(QCursor::pos()); } void ExtendedMenuPlugin::menuActivated() { QAction *act = qobject_cast(sender()); QString jid = act->property("jid").toString(); int account = act->property("account").toInt(); if(!contactInfo->isPrivate(account, jid) && jid.contains("/")) { jid = jid.split("/").first(); } ActionType type = (ActionType)act->property("type").toInt(); QString command; switch(type) { case CopyJid: QApplication::clipboard()->setText(jid); return; case CopyNick: QApplication::clipboard()->setText(contactInfo->name(account, jid)); return; case CopyStatusMessage: QApplication::clipboard()->setText(contactInfo->statusMessage(account, jid)); return; case RequestPing: command = pingString; break; case RequestTime: command = timeString; break; case RequestLastSeen: command = lastSeenString; break; default: return; } if(contactInfo->isPrivate(account, jid)) { doCommand(account, jid, command, type); } else { QStringList res = contactInfo->resources(account, jid); if(type == RequestLastSeen && res.isEmpty()) { doCommand(account, jid, command, type); } else { foreach(const QString& resource, res) { QString fullJid = jid; if(!resource.isEmpty()) { fullJid += QString("/") + resource; } doCommand(account, fullJid, command, type); } } } } void ExtendedMenuPlugin::doCommand(int account, const QString &jid, const QString& command, ActionType type) { if(jid.isEmpty()) return; const QString id = stanzaSender->uniqueId(account); QString str = command.arg(accInfo->getJid(account), stanzaSender->escape(jid), id); addRequest(account, Request(id, type)); stanzaSender->sendStanza(account, str); } void ExtendedMenuPlugin::addRequest(int account, const Request &r) { Requests rl = requestList_.value(account); rl.push_back(r); requestList_.insert(account, rl); } QString ExtendedMenuPlugin::pluginInfo() { return tr("Author: ") + "Dealer_WeARE\n" + tr("Email: ") + "wadealer@gmail.com\n\n" + tr("This plugin adds several additional commands into contacts context menu."); } QPixmap ExtendedMenuPlugin::icon() const { return QPixmap(":/icons/extendedmenu.png"); } #include "extendedmenuplugin.moc" plugins-1.5/generic/extendedmenuplugin/extendedmenuplugin.pro000066400000000000000000000003421336777360500250260ustar00rootroot00000000000000isEmpty(PSISDK) { include(../../psiplugin.pri) } else { include($$PSISDK/plugins/psiplugin.pri) } SOURCES += extendedmenuplugin.cpp FORMS += \ options.ui OTHER_FILES += RESOURCES += \ extendedmenuplugin.qrc plugins-1.5/generic/extendedmenuplugin/extendedmenuplugin.qrc000066400000000000000000000004041336777360500250120ustar00rootroot00000000000000 extendedmenu.png icons/copyjid.png icons/copynick.png icons/ping.png icons/copystatusmsg.png plugins-1.5/generic/extendedmenuplugin/icons/000077500000000000000000000000001336777360500215145ustar00rootroot00000000000000plugins-1.5/generic/extendedmenuplugin/icons/copyjid.png000066400000000000000000000012201336777360500236560ustar00rootroot00000000000000PNG  IHDRabKGD pHYs  ~tIME55\IDAT8˥MHTQsͽ3\sFIWQwQЪMf3MEz 7 E@ljB?LQjF8eNý3siՠvv^^?,x-{~pg[t16A ӍgF,{a Ž?6$8ڽ4ˇaςCpGE}zLYО81PYܞQQO&z? Qka%xv5Mj:*)C vFlm7,(h[' aݏ QB 21tֹfbGkЀÃćVwOٗ:;mb[o͹&okbBr(lh+W=o]*g>''^g x̿$f͙ZCowv۶IKK -AI*-//sTJJ)I(QJ]JsNj \ !y4MS1iD"m2LJ 1ф0IENDB`plugins-1.5/generic/extendedmenuplugin/icons/copynick.png000066400000000000000000000012201336777360500240340ustar00rootroot00000000000000PNG  IHDRabKGD pHYs  ~tIME55\IDAT8˥MHTQsͽ3\sFIWQwQЪMf3MEz 7 E@ljB?LQjF8eNý3siՠvv^^?,x-{~pg[t16A ӍgF,{a Ž?6$8ڽ4ˇaςCpGE}zLYО81PYܞQQO&z? Qka%xv5Mj:*)C vFlm7,(h[' aݏ QB 21tֹfbGkЀÃćVwOٗ:;mb[o͹&okbBr(lh+W=o]*g>''^g x̿$f͙ZCowv۶IKK -AI*-//sTJJ)I(QJ]JsNj \ !y4MS1iD"m2LJ 1ф0IENDB`plugins-1.5/generic/extendedmenuplugin/icons/copystatusmsg.png000066400000000000000000000012201336777360500251420ustar00rootroot00000000000000PNG  IHDRabKGD pHYs  ~tIME55\IDAT8˥MHTQsͽ3\sFIWQwQЪMf3MEz 7 E@ljB?LQjF8eNý3siՠvv^^?,x-{~pg[t16A ӍgF,{a Ž?6$8ڽ4ˇaςCpGE}zLYО81PYܞQQO&z? Qka%xv5Mj:*)C vFlm7,(h[' aݏ QB 21tֹfbGkЀÃćVwOٗ:;mb[o͹&okbBr(lh+W=o]*g>''^g x̿$f͙ZCowv۶IKK -AI*-//sTJJ)I(QJ]JsNj \ !y4MS1iD"m2LJ 1ф0IENDB`plugins-1.5/generic/extendedmenuplugin/icons/ping.png000066400000000000000000000003751336777360500231640ustar00rootroot00000000000000PNG  IHDRa pHYs.#.#x?vIDATxc?>ljFQ,?:)z/_c` ```@6 p 1P( X[B]]kШg:o?@03dP?Ä(MHpܞg~pTBN$hP&B^ &!)IIENDB`plugins-1.5/generic/extendedmenuplugin/options.ui000066400000000000000000000025621336777360500224400ustar00rootroot00000000000000 Options 0 0 352 119 Form Contact menu Toolbar action Qt::Vertical 20 40 <a href="http://psi-plus.com/wiki/plugins#extended_menu_plugin">Wiki (Online)</a> true plugins-1.5/generic/extendedoptionsplugin/000077500000000000000000000000001336777360500211305ustar00rootroot00000000000000plugins-1.5/generic/extendedoptionsplugin/CMakeLists.txt000066400000000000000000000024231336777360500236710ustar00rootroot00000000000000unset(_HDRS) unset(_UIS) unset(_SRCS) unset(_RSCS) unset(PLUGIN) set( PLUGIN extendedoptionsplugin ) project(${PLUGIN}) cmake_minimum_required(VERSION 3.1.0) set( CMAKE_AUTOMOC TRUE ) IF( NOT WIN32 ) set( LIB_SUFFIX "" CACHE STRING "Define suffix of directory name (32/64)" ) set( PLUGINS_PATH "lib${LIB_SUFFIX}/psi-plus/plugins" CACHE STRING "Install suffix for plugins" ) ELSE() set( PLUGINS_PATH "psi-plus/plugins" CACHE STRING "Install suffix for plugins" ) ENDIF() add_definitions( -DQT_PLUGIN -DHAVE_QT5 ) include_directories( ${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ../../include . ) set( _SRCS ${PLUGIN}.cpp ) set( _RSCS resources.qrc ) find_package( Qt5 COMPONENTS Widgets Xml REQUIRED ) set(QT_DEPLIBS Qt5::Widgets Qt5::Xml ) qt5_add_resources(RSCS ${_RSCS}) add_library( ${PLUGIN} MODULE ${_SRCS} ${UIS} ${RSCS} ) target_link_libraries( ${PLUGIN} ${QT_DEPLIBS} ) if( UNIX AND NOT( APPLE OR CYGWIN ) ) install( TARGETS ${PLUGIN} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} ) endif() if( WIN32 ) install( TARGETS ${PLUGIN} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} ) endif() plugins-1.5/generic/extendedoptionsplugin/changelog.txt000066400000000000000000000210241336777360500236170ustar00rootroot000000000000002017-02-12 v.0.4.2 + добавлена опция options.history.store-muc-private 2014-03-20 v0.4.0 + добавлена опция options.ui.muc.allow-highlight-events + добавлены опции none и detach для мидлклика на табе + добавлены названия опций в описание элементов (пкм на элементе -> "Что это?") 2013-09-02 v0.3.9 - taurus * Использовать слово Groupchat вместо Conference и MUC - Удалены опции которые отображают тулбар чата и кнопку Вставить и отправить 2013-08-13 v0.3.8 - taurus + Иконка плагина 2012-04-03 v0.3.7 + добавлены опции "options.service-discovery.last-activity", "options.ui.notifications.sounds.notify-every-muc-message", "options.ui.notifications.passive-popups.suppress-while-dnd", "options.ui.notifications.passive-popups.suppress-while-away" 2011-12-15 v0.3.6 - удалена продублированная опция options.html.chat.render (Использовать формат текста отправителя) 2011-08-26 v0.3.5 + добавлены опции options.ui.message.enabled, options.ui.chat.scaled-message-icons * исправлено сохранение списка игнорирования конференций для автовхода * настройки помещены внутрь обрасти с полосами прокрутки, что позволит им поместиться на мониторах с небольшим разрешением 2011-07-18 v0.3.4 + добавлены опции: options.ui.muc.show-initial-joins options.ui.muc.status-with-priority options.ui.muc.userlist.show-status-icons options.ui.muc.userlist.use-slim-group-headings options.ui.muc.userlist.contact-sort-style options.ui.muc.userlist.avatars.avatars-at-left options.ui.muc.userlist.avatars.show options.ui.muc.userlist.avatars.size options.ui.muc.userlist.avatars.radius options.ui.chat.auto-capitalize options.ui.chat.auto-scroll-to-bottom options.ui.chat.caption options.ui.chat.default-jid-mode options.ui.chat.default-jid-mode-ignorelist options.ui.chat.show-status-changes options.ui.chat.status-with-priority options.ui.contactlist.auto-delete-unlisted options.ui.account.single options.xml-console.enable-at-login options.muc.leave-status-message options.muc.accept-defaults options.muc.auto-configure options.ui.flash-windows * некоторый редизайнинг 2011-06-17 v0.3.3 * исправлена работа некоторых опций на вкладке "Конференции" 2011-02-11 v0.3.2 - убрана вкладка с настройками попапов + добавлена вкладка с настройками табов + добавлены опции options.ui.look.colors.tooltip.enable, options.ui.muc.roster-nick-coloring, options.ui.tabs.mouse-doubleclick-action, options.ui.tabs.can-close-inactive-tab 2010-12-14 v0.3.1 + добавлены опции options.ui.muc.hide-on-autojoin, options.ui.look.colors.chat.unread-message-color, options.ui.look.colors.chat.composing-color 2010-09-11 v0.3.0 * обновлены ссылки на wiki 2010-07-19 v0.2.9 + добавлена ссылка на страничку с описанием css для psi+ + добавлена обработка опций options.ui.chat.hide-when-closing, options.html.muc.render и options.ui.disable-send-button * небольшие изменения вкладки настроек ростера 2010-07-15 v0.2.8 - убраны неиспользуемые опции сортировки групп и аккаунтов 2010-05-31 v0.2.7 + добавлена обработка опций options.ui.notifications.passive-popups.top-to-bottom, options.ui.notifications.passive-popups.at-left-corner, options.ui.notifications.passive-popups.notify-every-muc-message, options.ui.muc.roster-nick-coloring 2010-05-17 v0.2.6 + добавлена информация о плагине 2010-05-04 v0.2.5 * исправлена ссылка на wiki 2010-04-30 v0.2.4 + добавлена обработка опции включения/отключения иконок клиентов в ростере конференции * настройки css разнесены по отдельным подвкладкам 2010-04-14 v0.2.3 + добавлена обработка опций options.ui.tabs.show-tab-icons, options.ui.notifications.passive-popups.css, options.ui.contactlist.tooltip.css 2010-03-24 v0.2.2 + добавлена вкладка с настройками css + добавлены опции для настроек css в окне чата и главном окне 2010-03-13 v0.2.0 - удалена ненужная опция Switch tabs with "ALT+(1-9)" + добавлены опции настроки цветов всплывающей подсказки 2010-03-05 v0.1.9 * исправлены опечатки в названиях опций * редизайнинг опций вкладки "ростер" * исправлено определение местонахождения директории текущего профиля для ОС семейства MS Windows 2010-03-03 v0.1.7 + добавлена обработка опции options.ui.contactlist.show-status-icons + добавлена обработка опции options.ui.contactlist.status-icon-over-avatar + добавлена обработка опции options.muc.bookmarks.auto-join + добавлена возможность задать список закладок, в которые не будет осуществляться автовход * исправлена работа списка исключений для автовхода 2010-02-22 v0.1.5 * исправлена опечатка в названии опции + добавлена обработка опции options.ui.contactlist.avatars.use-default-avatar 2010-02-18 v0.1.4 + добавлена обработка опции options.ui.contactlist.avatars.avatars-at-left + добавлена обработка опции options.ui.chat.use-chat-says-style + добавлена обработка опции options.ui.chat.disable-paste-send 2010-02-02 v0.1.3 * фикс имени опции (s/messsage/message) * options.ui.muc.roster-at-left 2010-02-01 v0.1.1 + добавлена настройка отключения групп в ростере конференции + добавлены настройки цветов ролей в ростере конференции + добавлена настройка включения/выключения показа иконок рангов в ростере конференции 2010-01-25 v0.0.9 + добавлена опция включения/отключения показа геолокации во всплывающей подсказке 2010-01-23 v0.0.8 * исправлен вызов опции "Ask for confirmation before clearing chat window" после коммита в psi-git 2010-01-20 v0.0.7 + добавлены опции сортировки групп и аккаунтов в ростере 2010-01-19 v0.0.6 - удалены лишние опции на вкладке Menu ("Меню") + добавлены опции настройки показа аватара в окне чата * теперь можно задать значение "-1" для длительности показа всплывающих окон (это означает, что всплывающее окно не будет само исчезать) 2010-01-13 v0.0.5 * исправлена опечатка в названии опции Enable central toolbar - удалена лишняя опция из настроек всплывающих окон + добавлены настройки цвета 2010-01-12 v0.0.2 * fixed typo (clearing option) 2010-01-12 v0.0.1 ! initial version Данный плагин предназначен для более удобной настройки дополнительных параметров (advanced options) Psi+. Плагин предоставляет доступ к дополнительным настройкам, которые не имеют своего графического интерфейса plugins-1.5/generic/extendedoptionsplugin/extendedoptions.png000066400000000000000000000016221336777360500250530ustar00rootroot00000000000000PNG  IHDRaYIDATx}SkLW~G~@Y+RR)6 #8,6:4D%.CAft`FnLeF.FMsV,P{w/'99'or/ HM4]A1 U_ēWѥmEMMmkvRh24]5qkF{^B,7/{@ ɳ#ۼ!iV(*nִc2eN7% 8!6^*;8ᐤd=nt*ɨʨGw<"a zAHPZL9F6^j^4/'ŐSp(YWNEX\;-Ͽ DВkKr]cAܶ81h .~@hOfbA*G:DoL,~ߕAvV 7"VS4OSS7H( om=pݻޟ6@W#fb)%@&v5 nî%mϝ1!D~L;{X9SԸ~!yY>[ #include #include #include #include #include #include #include #include #include #include #include #include #include "psiplugin.h" #include "optionaccessor.h" #include "optionaccessinghost.h" #include "applicationinfoaccessor.h" #include "applicationinfoaccessinghost.h" #include "plugininfoprovider.h" #define constVersion "0.4.2" class ExtToolButton : public QToolButton { Q_OBJECT public: ExtToolButton() : QToolButton() { setFixedSize(22,22); } }; class ExtendedOptions : public QObject, public PsiPlugin, public OptionAccessor, public ApplicationInfoAccessor, public PluginInfoProvider { Q_OBJECT #ifdef HAVE_QT5 Q_PLUGIN_METADATA(IID "com.psi-plus.ExtendedOptions") #endif Q_INTERFACES(PsiPlugin OptionAccessor ApplicationInfoAccessor PluginInfoProvider) public: ExtendedOptions(); virtual QString name() const; virtual QString shortName() const; virtual QString version() const; virtual QWidget* options(); virtual bool enable(); virtual bool disable(); virtual void optionChanged(const QString& option); virtual void applyOptions(); virtual void restoreOptions(); virtual void setOptionAccessingHost(OptionAccessingHost* host); virtual void setApplicationInfoAccessingHost(ApplicationInfoAccessingHost* host); virtual QString pluginInfo(); virtual QPixmap icon() const; private slots: void chooseColor(QAbstractButton*); void hack(); private: void setWhatThis(); private: OptionAccessingHost *psiOptions; ApplicationInfoAccessingHost* appInfo; bool enabled; QString readFile(); void saveFile(const QString& text); QString profileDir(); QPointer options_; //Chats----- // QCheckBox *htmlRender; QCheckBox *confirmClearing; QCheckBox *messageIcons; //QCheckBox *altnSwitch; QCheckBox *showAvatar; QSpinBox *avatarSize; QCheckBox *sayMode; QCheckBox *disableSend; QCheckBox *auto_capitalize; QCheckBox *auto_scroll_to_bottom; QLineEdit *chat_caption; QComboBox *default_jid_mode; QTextEdit *default_jid_mode_ignorelist; QCheckBox *show_status_changes; QCheckBox *chat_status_with_priority; QCheckBox *scaledIcons; //MUC----- QCheckBox *showJoins; QCheckBox *showRole; QCheckBox *showStatus; QCheckBox *leftMucRoster; QCheckBox *showGroups; QCheckBox *showAffIcons; QCheckBox *skipAutojoin; QTextEdit *bookmarksListSkip; QCheckBox *mucClientIcons; //QCheckBox *rosterNickColors; QCheckBox *mucHtml; QCheckBox *hideAutoJoin; QCheckBox *show_initial_joins; QCheckBox *status_with_priority; QCheckBox *show_status_icons; QCheckBox *use_slim_group_headings; QComboBox *userlist_contact_sort_style; QCheckBox *avatars_at_left; QCheckBox *avatars_show; QSpinBox *userlist_avatars_size; QSpinBox *userlist_avatars_radius; QLineEdit *muc_leave_status_message; QCheckBox *accept_defaults; QCheckBox *auto_configure; QCheckBox *allowMucEvents; QCheckBox *storeMucPrivates; //Roster QCheckBox *resolveNicks; QCheckBox *lockRoster; QCheckBox *leftRoster; QCheckBox *singleLineStatus; QCheckBox *avatarTip; QCheckBox *statusTip; QCheckBox *geoTip; QCheckBox *pgpTip; QCheckBox *clientTip; QComboBox *sortContacts; // QComboBox *sortGroups; // QComboBox *sortAccs; QCheckBox *leftAvatars; QCheckBox *defaultAvatar; QCheckBox *showStatusIcons; QCheckBox *statusIconsOverAvatars; QCheckBox *auto_delete_unlisted; //Menu------ QCheckBox *admin; QCheckBox *activeChats; QCheckBox *pgpKey; QCheckBox *picture; QCheckBox *changeProfile; QCheckBox *chat; QCheckBox *invis; QCheckBox *xa; QCheckBox *enableMessages; //Look----- QToolButton *popupBorder; QToolButton *linkColor; QToolButton *mailtoColor; QToolButton *moderColor; QToolButton *visitorColor; QToolButton *parcColor; QToolButton *noroleColor; QToolButton *tipText; QToolButton *tipBase; QToolButton *composingBut; QToolButton *unreadBut; QGroupBox *groupTip; QGroupBox *groupMucRoster; //CSS---------------- QTextEdit *chatCss; QTextEdit *rosterCss; QTextEdit *popupCss; QTextEdit *tooltipCss; //Tabs---------------- QCheckBox *disableScroll; QCheckBox *bottomTabs; QCheckBox *closeButton; QComboBox *middleButton; QCheckBox *showTabIcons; QCheckBox *hideWhenClose; QCheckBox *canCloseTab; QComboBox *mouseDoubleclick; QCheckBox *multiRow; //Misc QCheckBox *flash_windows; QCheckBox *account_single; QCheckBox *xml_console_enable_at_login; QCheckBox *lastActivity; QCheckBox *sndMucNotify; QCheckBox *popupsSuppressDnd; QCheckBox *popupsSuppressAway; }; #ifndef HAVE_QT5 Q_EXPORT_PLUGIN(ExtendedOptions) #endif ExtendedOptions::ExtendedOptions() : psiOptions(0) , appInfo(0) , enabled(false) { } QString ExtendedOptions::name() const { return "Extended Options Plugin"; } QString ExtendedOptions::shortName() const { return "extopt"; } QString ExtendedOptions::version() const { return constVersion; } bool ExtendedOptions::enable() { if(psiOptions) { enabled = true; } return enabled; } bool ExtendedOptions::disable() { enabled = false; return true; } QWidget* ExtendedOptions::options() { if (!enabled) { return 0; } options_ = new QWidget; QVBoxLayout *mainLayout = new QVBoxLayout(options_); QTabWidget *tabs = new QTabWidget; QWidget *tab1 = new QWidget; QWidget *tab2 = new QWidget; QWidget *tab3 = new QWidget; QWidget *tab4 = new QWidget; QWidget *tab5 = new QWidget; QWidget *tab6 = new QWidget; QWidget *tab7 = new QWidget; QWidget *tab8 = new QWidget; QVBoxLayout *tab1Layout = new QVBoxLayout(tab1); QVBoxLayout *tab2Layout = new QVBoxLayout(tab2); QVBoxLayout *tab3Layout = new QVBoxLayout(tab3); QVBoxLayout *tab4Layout = new QVBoxLayout(tab4); QVBoxLayout *tab5Layout = new QVBoxLayout(tab5); QVBoxLayout *tab6Layout = new QVBoxLayout(tab6); QVBoxLayout *tab7Layout = new QVBoxLayout(tab7); QVBoxLayout *tab8Layout = new QVBoxLayout(tab8); tabs->addTab(tab1, tr("Chat")); tabs->addTab(tab2, tr("Groupchat")); tabs->addTab(tab5, tr("Tabs")); tabs->addTab(tab3, tr("Roster")); tabs->addTab(tab4, tr("Menu")); tabs->addTab(tab6, tr("Look")); tabs->addTab(tab7, tr("CSS")); tabs->addTab(tab8, tr("Misc")); //Chats----- // htmlRender = new QCheckBox(tr("Enable HTML rendering in chat window")); confirmClearing = new QCheckBox(tr("Ask for confirmation before clearing chat window")); messageIcons = new QCheckBox(tr("Enable icons in chat")); scaledIcons = new QCheckBox(tr("Scaled message icons")); /* altnSwitch = new QCheckBox(tr("Switch tabs with \"ALT+(1-9)\"")); altnSwitch->setChecked(psiOptions->getGlobalOption("options.ui.tabs.alt-n-switch").toBool());*/ showAvatar = new QCheckBox(tr("Show Avatar")); sayMode = new QCheckBox(tr("Enable \"Says style\"")); disableSend = new QCheckBox(tr("Hide \"Send\" button")); avatarSize = new QSpinBox; QGridLayout *chatGridLayout = new QGridLayout; chatGridLayout->addWidget(new QLabel(tr("Avatar size:")), 0, 0); chatGridLayout->addWidget(avatarSize, 0, 1); default_jid_mode = new QComboBox; default_jid_mode->addItems(QStringList() << "auto" << "barejid"); chatGridLayout->addWidget(new QLabel(tr("Default JID mode:")), 1, 0); chatGridLayout->addWidget(default_jid_mode); auto_capitalize = new QCheckBox(tr("Automatically capitalize the first letter in a sentence")); auto_scroll_to_bottom = new QCheckBox(tr("Automatically scroll down the log when a message was sent")); show_status_changes = new QCheckBox(tr("Show status changes")); chat_status_with_priority = new QCheckBox(tr("Show status priority")); default_jid_mode_ignorelist = new QTextEdit; default_jid_mode_ignorelist->setMaximumWidth(300); chat_caption = new QLineEdit; tab1Layout->addWidget(new QLabel(tr("Chat window caption:"))); tab1Layout->addWidget(chat_caption); // tab1Layout->addWidget(htmlRender); tab1Layout->addWidget(confirmClearing); tab1Layout->addWidget(messageIcons); tab1Layout->addWidget(scaledIcons); //tab1Layout->addWidget(altnSwitch); tab1Layout->addWidget(disableSend); tab1Layout->addWidget(sayMode); tab1Layout->addWidget(showAvatar); tab1Layout->addLayout(chatGridLayout); tab1Layout->addWidget(new QLabel(tr("Default JID mode ignore list:"))); tab1Layout->addWidget(default_jid_mode_ignorelist); tab1Layout->addWidget(auto_capitalize); tab1Layout->addWidget(auto_scroll_to_bottom); tab1Layout->addWidget(show_status_changes); tab1Layout->addWidget(chat_status_with_priority); tab1Layout->addStretch(); //MUC----- QTabWidget *mucTabWidget = new QTabWidget; QWidget *mucGeneralWidget = new QWidget; QWidget *mucRosterWidget = new QWidget; QVBoxLayout *mucGeneralLayout = new QVBoxLayout(mucGeneralWidget); QVBoxLayout *mucRosterLayout = new QVBoxLayout(mucRosterWidget); mucTabWidget->addTab(mucGeneralWidget, tr("General")); mucTabWidget->addTab(mucRosterWidget, tr("Roster")); showJoins = new QCheckBox(tr("Show joins")); show_initial_joins = new QCheckBox(tr("Show initial joins")); status_with_priority = new QCheckBox(tr("Show status with priority")); showRole = new QCheckBox(tr("Show roles and affiliations changes")); showStatus = new QCheckBox(tr("Show status changes")); skipAutojoin = new QCheckBox(tr("Enable autojoin for bookmarked groupchats")); hideAutoJoin = new QCheckBox(tr("Hide groupchat on auto-join")); mucHtml = new QCheckBox(tr("Enable HTML rendering in groupchat chat window")); allowMucEvents = new QCheckBox(tr("Allow groupchat highlight events")); storeMucPrivates = new QCheckBox(tr("Store MUC private messages in history")); muc_leave_status_message = new QLineEdit; accept_defaults = new QCheckBox(tr("Automatically accept the default room configuration")); accept_defaults->setToolTip(tr("Automatically accept the default room configuration when a new room is created")); auto_configure = new QCheckBox(tr("Automatically open the configuration dialog when a new room is created")); auto_configure->setToolTip(tr("Automatically open the configuration dialog when a new room is created.\n" "This option only has effect if accept-defaults is false.")); bookmarksListSkip = new QTextEdit(); bookmarksListSkip->setMaximumWidth(300); bookmarksListSkip->setPlainText(readFile()); mucGeneralLayout->addWidget(accept_defaults); mucGeneralLayout->addWidget(auto_configure); mucGeneralLayout->addWidget(mucHtml); mucGeneralLayout->addWidget(showJoins); mucGeneralLayout->addWidget(show_initial_joins); mucGeneralLayout->addWidget(showRole); mucGeneralLayout->addWidget(showStatus); mucGeneralLayout->addWidget(status_with_priority); mucGeneralLayout->addWidget(skipAutojoin); mucGeneralLayout->addWidget(hideAutoJoin); mucGeneralLayout->addWidget(allowMucEvents); mucGeneralLayout->addWidget(storeMucPrivates); mucGeneralLayout->addWidget(new QLabel(tr("Disable autojoin to following groupchats:\n(specify JIDs)"))); mucGeneralLayout->addWidget(bookmarksListSkip); mucGeneralLayout->addWidget(new QLabel(tr("Groupchat leave status message:"))); mucGeneralLayout->addWidget(muc_leave_status_message); mucGeneralLayout->addStretch(); leftMucRoster = new QCheckBox(tr("Place groupchat roster at left")); showGroups = new QCheckBox(tr("Show groups")); use_slim_group_headings = new QCheckBox(tr("Use slim group heading")); show_status_icons = new QCheckBox(tr("Show status icons")); showAffIcons = new QCheckBox(tr("Show affiliation icons")); mucClientIcons = new QCheckBox(tr("Show client icons")); // rosterNickColors = new QCheckBox(tr("Enable nick coloring")); avatars_show = new QCheckBox(tr("Show avatars")); avatars_at_left = new QCheckBox(tr("Place avatars at left")); userlist_contact_sort_style = new QComboBox; userlist_contact_sort_style->addItems(QStringList() << "alpha" << "status"); QGridLayout *mucRosterGrid = new QGridLayout; mucRosterGrid->addWidget(new QLabel(tr("Sort style for contacts:")), 0, 0); mucRosterGrid->addWidget(userlist_contact_sort_style, 0, 2); userlist_avatars_size = new QSpinBox; mucRosterGrid->addWidget(new QLabel(tr("Avatars size:")), 1, 0); mucRosterGrid->addWidget(userlist_avatars_size, 1, 2); userlist_avatars_radius = new QSpinBox; mucRosterGrid->addWidget(new QLabel(tr("Avatars radius:")), 2, 0); mucRosterGrid->addWidget(userlist_avatars_radius, 2, 2); mucRosterLayout->addWidget(leftMucRoster); mucRosterLayout->addWidget(showGroups); mucRosterLayout->addWidget(use_slim_group_headings); mucRosterLayout->addWidget(show_status_icons); mucRosterLayout->addWidget(showAffIcons); mucRosterLayout->addWidget(mucClientIcons); // mucRosterLayout->addWidget(rosterNickColors); mucRosterLayout->addWidget(avatars_show); mucRosterLayout->addWidget(avatars_at_left); mucRosterLayout->addLayout(mucRosterGrid); mucRosterLayout->addStretch(); tab2Layout->addWidget(mucTabWidget); //Roster resolveNicks = new QCheckBox(tr("Resolve nicks on contact add")); lockRoster = new QCheckBox(tr("Lockdown roster")); leftRoster = new QCheckBox(tr("Place roster at left in \"all-in-one-window\" mode")); singleLineStatus = new QCheckBox(tr("Contact name and status message in a row")); leftAvatars = new QCheckBox(tr("Place avatars at left")); defaultAvatar = new QCheckBox(tr("If contact does not have avatar, use default avatar")); showStatusIcons = new QCheckBox(tr("Show status icons")); statusIconsOverAvatars = new QCheckBox(tr("Place status icon over avatar")); auto_delete_unlisted = new QCheckBox(tr("Automatically remove temporary contacts")); auto_delete_unlisted->hide(); //FIXME!!!! Remove this when the option will be fixed QGroupBox *groupBox = new QGroupBox(tr("Tooltips:")); QVBoxLayout *boxLayout = new QVBoxLayout(groupBox); avatarTip = new QCheckBox(tr("Show avatar")); statusTip = new QCheckBox(tr("Show last status")); pgpTip = new QCheckBox(tr("Show PGP")); clientTip = new QCheckBox(tr("Show client version")); geoTip = new QCheckBox(tr("Show geolocation")); boxLayout->addWidget(avatarTip); boxLayout->addWidget(statusTip); boxLayout->addWidget(pgpTip); boxLayout->addWidget(clientTip); boxLayout->addWidget(geoTip); sortContacts = new QComboBox; sortContacts->addItem("alpha"); sortContacts->addItem("status"); QHBoxLayout *sortLayout = new QHBoxLayout(); sortLayout->addWidget(new QLabel(tr("Sort style for contacts:"))); sortLayout->addWidget(sortContacts); sortLayout->addStretch(); tab3Layout->addWidget(resolveNicks); tab3Layout->addWidget(lockRoster); tab3Layout->addWidget(auto_delete_unlisted); tab3Layout->addWidget(leftRoster); tab3Layout->addWidget(singleLineStatus); tab3Layout->addWidget(showStatusIcons); tab3Layout->addWidget(statusIconsOverAvatars); tab3Layout->addWidget(leftAvatars); tab3Layout->addWidget(defaultAvatar); tab3Layout->addLayout(sortLayout); tab3Layout->addWidget(groupBox); tab3Layout->addStretch(); //Menu------ admin = new QCheckBox(tr("Show \"Admin\" option in account menu")); activeChats = new QCheckBox(tr("Show \"Active Chats\" option in contact menu")); pgpKey = new QCheckBox(tr("Show \"Assign OpenPGP Key\" option in contact menu")); picture = new QCheckBox(tr("Show \"Picture\" option in contact menu")); changeProfile = new QCheckBox(tr("Show \"Change Profile\" option in main menu")); chat = new QCheckBox(tr("Show \"Chat\" option in status menu")); invis = new QCheckBox(tr("Show \"Invisible\" option in status menu")); xa = new QCheckBox(tr("Show \"XA\" option in status menu")); enableMessages = new QCheckBox(tr("Enable single messages")); tab4Layout->addWidget(enableMessages); tab4Layout->addWidget(admin); tab4Layout->addWidget(activeChats); tab4Layout->addWidget(pgpKey); tab4Layout->addWidget(picture); tab4Layout->addWidget(changeProfile); tab4Layout->addWidget(chat); tab4Layout->addWidget(invis); tab4Layout->addWidget(xa); tab4Layout->addStretch(); //Look---- popupBorder = new ExtToolButton; QHBoxLayout *pbLayout = new QHBoxLayout; pbLayout->addWidget(new QLabel(tr("Popup border color:"))); pbLayout->addStretch(); pbLayout->addWidget(popupBorder); linkColor = new ExtToolButton; QHBoxLayout *lcLayout = new QHBoxLayout; lcLayout->addWidget(new QLabel(tr("Link color:"))); lcLayout->addStretch(); lcLayout->addWidget(linkColor); mailtoColor = new ExtToolButton; QHBoxLayout *mcLayout = new QHBoxLayout; mcLayout->addWidget(new QLabel(tr("Mailto color:"))); mcLayout->addStretch(); mcLayout->addWidget(mailtoColor); moderColor = new ExtToolButton; QHBoxLayout *modcLayout = new QHBoxLayout; modcLayout->addWidget(new QLabel(tr("Moderators color:"))); modcLayout->addStretch(); modcLayout->addWidget(moderColor); parcColor = new ExtToolButton; QHBoxLayout *parcLayout = new QHBoxLayout; parcLayout->addWidget(new QLabel(tr("Participants color:"))); parcLayout->addStretch(); parcLayout->addWidget(parcColor); visitorColor = new ExtToolButton; QHBoxLayout *vscLayout = new QHBoxLayout; vscLayout->addWidget(new QLabel(tr("Visitors color:"))); vscLayout->addStretch(); vscLayout->addWidget(visitorColor); noroleColor = new ExtToolButton; QHBoxLayout *nrcLayout = new QHBoxLayout; nrcLayout->addWidget(new QLabel(tr("No Role color:"))); nrcLayout->addStretch(); nrcLayout->addWidget(noroleColor); groupMucRoster = new QGroupBox(tr("Groupchat roster coloring:")); groupMucRoster->setCheckable(true); QVBoxLayout *mucRosterLay = new QVBoxLayout(groupMucRoster); mucRosterLay->addLayout(modcLayout); mucRosterLay->addLayout(parcLayout); mucRosterLay->addLayout(vscLayout); mucRosterLay->addLayout(nrcLayout); connect(groupMucRoster, SIGNAL(toggled(bool)), SLOT(hack())); tipText = new ExtToolButton; QHBoxLayout *ttLayout = new QHBoxLayout; ttLayout->addWidget(new QLabel(tr("ToolTip text color:"))); ttLayout->addStretch(); ttLayout->addWidget(tipText); tipBase = new ExtToolButton; QHBoxLayout *tbLayout = new QHBoxLayout; tbLayout->addWidget(new QLabel(tr("ToolTip background color:"))); tbLayout->addStretch(); tbLayout->addWidget(tipBase); groupTip = new QGroupBox(tr("ToolTip coloring:")); groupTip->setCheckable(true); QVBoxLayout *tipLay = new QVBoxLayout(groupTip); tipLay->addLayout(ttLayout); tipLay->addLayout(tbLayout); connect(groupTip, SIGNAL(toggled(bool)), SLOT(hack())); composingBut = new ExtToolButton; QHBoxLayout *composingLayout = new QHBoxLayout; composingLayout->addWidget(new QLabel(tr("Text color for \"composing\" events on tabs:"))); composingLayout->addStretch(); composingLayout->addWidget(composingBut); unreadBut = new ExtToolButton; QHBoxLayout *unreadLayout = new QHBoxLayout; unreadLayout->addWidget(new QLabel(tr("Text color for \"unread\" events on tabs:"))); unreadLayout->addStretch(); unreadLayout->addWidget(unreadBut); QButtonGroup *b_color = new QButtonGroup; b_color->addButton(popupBorder); b_color->addButton(linkColor); b_color->addButton(mailtoColor); b_color->addButton(moderColor); b_color->addButton(parcColor); b_color->addButton(visitorColor); b_color->addButton(noroleColor); b_color->addButton(tipText); b_color->addButton(tipBase); b_color->addButton(composingBut); b_color->addButton(unreadBut); connect(b_color, SIGNAL(buttonClicked(QAbstractButton*)), SLOT(chooseColor(QAbstractButton*))); QGroupBox *group3Box = new QGroupBox(tr("Colors:")); QVBoxLayout *box3Layout = new QVBoxLayout(group3Box); box3Layout->addWidget(groupMucRoster); box3Layout->addWidget(groupTip); box3Layout->addLayout(pbLayout); box3Layout->addLayout(lcLayout); box3Layout->addLayout(mcLayout); box3Layout->addLayout(composingLayout); box3Layout->addLayout(unreadLayout); box3Layout->addStretch(); tab6Layout->addWidget(group3Box); //CSS---------------- QTabWidget *cssTab = new QTabWidget; chatCss = new QTextEdit; chatCss->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); rosterCss = new QTextEdit; rosterCss->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); popupCss = new QTextEdit; popupCss->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); tooltipCss = new QTextEdit; tooltipCss->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); cssTab->addTab(chatCss, tr("Chat")); cssTab->addTab(rosterCss, tr("Roster")); cssTab->addTab(popupCss, tr("Popup")); cssTab->addTab(tooltipCss, tr("Tooltip")); QLabel *cssLabel = new QLabel(tr("CSS for Psi+")); cssLabel->setOpenExternalLinks(true); tab7Layout->addWidget(cssTab); tab7Layout->addWidget(cssLabel); //Tabs-------------------- disableScroll = new QCheckBox(tr("Disable wheel scroll")); bottomTabs = new QCheckBox(tr("Put tabs at bottom of chat window")); closeButton = new QCheckBox(tr("Show Close Button on tabs")); showTabIcons = new QCheckBox(tr("Show status icons on tabs")); hideWhenClose = new QCheckBox(tr("Hide tab when close chat window")); canCloseTab = new QCheckBox(tr("Allow closing inactive tabs")); multiRow = new QCheckBox(tr("Enable multirow tabs")); middleButton = new QComboBox; QHBoxLayout *mbLayout = new QHBoxLayout; middleButton->addItem("none"); middleButton->addItem("hide"); middleButton->addItem("close"); middleButton->addItem("detach"); mbLayout->addWidget(new QLabel(tr("Action for mouse middle click on tabs:"))); mbLayout->addStretch(); mbLayout->addWidget(middleButton); mouseDoubleclick = new QComboBox; QHBoxLayout *mdLayout = new QHBoxLayout; mouseDoubleclick->addItem("none"); mouseDoubleclick->addItem("hide"); mouseDoubleclick->addItem("close"); mouseDoubleclick->addItem("detach"); mdLayout->addWidget(new QLabel(tr("Action for mouse double click on tabs:"))); mdLayout->addStretch(); mdLayout->addWidget(mouseDoubleclick); tab5Layout->addWidget(hideWhenClose); tab5Layout->addWidget(disableScroll); tab5Layout->addWidget(bottomTabs); tab5Layout->addWidget(canCloseTab); tab5Layout->addWidget(closeButton); tab5Layout->addWidget(showTabIcons); tab5Layout->addWidget(multiRow); tab5Layout->addLayout(mbLayout); tab5Layout->addLayout(mdLayout); tab5Layout->addStretch(); //Misc-------------------------------- flash_windows = new QCheckBox(tr("Enable windows flashing")); account_single = new QCheckBox(tr("Enable \"Single Account\" mode")); xml_console_enable_at_login = new QCheckBox(tr("Enable XML-console on login")); lastActivity = new QCheckBox(tr("Enable last activity server")); sndMucNotify = new QCheckBox(tr("Enable sound notifications for every groupchat message")); popupsSuppressDnd = new QCheckBox(tr("Disable popup notifications if status is DND")); popupsSuppressAway = new QCheckBox(tr("Disable popup notifications if status is Away")); QGroupBox *ngb = new QGroupBox(tr("Notifications")); QVBoxLayout *nvbl = new QVBoxLayout(ngb); nvbl->addWidget(flash_windows); nvbl->addWidget(sndMucNotify); nvbl->addWidget(popupsSuppressDnd); nvbl->addWidget(popupsSuppressAway); tab8Layout->addWidget(account_single); tab8Layout->addWidget(xml_console_enable_at_login); tab8Layout->addWidget(lastActivity); tab8Layout->addWidget(ngb); tab8Layout->addStretch(); QLabel *wikiLink = new QLabel(tr("Wiki (Online)")); wikiLink->setOpenExternalLinks(true); mainLayout->addWidget(tabs); mainLayout->addWidget(wikiLink); setWhatThis(); restoreOptions(); return options_; } void ExtendedOptions::applyOptions() { if(!options_) return; //Chats----- //psiOptions->setGlobalOption("options.html.chat.render",QVariant(htmlRender->isChecked())); psiOptions->setGlobalOption("options.ui.chat.warn-before-clear",QVariant(confirmClearing->isChecked())); psiOptions->setGlobalOption("options.ui.chat.use-message-icons",QVariant(messageIcons->isChecked())); psiOptions->setGlobalOption("options.ui.chat.scaled-message-icons",QVariant(scaledIcons->isChecked())); //psiOptions->setGlobalOption("options.ui.tabs.alt-n-switch",QVariant(altnSwitch->isChecked())); psiOptions->setGlobalOption("options.ui.chat.avatars.show",QVariant(showAvatar->isChecked())); psiOptions->setGlobalOption("options.ui.chat.use-chat-says-style",QVariant(sayMode->isChecked())); psiOptions->setGlobalOption("options.ui.chat.avatars.size", QVariant(avatarSize->value())); psiOptions->setGlobalOption("options.ui.disable-send-button",QVariant(disableSend->isChecked())); psiOptions->setGlobalOption("options.ui.chat.auto-capitalize",QVariant(auto_capitalize->isChecked())); psiOptions->setGlobalOption("options.ui.chat.auto-scroll-to-bottom",QVariant(auto_scroll_to_bottom->isChecked())); psiOptions->setGlobalOption("options.ui.chat.caption",QVariant(chat_caption->text())); psiOptions->setGlobalOption("options.ui.chat.default-jid-mode",QVariant(default_jid_mode->currentText())); psiOptions->setGlobalOption("options.ui.chat.default-jid-mode-ignorelist", QVariant(default_jid_mode_ignorelist->toPlainText() .split(QRegExp("\\s+"), QString::SkipEmptyParts) .join(","))); psiOptions->setGlobalOption("options.ui.chat.show-status-changes",QVariant(show_status_changes->isChecked())); psiOptions->setGlobalOption("options.ui.chat.status-with-priority",QVariant(chat_status_with_priority->isChecked())); //MUC----- psiOptions->setGlobalOption("options.ui.muc.allow-highlight-events", QVariant(allowMucEvents->isChecked())); psiOptions->setGlobalOption("options.muc.show-joins",QVariant(showJoins->isChecked())); psiOptions->setGlobalOption("options.muc.show-role-affiliation",QVariant(showRole->isChecked())); psiOptions->setGlobalOption("options.muc.show-status-changes",QVariant(showStatus->isChecked())); psiOptions->setGlobalOption("options.ui.muc.roster-at-left",QVariant(leftMucRoster->isChecked())); psiOptions->setGlobalOption("options.ui.muc.userlist.show-groups",QVariant(showGroups->isChecked())); psiOptions->setGlobalOption("options.ui.muc.userlist.show-affiliation-icons",QVariant(showAffIcons->isChecked())); psiOptions->setGlobalOption("options.ui.muc.userlist.show-client-icons",QVariant(mucClientIcons->isChecked())); psiOptions->setGlobalOption("options.muc.bookmarks.auto-join",QVariant(skipAutojoin->isChecked())); // psiOptions->setGlobalOption("options.ui.muc.userlist.nick-coloring",QVariant(rosterNickColors->isChecked())); psiOptions->setGlobalOption("options.html.muc.render",QVariant(mucHtml->isChecked())); psiOptions->setGlobalOption("options.ui.muc.hide-on-autojoin",QVariant(hideAutoJoin->isChecked())); saveFile(bookmarksListSkip->toPlainText()); psiOptions->setGlobalOption("options.ui.muc.show-initial-joins",QVariant(show_initial_joins->isChecked())); psiOptions->setGlobalOption("options.ui.muc.status-with-priority",QVariant(status_with_priority->isChecked())); psiOptions->setGlobalOption("options.ui.muc.userlist.show-status-icons",QVariant(show_status_icons->isChecked())); psiOptions->setGlobalOption("options.ui.muc.userlist.use-slim-group-headings",QVariant(use_slim_group_headings->isChecked())); psiOptions->setGlobalOption("options.ui.muc.userlist.contact-sort-style",QVariant(userlist_contact_sort_style->currentText())); psiOptions->setGlobalOption("options.ui.muc.userlist.avatars.avatars-at-left",QVariant(avatars_at_left->isChecked())); psiOptions->setGlobalOption("options.ui.muc.userlist.avatars.show",QVariant(avatars_show->isChecked())); psiOptions->setGlobalOption("options.ui.muc.userlist.avatars.size",QVariant(userlist_avatars_size->value())); psiOptions->setGlobalOption("options.ui.muc.userlist.avatars.radius",QVariant(userlist_avatars_radius->value())); psiOptions->setGlobalOption("options.muc.leave-status-message",QVariant(muc_leave_status_message->text())); psiOptions->setGlobalOption("options.muc.accept-defaults",QVariant(accept_defaults->isChecked())); psiOptions->setGlobalOption("options.muc.auto-configure",QVariant(auto_configure->isChecked())); psiOptions->setGlobalOption("options.history.store-muc-private", QVariant(storeMucPrivates->isChecked())); //Tabs-------------------- psiOptions->setGlobalOption("options.ui.tabs.disable-wheel-scroll",QVariant(disableScroll->isChecked())); psiOptions->setGlobalOption("options.ui.tabs.put-tabs-at-bottom",QVariant(bottomTabs->isChecked())); psiOptions->setGlobalOption("options.ui.tabs.show-tab-close-buttons",QVariant(closeButton->isChecked())); psiOptions->setGlobalOption("options.ui.tabs.mouse-middle-button",QVariant(middleButton->currentText())); psiOptions->setGlobalOption("options.ui.tabs.mouse-doubleclick-action",QVariant(mouseDoubleclick->currentText())); psiOptions->setGlobalOption("options.ui.tabs.show-tab-icons",QVariant(showTabIcons->isChecked())); psiOptions->setGlobalOption("options.ui.chat.hide-when-closing",QVariant(hideWhenClose->isChecked())); psiOptions->setGlobalOption("options.ui.tabs.can-close-inactive-tab",QVariant(canCloseTab->isChecked())); psiOptions->setGlobalOption("options.ui.tabs.multi-rows",QVariant(multiRow->isChecked())); //Roster----- psiOptions->setGlobalOption("options.contactlist.resolve-nicks-on-contact-add",QVariant(resolveNicks->isChecked())); psiOptions->setGlobalOption("options.ui.contactlist.lockdown-roster",QVariant(lockRoster->isChecked())); psiOptions->setGlobalOption("options.ui.contactlist.aio-left-roster",QVariant(leftRoster->isChecked())); psiOptions->setGlobalOption("options.ui.contactlist.status-messages.single-line",QVariant(singleLineStatus->isChecked())); psiOptions->setGlobalOption("options.ui.contactlist.tooltip.avatar",QVariant(avatarTip->isChecked())); psiOptions->setGlobalOption("options.ui.contactlist.tooltip.last-status",QVariant(statusTip->isChecked())); psiOptions->setGlobalOption("options.ui.contactlist.tooltip.pgp",QVariant(pgpTip->isChecked())); psiOptions->setGlobalOption("options.ui.contactlist.tooltip.geolocation",QVariant(geoTip->isChecked())); psiOptions->setGlobalOption("options.ui.contactlist.tooltip.client-version",QVariant(clientTip->isChecked())); psiOptions->setGlobalOption("options.ui.contactlist.contact-sort-style",QVariant(sortContacts->currentText())); // psiOptions->setGlobalOption("options.ui.contactlist.group-sort-style",QVariant(sortGroups->currentText())); // psiOptions->setGlobalOption("options.ui.contactlist.account-sort-style",QVariant(sortAccs->currentText())); psiOptions->setGlobalOption("options.ui.contactlist.avatars.avatars-at-left",QVariant(leftAvatars->isChecked())); psiOptions->setGlobalOption("options.ui.contactlist.avatars.use-default-avatar",QVariant(defaultAvatar->isChecked())); psiOptions->setGlobalOption("options.ui.contactlist.show-status-icons",QVariant(showStatusIcons->isChecked())); psiOptions->setGlobalOption("options.ui.contactlist.status-icon-over-avatar",QVariant(statusIconsOverAvatars->isChecked())); psiOptions->setGlobalOption("options.ui.contactlist.auto-delete-unlisted",QVariant(auto_delete_unlisted->isChecked())); //Menu------ psiOptions->setGlobalOption("options.ui.menu.account.admin",QVariant(admin->isChecked())); psiOptions->setGlobalOption("options.ui.menu.contact.active-chats",QVariant(activeChats->isChecked())); psiOptions->setGlobalOption("options.ui.menu.contact.custom-pgp-key",QVariant(pgpKey->isChecked())); psiOptions->setGlobalOption("options.ui.menu.contact.custom-picture",QVariant(picture->isChecked())); psiOptions->setGlobalOption("options.ui.menu.main.change-profile",QVariant(changeProfile->isChecked())); psiOptions->setGlobalOption("options.ui.menu.status.chat",QVariant(chat->isChecked())); psiOptions->setGlobalOption("options.ui.menu.status.invisible",QVariant(invis->isChecked())); psiOptions->setGlobalOption("options.ui.menu.status.xa",QVariant(xa->isChecked())); psiOptions->setGlobalOption("options.ui.message.enabled", QVariant(enableMessages->isChecked())); //Look---- psiOptions->setGlobalOption("options.ui.look.colors.passive-popup.border", QVariant(popupBorder->property("psi_color").value())); psiOptions->setGlobalOption("options.ui.look.colors.chat.link-color", QVariant(linkColor->property("psi_color").value())); psiOptions->setGlobalOption("options.ui.look.colors.chat.mailto-color", QVariant(mailtoColor->property("psi_color").value())); psiOptions->setGlobalOption("options.ui.look.colors.muc.role-moderator", QVariant(moderColor->property("psi_color").value())); psiOptions->setGlobalOption("options.ui.look.colors.muc.role-participant", QVariant(parcColor->property("psi_color").value())); psiOptions->setGlobalOption("options.ui.look.colors.muc.role-visitor", QVariant(visitorColor->property("psi_color").value())); psiOptions->setGlobalOption("options.ui.look.colors.muc.role-norole", QVariant(noroleColor->property("psi_color").value())); psiOptions->setGlobalOption("options.ui.look.colors.tooltip.text", QVariant(tipText->property("psi_color").value())); psiOptions->setGlobalOption("options.ui.look.colors.tooltip.background", QVariant(tipBase->property("psi_color").value())); psiOptions->setGlobalOption("options.ui.look.colors.chat.unread-message-color", QVariant(unreadBut->property("psi_color").value())); psiOptions->setGlobalOption("options.ui.look.colors.chat.composing-color", QVariant(composingBut->property("psi_color").value())); psiOptions->setGlobalOption("options.ui.look.colors.tooltip.enable",QVariant(groupTip->isChecked())); psiOptions->setGlobalOption("options.ui.muc.userlist.nick-coloring",QVariant(groupMucRoster->isChecked())); //CSS---------------- psiOptions->setGlobalOption("options.ui.chat.css", QVariant(chatCss->toPlainText())); psiOptions->setGlobalOption("options.ui.contactlist.css", QVariant(rosterCss->toPlainText())); psiOptions->setGlobalOption("options.ui.notifications.passive-popups.css", QVariant(popupCss->toPlainText())); psiOptions->setGlobalOption("options.ui.contactlist.tooltip.css", QVariant(tooltipCss->toPlainText())); //Misc-------------------- psiOptions->setGlobalOption("options.ui.flash-windows", QVariant(flash_windows->isChecked())); psiOptions->setGlobalOption("options.ui.account.single", QVariant(account_single->isChecked())); psiOptions->setGlobalOption("options.xml-console.enable-at-login", QVariant(xml_console_enable_at_login->isChecked())); psiOptions->setGlobalOption("options.service-discovery.last-activity", QVariant(lastActivity->isChecked())); psiOptions->setGlobalOption("options.ui.notifications.sounds.notify-every-muc-message", QVariant(sndMucNotify->isChecked())); psiOptions->setGlobalOption("options.ui.notifications.passive-popups.suppress-while-dnd", QVariant(popupsSuppressDnd->isChecked())); psiOptions->setGlobalOption("options.ui.notifications.passive-popups.suppress-while-away", QVariant(popupsSuppressAway->isChecked())); } void ExtendedOptions::restoreOptions() { if(!options_) return; //Chats----- // htmlRender->setChecked(psiOptions->getGlobalOption("options.html.chat.render").toBool()); confirmClearing->setChecked(psiOptions->getGlobalOption("options.ui.chat.warn-before-clear").toBool()); messageIcons->setChecked(psiOptions->getGlobalOption("options.ui.chat.use-message-icons").toBool()); scaledIcons->setChecked(psiOptions->getGlobalOption("options.ui.chat.scaled-message-icons").toBool()); // altnSwitch->setChecked(psiOptions->getGlobalOption("options.ui.tabs.alt-n-switch").toBool()); showAvatar->setChecked(psiOptions->getGlobalOption("options.ui.chat.avatars.show").toBool()); avatarSize->setValue(psiOptions->getGlobalOption("options.ui.chat.avatars.size").toInt()); sayMode->setChecked(psiOptions->getGlobalOption("options.ui.chat.use-chat-says-style").toBool()); disableSend->setChecked(psiOptions->getGlobalOption("options.ui.disable-send-button").toBool()); auto_capitalize->setChecked(psiOptions->getGlobalOption("options.ui.chat.auto-capitalize").toBool()); auto_scroll_to_bottom->setChecked(psiOptions->getGlobalOption("options.ui.chat.auto-scroll-to-bottom").toBool()); chat_caption->setText(psiOptions->getGlobalOption("options.ui.chat.caption").toString()); default_jid_mode->setCurrentIndex(default_jid_mode->findText(psiOptions->getGlobalOption("options.ui.chat.default-jid-mode").toString())); default_jid_mode_ignorelist->setPlainText(psiOptions->getGlobalOption("options.ui.chat.default-jid-mode-ignorelist").toString().split(",").join("\n")); show_status_changes->setChecked(psiOptions->getGlobalOption("options.ui.chat.show-status-changes").toBool()); chat_status_with_priority->setChecked(psiOptions->getGlobalOption("options.ui.chat.status-with-priority").toBool()); //MUC----- allowMucEvents->setChecked(psiOptions->getGlobalOption("options.ui.muc.allow-highlight-events").toBool()); showJoins->setChecked(psiOptions->getGlobalOption("options.muc.show-joins").toBool()); showRole->setChecked(psiOptions->getGlobalOption("options.muc.show-role-affiliation").toBool()); showStatus->setChecked(psiOptions->getGlobalOption("options.muc.show-status-changes").toBool()); leftMucRoster->setChecked(psiOptions->getGlobalOption("options.ui.muc.roster-at-left").toBool()); showGroups->setChecked(psiOptions->getGlobalOption("options.ui.muc.userlist.show-groups").toBool()); showAffIcons->setChecked(psiOptions->getGlobalOption("options.ui.muc.userlist.show-affiliation-icons").toBool()); skipAutojoin->setChecked(psiOptions->getGlobalOption("options.muc.bookmarks.auto-join").toBool()); bookmarksListSkip->setPlainText(readFile()); mucClientIcons->setChecked(psiOptions->getGlobalOption("options.ui.muc.userlist.show-client-icons").toBool()); // rosterNickColors->setChecked(psiOptions->getGlobalOption("options.ui.muc.userlist.nick-coloring").toBool()); mucHtml->setChecked(psiOptions->getGlobalOption("options.html.muc.render").toBool()); hideAutoJoin->setChecked(psiOptions->getGlobalOption("options.ui.muc.hide-on-autojoin").toBool()); show_initial_joins->setChecked(psiOptions->getGlobalOption("options.ui.muc.show-initial-joins").toBool()); status_with_priority->setChecked(psiOptions->getGlobalOption("options.ui.muc.status-with-priority").toBool()); show_status_icons->setChecked(psiOptions->getGlobalOption("options.ui.muc.userlist.show-status-icons").toBool()); use_slim_group_headings->setChecked(psiOptions->getGlobalOption("options.ui.muc.userlist.use-slim-group-headings").toBool()); userlist_contact_sort_style->setCurrentIndex(userlist_contact_sort_style->findText(psiOptions->getGlobalOption("options.ui.muc.userlist.contact-sort-style").toString())); avatars_at_left->setChecked(psiOptions->getGlobalOption("options.ui.muc.userlist.avatars.avatars-at-left").toBool()); avatars_show->setChecked(psiOptions->getGlobalOption("options.ui.muc.userlist.avatars.show").toBool()); userlist_avatars_size->setValue(psiOptions->getGlobalOption("options.ui.muc.userlist.avatars.size").toInt()); userlist_avatars_radius->setValue(psiOptions->getGlobalOption("options.ui.muc.userlist.avatars.radius").toInt()); muc_leave_status_message->setText(psiOptions->getGlobalOption("options.muc.leave-status-message").toString()); accept_defaults->setChecked(psiOptions->getGlobalOption("options.muc.accept-defaults").toBool()); auto_configure->setChecked(psiOptions->getGlobalOption("options.muc.auto-configure").toBool()); storeMucPrivates->setChecked(psiOptions->getGlobalOption("options.history.store-muc-private").toBool()); //Tabs---------------------- disableScroll->setChecked(psiOptions->getGlobalOption("options.ui.tabs.disable-wheel-scroll").toBool()); bottomTabs->setChecked(psiOptions->getGlobalOption("options.ui.tabs.put-tabs-at-bottom").toBool()); closeButton->setChecked(psiOptions->getGlobalOption("options.ui.tabs.show-tab-close-buttons").toBool()); middleButton->setCurrentIndex(middleButton->findText(psiOptions->getGlobalOption("options.ui.tabs.mouse-middle-button").toString())); int index = mouseDoubleclick->findText(psiOptions->getGlobalOption("options.ui.tabs.mouse-doubleclick-action").toString()); if(index == -1) index = 0; mouseDoubleclick->setCurrentIndex(index); showTabIcons->setChecked(psiOptions->getGlobalOption("options.ui.tabs.show-tab-icons").toBool()); hideWhenClose->setChecked(psiOptions->getGlobalOption("options.ui.chat.hide-when-closing").toBool()); canCloseTab->setChecked(psiOptions->getGlobalOption("options.ui.tabs.can-close-inactive-tab").toBool()); multiRow->setChecked(psiOptions->getGlobalOption("options.ui.tabs.multi-rows").toBool()); //Roster resolveNicks->setChecked(psiOptions->getGlobalOption("options.contactlist.resolve-nicks-on-contact-add").toBool()); lockRoster->setChecked(psiOptions->getGlobalOption("options.ui.contactlist.lockdown-roster").toBool()); leftRoster->setChecked(psiOptions->getGlobalOption("options.ui.contactlist.aio-left-roster").toBool()); singleLineStatus->setChecked(psiOptions->getGlobalOption("options.ui.contactlist.status-messages.single-line").toBool()); avatarTip->setChecked(psiOptions->getGlobalOption("options.ui.contactlist.tooltip.avatar").toBool()); statusTip->setChecked(psiOptions->getGlobalOption("options.ui.contactlist.tooltip.last-status").toBool()); geoTip->setChecked(psiOptions->getGlobalOption("options.ui.contactlist.tooltip.geolocation").toBool()); pgpTip->setChecked(psiOptions->getGlobalOption("options.ui.contactlist.tooltip.pgp").toBool()); clientTip->setChecked(psiOptions->getGlobalOption("options.ui.contactlist.tooltip.client-version").toBool()); sortContacts->setCurrentIndex(sortContacts->findText(psiOptions->getGlobalOption("options.ui.contactlist.contact-sort-style").toString())); leftAvatars->setChecked(psiOptions->getGlobalOption("options.ui.contactlist.avatars.avatars-at-left").toBool()); defaultAvatar->setChecked(psiOptions->getGlobalOption("options.ui.contactlist.avatars.use-default-avatar").toBool()); showStatusIcons->setChecked(psiOptions->getGlobalOption("options.ui.contactlist.show-status-icons").toBool()); statusIconsOverAvatars->setChecked(psiOptions->getGlobalOption("options.ui.contactlist.status-icon-over-avatar").toBool()); auto_delete_unlisted->setChecked(psiOptions->getGlobalOption("options.ui.contactlist.auto-delete-unlisted").toBool()); //Menu------ admin->setChecked(psiOptions->getGlobalOption("options.ui.menu.account.admin").toBool()); activeChats->setChecked(psiOptions->getGlobalOption("options.ui.menu.contact.active-chats").toBool()); pgpKey->setChecked(psiOptions->getGlobalOption("options.ui.menu.contact.custom-pgp-key").toBool()); picture->setChecked(psiOptions->getGlobalOption("options.ui.menu.contact.custom-picture").toBool()); changeProfile->setChecked(psiOptions->getGlobalOption("options.ui.menu.main.change-profile").toBool()); chat->setChecked(psiOptions->getGlobalOption("options.ui.menu.status.chat").toBool()); invis->setChecked(psiOptions->getGlobalOption("options.ui.menu.status.invisible").toBool()); xa->setChecked(psiOptions->getGlobalOption("options.ui.menu.status.xa").toBool()); enableMessages->setChecked(psiOptions->getGlobalOption("options.ui.message.enabled").toBool()); //Look---- QColor color; color = psiOptions->getGlobalOption("options.ui.look.colors.passive-popup.border").toString(); popupBorder->setStyleSheet(QString("background-color: %1;").arg(color.name())); popupBorder->setProperty("psi_color", color); color = psiOptions->getGlobalOption("options.ui.look.colors.chat.link-color").toString(); linkColor->setStyleSheet(QString("background-color: %1;").arg(color.name())); linkColor->setProperty("psi_color", color); color = psiOptions->getGlobalOption("options.ui.look.colors.chat.mailto-color").toString(); mailtoColor->setStyleSheet(QString("background-color: %1;").arg(color.name())); mailtoColor->setProperty("psi_color", color); color = psiOptions->getGlobalOption("options.ui.look.colors.muc.role-moderator").toString(); moderColor->setStyleSheet(QString("background-color: %1;").arg(color.name())); moderColor->setProperty("psi_color", color); color = psiOptions->getGlobalOption("options.ui.look.colors.muc.role-participant").toString(); parcColor->setStyleSheet(QString("background-color: %1;").arg(color.name())); parcColor->setProperty("psi_color", color); color = psiOptions->getGlobalOption("options.ui.look.colors.muc.role-visitor").toString(); visitorColor->setStyleSheet(QString("background-color: %1;").arg(color.name())); visitorColor->setProperty("psi_color", color); color = psiOptions->getGlobalOption("options.ui.look.colors.muc.role-norole").toString(); noroleColor->setStyleSheet(QString("background-color: %1;").arg(color.name())); noroleColor->setProperty("psi_color", color); color = psiOptions->getGlobalOption("options.ui.look.colors.tooltip.text").toString(); tipText->setStyleSheet(QString("background-color: %1;").arg(color.name())); tipText->setProperty("psi_color", color); color = psiOptions->getGlobalOption("options.ui.look.colors.tooltip.background").toString(); tipBase->setStyleSheet(QString("background-color: %1;").arg(color.name())); tipBase->setProperty("psi_color", color); color = psiOptions->getGlobalOption("options.ui.look.colors.chat.unread-message-color").toString(); unreadBut->setStyleSheet(QString("background-color: %1;").arg(color.name())); unreadBut->setProperty("psi_color", color); color = psiOptions->getGlobalOption("options.ui.look.colors.chat.composing-color").toString(); composingBut->setStyleSheet(QString("background-color: %1;").arg(color.name())); composingBut->setProperty("psi_color", color); groupTip->setChecked(psiOptions->getGlobalOption("options.ui.look.colors.tooltip.enable").toBool()); groupMucRoster->setChecked(psiOptions->getGlobalOption("options.ui.muc.userlist.nick-coloring").toBool()); //CSS---------------- chatCss->setText(psiOptions->getGlobalOption("options.ui.chat.css").toString()); rosterCss->setText(psiOptions->getGlobalOption("options.ui.contactlist.css").toString()); popupCss->setText(psiOptions->getGlobalOption("options.ui.notifications.passive-popups.css").toString()); tooltipCss->setText(psiOptions->getGlobalOption("options.ui.contactlist.tooltip.css").toString()); //Misc-------------------- flash_windows->setChecked(psiOptions->getGlobalOption("options.ui.flash-windows").toBool()); account_single->setChecked(psiOptions->getGlobalOption("options.ui.account.single").toBool()); xml_console_enable_at_login->setChecked(psiOptions->getGlobalOption("options.xml-console.enable-at-login").toBool()); lastActivity->setChecked(psiOptions->getGlobalOption("options.service-discovery.last-activity").toBool()); sndMucNotify->setChecked(psiOptions->getGlobalOption("options.ui.notifications.sounds.notify-every-muc-message").toBool()); popupsSuppressDnd->setChecked(psiOptions->getGlobalOption("options.ui.notifications.passive-popups.suppress-while-dnd").toBool()); popupsSuppressAway->setChecked(psiOptions->getGlobalOption("options.ui.notifications.passive-popups.suppress-while-away").toBool()); } void ExtendedOptions::setOptionAccessingHost(OptionAccessingHost *host) { psiOptions = host; } void ExtendedOptions::optionChanged(const QString &option) { Q_UNUSED(option); } void ExtendedOptions::chooseColor(QAbstractButton* button) { QColor c; c = button->property("psi_color").value(); c = QColorDialog::getColor(c, new QWidget()); if(c.isValid()) { button->setProperty("psi_color", c); button->setStyleSheet(QString("background-color: %1").arg(c.name())); } hack(); } void ExtendedOptions::setApplicationInfoAccessingHost(ApplicationInfoAccessingHost* host) { appInfo = host; } QString ExtendedOptions::readFile() { QFile file(profileDir() + QDir::separator() + QString("mucskipautojoin.txt")); if(file.open(QIODevice::ReadOnly)) { QTextStream in(&file); in.setCodec("UTF-8"); return in.readAll(); } return QString(); } void ExtendedOptions::saveFile(const QString& text) { QFile file(profileDir() + QDir::separator() + QString("mucskipautojoin.txt")); if(file.open(QIODevice::WriteOnly | QIODevice::Truncate)) { if(text.isEmpty()) return; QTextStream out(&file); out.setCodec("UTF-8"); out.setGenerateByteOrderMark(false); out << text << endl; } } void ExtendedOptions::hack() { //Enable "Apply" button confirmClearing->toggle(); confirmClearing->toggle(); } void ExtendedOptions::setWhatThis() { //Chats----- confirmClearing->setWhatsThis("options.ui.chat.warn-before-clear"); messageIcons->setWhatsThis("options.ui.chat.use-message-icons"); scaledIcons->setWhatsThis("options.ui.chat.scaled-message-icons"); showAvatar->setWhatsThis("options.ui.chat.avatars.show"); avatarSize->setWhatsThis("options.ui.chat.avatars.size"); sayMode->setWhatsThis("options.ui.chat.use-chat-says-style"); disableSend->setWhatsThis("options.ui.disable-send-button"); auto_capitalize->setWhatsThis("options.ui.chat.auto-capitalize"); auto_scroll_to_bottom->setWhatsThis("options.ui.chat.auto-scroll-to-bottom"); chat_caption->setWhatsThis("options.ui.chat.caption"); default_jid_mode->setWhatsThis("options.ui.chat.default-jid-mode"); default_jid_mode_ignorelist->setWhatsThis("options.ui.chat.default-jid-mode-ignorelist"); show_status_changes->setWhatsThis("options.ui.chat.show-status-changes"); chat_status_with_priority->setWhatsThis("options.ui.chat.status-with-priority"); //MUC----- allowMucEvents->setWhatsThis("options.ui.muc.allow-highlight-events"); showJoins->setWhatsThis("options.muc.show-joins"); showRole->setWhatsThis("options.muc.show-role-affiliation"); showStatus->setWhatsThis("options.muc.show-status-changes"); leftMucRoster->setWhatsThis("options.ui.muc.roster-at-left"); showGroups->setWhatsThis("options.ui.muc.userlist.show-groups"); showAffIcons->setWhatsThis("options.ui.muc.userlist.show-affiliation-icons"); skipAutojoin->setWhatsThis("options.muc.bookmarks.auto-join"); mucClientIcons->setWhatsThis("options.ui.muc.userlist.show-client-icons"); mucHtml->setWhatsThis("options.html.muc.render"); hideAutoJoin->setWhatsThis("options.ui.muc.hide-on-autojoin"); show_initial_joins->setWhatsThis("options.ui.muc.show-initial-joins"); status_with_priority->setWhatsThis("options.ui.muc.status-with-priority"); show_status_icons->setWhatsThis("options.ui.muc.userlist.show-status-icons"); use_slim_group_headings->setWhatsThis("options.ui.muc.userlist.use-slim-group-headings"); userlist_contact_sort_style->setWhatsThis("options.ui.muc.userlist.contact-sort-style"); avatars_at_left->setWhatsThis("options.ui.muc.userlist.avatars.avatars-at-left"); avatars_show->setWhatsThis("options.ui.muc.userlist.avatars.show"); userlist_avatars_size->setWhatsThis("options.ui.muc.userlist.avatars.size"); userlist_avatars_radius->setWhatsThis("options.ui.muc.userlist.avatars.radius"); muc_leave_status_message->setWhatsThis("options.muc.leave-status-message"); accept_defaults->setWhatsThis("options.muc.accept-defaults"); auto_configure->setWhatsThis("options.muc.auto-configure"); storeMucPrivates->setWhatsThis("options.history.store-muc-private"); //Tabs---------------------- disableScroll->setWhatsThis("options.ui.tabs.disable-wheel-scroll"); bottomTabs->setWhatsThis("options.ui.tabs.put-tabs-at-bottom"); closeButton->setWhatsThis("options.ui.tabs.show-tab-close-buttons"); middleButton->setWhatsThis("options.ui.tabs.mouse-middle-button"); mouseDoubleclick->setWhatsThis("options.ui.tabs.mouse-doubleclick-action"); showTabIcons->setWhatsThis("options.ui.tabs.show-tab-icons"); hideWhenClose->setWhatsThis("options.ui.chat.hide-when-closing"); canCloseTab->setWhatsThis("options.ui.tabs.can-close-inactive-tab"); multiRow->setWhatsThis("options.ui.tabs.multi-rows"); //Roster resolveNicks->setWhatsThis("options.contactlist.resolve-nicks-on-contact-add"); lockRoster->setWhatsThis("options.ui.contactlist.lockdown-roster"); leftRoster->setWhatsThis("options.ui.contactlist.aio-left-roster"); singleLineStatus->setWhatsThis("options.ui.contactlist.status-messages.single-line"); avatarTip->setWhatsThis("options.ui.contactlist.tooltip.avatar"); statusTip->setWhatsThis("options.ui.contactlist.tooltip.last-status"); geoTip->setWhatsThis("options.ui.contactlist.tooltip.geolocation"); pgpTip->setWhatsThis("options.ui.contactlist.tooltip.pgp"); clientTip->setWhatsThis("options.ui.contactlist.tooltip.client-version"); sortContacts->setWhatsThis("options.ui.contactlist.contact-sort-style"); leftAvatars->setWhatsThis("options.ui.contactlist.avatars.avatars-at-left"); defaultAvatar->setWhatsThis("options.ui.contactlist.avatars.use-default-avatar"); showStatusIcons->setWhatsThis("options.ui.contactlist.show-status-icons"); statusIconsOverAvatars->setWhatsThis("options.ui.contactlist.status-icon-over-avatar"); auto_delete_unlisted->setWhatsThis("options.ui.contactlist.auto-delete-unlisted"); //Menu------ admin->setWhatsThis("options.ui.menu.account.admin"); activeChats->setWhatsThis("options.ui.menu.contact.active-chats"); pgpKey->setWhatsThis("options.ui.menu.contact.custom-pgp-key"); picture->setWhatsThis("options.ui.menu.contact.custom-picture"); changeProfile->setWhatsThis("options.ui.menu.main.change-profile"); chat->setWhatsThis("options.ui.menu.status.chat"); invis->setWhatsThis("options.ui.menu.status.invisible"); xa->setWhatsThis("options.ui.menu.status.xa"); enableMessages->setWhatsThis("options.ui.message.enabled"); //Look---- popupBorder->setWhatsThis("options.ui.look.colors.passive-popup.border"); linkColor->setWhatsThis("options.ui.look.colors.chat.link-color"); mailtoColor->setWhatsThis("options.ui.look.colors.chat.mailto-color"); moderColor->setWhatsThis("options.ui.look.colors.muc.role-moderator"); parcColor->setWhatsThis("options.ui.look.colors.muc.role-participant"); visitorColor->setWhatsThis("options.ui.look.colors.muc.role-visitor"); noroleColor->setWhatsThis("options.ui.look.colors.muc.role-norole"); tipText->setWhatsThis("options.ui.look.colors.tooltip.text"); tipBase->setWhatsThis("options.ui.look.colors.tooltip.background"); unreadBut->setWhatsThis("options.ui.look.colors.chat.unread-message-color"); composingBut->setWhatsThis("options.ui.look.colors.chat.composing-color"); groupTip->setWhatsThis("options.ui.look.colors.tooltip.enable"); groupMucRoster->setWhatsThis("options.ui.muc.userlist.nick-coloring"); //CSS---------------- chatCss->setWhatsThis("options.ui.chat.css"); rosterCss->setWhatsThis("options.ui.contactlist.css"); popupCss->setWhatsThis("options.ui.notifications.passive-popups.css"); tooltipCss->setWhatsThis("options.ui.contactlist.tooltip.css"); //Misc-------------------- flash_windows->setWhatsThis("options.ui.flash-windows"); account_single->setWhatsThis("options.ui.account.single"); xml_console_enable_at_login->setWhatsThis("options.xml-console.enable-at-login"); lastActivity->setWhatsThis("options.service-discovery.last-activity"); sndMucNotify->setWhatsThis("options.ui.notifications.sounds.notify-every-muc-message"); popupsSuppressDnd->setWhatsThis("options.ui.notifications.passive-popups.suppress-while-dnd"); popupsSuppressAway->setWhatsThis("options.ui.notifications.passive-popups.suppress-while-away"); } QString ExtendedOptions::profileDir() { QString profileDir = appInfo->appHistoryDir(); int index = profileDir.size() - profileDir.lastIndexOf("/"); profileDir.chop(index); return profileDir; } QString ExtendedOptions::pluginInfo() { return tr("Author: ") + "Dealer_WeARE\n" + tr("Email: ") + "wadealer@gmail.com\n\n" + trUtf8("This plugin is designed to allow easy configuration of some advanced options in Psi+.\n" "This plugin gives you access to advanced application options, which do not have a graphical user interface.\n\n" "Importantly: a large part of the options are important system settings. These require extra attention and proper" "understanding of the results when changing the option."); } QPixmap ExtendedOptions::icon() const { return QPixmap(":/icons/extendedoptions.png"); } #include "extendedoptionsplugin.moc" plugins-1.5/generic/extendedoptionsplugin/extendedoptionsplugin.pro000066400000000000000000000002521336777360500263040ustar00rootroot00000000000000isEmpty(PSISDK) { include(../../psiplugin.pri) } else { include($$PSISDK/plugins/psiplugin.pri) } SOURCES += extendedoptionsplugin.cpp RESOURCES += resources.qrc plugins-1.5/generic/extendedoptionsplugin/resources.qrc000066400000000000000000000001471336777360500236530ustar00rootroot00000000000000 extendedoptions.png plugins-1.5/generic/generic.pro000066400000000000000000000011551336777360500166350ustar00rootroot00000000000000TEMPLATE = subdirs SUBDIRS += attentionplugin \ autoreplyplugin \ birthdayreminderplugin \ chessplugin \ cleanerplugin \ clientswitcherplugin \ conferenceloggerplugin \ contentdownloaderplugin \ enummessagesplugin \ extendedmenuplugin \ extendedoptionsplugin \ gnupgplugin \ gomokugameplugin \ historykeeperplugin \ httpuploadplugin \ icqdieplugin \ imageplugin \ imagepreviewplugin \ jabberdiskplugin \ juickplugin \ messagefilterplugin \ otrplugin \ pepchangenotifyplugin \ qipxstatusesplugin \ screenshotplugin \ skinsplugin \ stopspamplugin \ storagenotesplugin \ translateplugin \ videostatusplugin \ watcherplugin plugins-1.5/generic/gnupgplugin/000077500000000000000000000000001336777360500170345ustar00rootroot00000000000000plugins-1.5/generic/gnupgplugin/CMakeLists.txt000066400000000000000000000030041336777360500215710ustar00rootroot00000000000000unset(_HDRS) unset(_UIS) unset(_SRCS) unset(_RSCS) unset(PLUGIN) set( PLUGIN gnupgplugin ) project(${PLUGIN}) cmake_minimum_required(VERSION 3.1.0) set( CMAKE_AUTOMOC TRUE ) IF( NOT WIN32 ) set( LIB_SUFFIX "" CACHE STRING "Define suffix of directory name (32/64)" ) set( PLUGINS_PATH "lib${LIB_SUFFIX}/psi-plus/plugins" CACHE STRING "Install suffix for plugins" ) ELSE() set( PLUGINS_PATH "psi-plus/plugins" CACHE STRING "Install suffix for plugins" ) ENDIF() add_definitions( -DQT_PLUGIN -DHAVE_QT5 ) include_directories( ${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ../../include . ) set( _HDRS options.h model.h gpgprocess.h addkeydlg.h gnupg.h lineeditwidget.h datewidget.h ) set( _SRCS options.cpp model.cpp gpgprocess.cpp addkeydlg.cpp gnupg.cpp lineeditwidget.cpp datewidget.cpp ) set( _UIS options.ui addkeydlg.ui ) set( _RSCS resources.qrc ) find_package( Qt5 COMPONENTS Widgets Xml REQUIRED ) set(QT_DEPLIBS Qt5::Widgets Qt5::Xml ) qt5_wrap_ui(UIS ${_UIS}) qt5_add_resources(RSCS ${_RSCS}) add_library( ${PLUGIN} MODULE ${_SRCS} ${UIS} ${RSCS} ) target_link_libraries( ${PLUGIN} ${QT_DEPLIBS} ) if( UNIX AND NOT( APPLE OR CYGWIN ) ) install( TARGETS ${PLUGIN} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} ) endif() if( WIN32 ) install( TARGETS ${PLUGIN} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} ) endif() plugins-1.5/generic/gnupgplugin/addkeydlg.cpp000066400000000000000000000042211336777360500214670ustar00rootroot00000000000000/* * addkeydlg.cpp - generating key pair dialog * * Copyright (C) 2013 Ivan Romanov * * 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 #include "addkeydlg.h" #include "ui_addkeydlg.h" #include "datewidget.h" AddKeyDlg::AddKeyDlg(QWidget *parent) : QDialog(parent) , ui(new Ui::AddKeyDlg) { ui->setupUi(this); adjustSize(); // By default key expires in a year ui->dateExpiration->setDate(QDate::currentDate().addYears(1)); fillLenght(ui->cmbType->currentText()); ui->lineName->setFocus(); } AddKeyDlg::~AddKeyDlg() { delete ui; } QString AddKeyDlg::name() const { return ui->lineName->text().trimmed(); } QString AddKeyDlg::email() const { return ui->lineEmail->text().trimmed(); } QString AddKeyDlg::comment() const { return ui->lineComment->text().trimmed(); } int AddKeyDlg::type() const { return ui->cmbType->currentIndex(); } int AddKeyDlg::length() const { return ui->cmbLength->currentText().toInt(); } QDate AddKeyDlg::expiration() const { return ui->dateExpiration->date(); } QString AddKeyDlg::pass() const { return ui->linePass->text(); } void AddKeyDlg::checkPass() { ui->btnBox->button(QDialogButtonBox::Ok)->setEnabled(ui->linePass->text() == ui->linePass2->text()); } void AddKeyDlg::fillLenght(const QString &type) { QStringList lenghts; lenghts << "1024" << "2048" << "3072"; if (!type.contains("DSA")) { lenghts << "4096"; } ui->cmbLength->clear(); ui->cmbLength->addItems(lenghts); ui->cmbLength->setCurrentIndex(1); } plugins-1.5/generic/gnupgplugin/addkeydlg.h000066400000000000000000000025031336777360500211350ustar00rootroot00000000000000/* * addkeydlg.h - generating key pair dialog * * Copyright (C) 2013 Ivan Romanov * * 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. */ #ifndef ADDKEYDLG_H #define ADDKEYDLG_H #include #include namespace Ui { class AddKeyDlg; } class AddKeyDlg : public QDialog { Q_OBJECT public: explicit AddKeyDlg(QWidget *parent = 0); ~AddKeyDlg(); QString name() const; QString email() const; QString comment() const; int type() const; int length() const; QDate expiration() const; QString pass() const; private slots: void checkPass(); void fillLenght(const QString &type); private: Ui::AddKeyDlg *ui; }; #endif // ADDKEYDLG_H plugins-1.5/generic/gnupgplugin/addkeydlg.ui000066400000000000000000000143701336777360500213300ustar00rootroot00000000000000 AddKeyDlg 0 0 390 341 Generate a new key pair Length: Comment: Expiration date: QLineEdit::Password Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok false Qt::Vertical 20 0 true -1 QLineEdit::Password RSA and RSA (default) DSA and Elgamal DSA (sign only) RSA (sign only) Full name: Passphrase: E-mail address: Key type: Repeat: DateWidget QLineEdit
datewidget.h
lineName lineEmail lineComment cmbType cmbLength dateExpiration linePass linePass2 btnBox btnBox accepted() AddKeyDlg accept() 266 331 157 274 btnBox rejected() AddKeyDlg reject() 334 331 286 274 linePass textEdited(QString) AddKeyDlg checkPass() 180 247 366 239 linePass2 textEdited(QString) AddKeyDlg checkPass() 341 273 362 324 cmbType currentIndexChanged(QString) AddKeyDlg fillLenght(QString) 289 112 386 79 checkPass() fillLenght(QString)
plugins-1.5/generic/gnupgplugin/calendar.png000066400000000000000000000013401336777360500213110ustar00rootroot00000000000000PNG  IHDRh6sRGBbKGD pHYs  tIME131`IDAT(υ=kTa{?Mbf5DB4 DZ?@DE F h@_PtA ƈɽwx9+bTS< C[w+qGk;L-UBs`R_@bעvAι;Ig5džJOk= l' +Ȑ_eUw  LG=g_k"+g2TUoxDZc8I~x [+"@u(TD"Ҙr:OfZ^t("r;gzV!2YsK @Tymz}"U%b(D\KWfۼ(4cf**45v:{Ç}{P[L;bJ۷ZvFameiێnS HU|g.a@UY<4˲vdYFKKKssIҩV=00[˖-7~AIENDB`plugins-1.5/generic/gnupgplugin/changelog.txt000066400000000000000000000061401336777360500215250ustar00rootroot000000000000002015-10-26 - v0.3.9 - taurus * Фикс удаления ключей * Фикс переводов названий столбцов 2014-10-31 - v0.3.8 - taurus * Фикс магических чисел в модели 2014-10-31 - v0.3.7 - taurus * Фикс кнопки отправки ключа 2014-10-29 - v0.3.6 - taurus * Обе настройки по умолчанию включены + Добавлена колонка Expiration 2013-09-27 - v0.3.5 - taurus * Уменьшена иконка плагина - Убрана опция отображать на панели чата 2013-08-13 - v0.3.4 - taurus + Иконка плагина 2013-05-14 - v0.3.3 - taurus * Улучшен алгоритм поиска gpg бинарника * Иконка критической ошибки в информации в случае ошибки 2013-05-14 - v0.3.2 - taurus * Косметика в диалоге создания ключевой пары 2013-05-13 - v0.3.1 - taurus * Добавлен диалог подтверждения удаления ключей 2013-04-04 - v0.3.0 - taurus * Добавлена функция автоимпорта ключа из тела сообщения * В панель инструментов чата добавлена кнопка отправки публичного ключа * В диалоге генерации ключевой пары по умолчанию срок действия ключа 1 год 2013-02-27 - v0.2.1 - taurus * Добавлена информация о плагине * Исправлен алгоритм поиска gpg * Кнопка "Инфо" выводит сообщение о невозможности запустить gpg * Плагин переименован в GnuPG Key Manager (thx nsof) 2013-01-26 - v0.2.0 - taurus * Импорт/экспорт из/в буфер обмена * Улучшен дизайн диалога создания ключей * Испровлена кодировка информации 2013-01-25 - v0.1.6 - taurus * Максимальная длина ключа в диалоге создания ключей зависит от его типа 2013-01-24 - v0.1.5 - taurus * Добавлены двоеточия в диалоге создания новой пары ключей 2013-01-24 - v0.1.4 - taurus * Улучшен внешний вид диалога генерации ключей 2013-01-23 - v0.1.3 - taurus * Исправлено окно Export теперь, Save вместо Open 2013-01-23 - v0.1.2 - taurus * Исправлено отображение русских символов 2013-01-23 - v0.1.1 - taurus * Исправлен алгоритм поиска gpg бинарника 2013-01-21 - v0.1.0 - taurus * GnuPG плагин предназначен для работы с ключами. Первая версия содержит основной набор функций. Позволяет генерировать ключи, удалять, экспортировать и импортировать. plugins-1.5/generic/gnupgplugin/clean.png000066400000000000000000000062131336777360500206260ustar00rootroot00000000000000PNG  IHDRh6 /iCCPICC profileHǝwTTϽwz0R޻{^Ea`(34!ED"HPĀP$VDT$(1ET,oF֋oZ/K<Qt`)LVF_{ͅ!r_zXp3NY|9,8%K.ϊ,f%f(Aˉ9a >,٩<9SbL!GĈ 3,F0+7T3IlpX"61"H _qW,d ėrIKst.ښAdp&+g]RәY2EE44432PuoJEzg`̉j- -b8o׿M]9La.+-%Mȧg3YះuAxEK i<:ŹPcu*@~(  ]o0 ~y*s7g%9%(3H*@C`-pn VH@ A1 jPA3hA'8΃Kn`Lg` a!2D!H҇ dAP B Byf*z: @]h ~L CUp΅ p%;56< ?" GxG iE>&2 oQEGlQP UFFuzQ7QcYG4G۠t]nB/o'Я1 xb"1I>Lf3bX} *QYvGĩp( &q x)&gsF|7:~@&h!$&B%pH$D.q#xx8F|K!\H$!i.%L";r3EHK-AFCbH$^RSIrdd 3Rx)-))zR#RsiSiT#Wd2Z2n2l2d)EBaQ6S))T UEMSPgeedɆfȞ!4--VJ;N g%K-sɵݖ{'OwO%)P_RRۥEK/+))U<د8䡔TtAiF쨜\|FyZbU)W9.Kw+YUEUOUjꂚZZZCu:C=^\G}VCEO#OE&^WOs^K[+\kV֔vv[]n>z^^u}XROm`m3h01$:fь|:kG23hbabhrT4ߴw3=3Y-s.q_vǂbgբ⃥%߲rJ*֪jAe0JOY6rvvtXLǎl&I']$NϝM.6.\ι"En2nnn[g=,=t٪E2}4\j5loDŽǞ~q=''Z^utv&vvEv >mяN9-{ LOgsΝK?7s>xOL n\x }N}g/]>uɫ,u[dS@u]7ot.<30tKn]p;;SwSyoEV:r ln}%Ϧ^~@@,?#R}m!TPo}#a6 #include #include #include #include #include #include #include #include #include #include #include #include "datewidget.h" DateWidget::DateWidget(QWidget *parent) : LineEditWidget(parent) , _tbCalendar(new QToolButton(this)) , _tbClean(new QToolButton(this)) , _calendar(new QCalendarWidget(this)) { setReadOnly(true); _tbClean->setObjectName("brClear"); _tbClean->setIcon(QIcon(":/icons/clean.png")); _tbClean->setContentsMargins(0, 0, 0, 0); _tbClean->setFocusPolicy(Qt::NoFocus); _tbClean->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); _tbClean->setIconSize(QSize(16, 16)); _tbClean->setAutoRaise(true); _tbClean->setAutoFillBackground(true); _tbClean->setCursor(QCursor(Qt::ArrowCursor)); _tbClean->resize(0, 0); addWidget(_tbClean); _tbCalendar->setObjectName("tbCalendar"); _tbCalendar->setIcon(QIcon(":/icons/calendar.png")); _tbCalendar->setContentsMargins(0, 0, 0, 0); _tbCalendar->setFocusPolicy(Qt::NoFocus); _tbCalendar->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); _tbCalendar->setIconSize(QSize(16, 16)); _tbCalendar->setAutoRaise(true); _tbCalendar->setAutoFillBackground(true); _tbCalendar->setCursor(QCursor(Qt::ArrowCursor)); _tbCalendar->resize(0, 0); addWidget(_tbCalendar); setPopup(_calendar); connect(_calendar, SIGNAL(clicked(const QDate&)), SLOT(closeCalendar(const QDate&))); connect(_tbCalendar, SIGNAL(clicked()), SLOT(showPopup())); connect(_tbCalendar, SIGNAL(clicked()), SLOT(calendarSetDate())); connect(_tbClean, SIGNAL(clicked()), SLOT(disableExpiration())); } // Always use format of current locale inline QString dateFormat() { QString format = QLocale().dateFormat(QLocale::LongFormat); #ifdef Q_OS_MAC // The LongFormat has changed between OS X 10.6 and 10.7. // https://qt.gitorious.org/qt/qtbase/commit/8e722eb/diffs // https://bugreports.qt-project.org/browse/QTBUG-27790 if (format.count('y') == 1) { format.replace('y', "yyyy"); } #endif return format; } void DateWidget::setDate(const QDate &date) { setText(date.toString(dateFormat())); } QDate DateWidget::date() const { return QDate::fromString(text(), dateFormat()); } void DateWidget::closeCalendar(const QDate &date) { setDate(date); hidePopup(); } void DateWidget::calendarSetDate() { if(date().isValid()) { _calendar->setSelectedDate(date()); } } void DateWidget::disableExpiration() { setText(trUtf8("never")); } void DateWidget::keyPressEvent(QKeyEvent *event) { if (event->key() == Qt::Key_Backspace || event->key() == Qt::Key_Delete) { disableExpiration(); } else if (event->key() == Qt::Key_Space) { showPopup(); } else { LineEditWidget::keyPressEvent(event); } } plugins-1.5/generic/gnupgplugin/datewidget.h000066400000000000000000000012201336777360500213210ustar00rootroot00000000000000#ifndef DATEWIDGET_H #define DATEWIDGET_H #include #include "lineeditwidget.h" class QToolButton; class QCalendarWidget; class DateWidget : public LineEditWidget { Q_OBJECT Q_PROPERTY(QDate date READ date WRITE setDate) public: explicit DateWidget(QWidget *parent = 0); // get/set date void setDate(const QDate &date); QDate date() const; protected slots: void closeCalendar(const QDate &text); void calendarSetDate(); void disableExpiration(); void keyPressEvent(QKeyEvent *event); private: // Inner widgets QToolButton *_tbCalendar; QToolButton *_tbClean; QCalendarWidget *_calendar; }; #endif // DATEWIDGETs_H plugins-1.5/generic/gnupgplugin/gnupg.cpp000066400000000000000000000136601336777360500206660ustar00rootroot00000000000000/* * gnupg.cpp - plugin main class * * Copyright (C) 2013 Ivan Romanov * * 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 #include #include #include #include #include "options.h" #include "gnupg.h" #include "gpgprocess.h" #include "psiaccountcontrollinghost.h" #include "optionaccessinghost.h" #include "iconfactoryaccessinghost.h" #include "model.h" #include "activetabaccessinghost.h" #include "accountinfoaccessinghost.h" #include "stanzasendinghost.h" #ifndef HAVE_QT5 Q_EXPORT_PLUGIN(GnuPG); #endif GnuPG::GnuPG() : _enabled(false) , _optionsForm(0) , _accountHost(0) , _optionHost(0) , _iconFactory(0) , _menu(0) , _stanzaSending(0) , _activeTab(0) , _accountInfo(0) { } GnuPG::~GnuPG() { } QWidget *GnuPG::options() { if (!_enabled) { return 0; } _optionsForm = new Options(); _optionsForm->setOptionAccessingHost(_optionHost); _optionsForm->loadSettings(); return qobject_cast(_optionsForm); } bool GnuPG::enable() { QFile file(":/icons/key.png"); if ( file.open(QIODevice::ReadOnly) ) { QByteArray image = file.readAll(); _iconFactory->addIcon("gnupg/icon",image); file.close(); _enabled = true; } else { _enabled = false; } return _enabled; } bool GnuPG::disable() { _enabled = false; return true; } void GnuPG::applyOptions() { _optionsForm->saveSettings(); } void GnuPG::restoreOptions() { } QPixmap GnuPG::icon() const { return QPixmap(":/icons/gnupg.png"); } QString GnuPG::pluginInfo() { return tr("Author: ") + "Ivan Romanov\n" + tr("e-mail: ") + "drizt@land.ru\n\n" + tr("GnuPG Key Manager can create, remove, export and import GnuPG keys. " "It can do only the base operations but I hope it will be enough for your needs."); } bool GnuPG::incomingStanza(int account, const QDomElement& stanza) { if (!_enabled) { return false; } if (!_optionHost->getPluginOption("auto-import", true).toBool()) { return false; } if (stanza.tagName() != "message" && stanza.attribute("type") != "chat") { return false; } QString body = stanza.firstChildElement("body").text(); int start = body.indexOf("-----BEGIN PGP PUBLIC KEY BLOCK-----"); if (start == -1) { return false; } int end = body.indexOf("-----END PGP PUBLIC KEY BLOCK-----", start); if (end == -1) { return false; } QString key = body.mid(start, end - start); GpgProcess gpg; QStringList arguments; arguments << "--batch" << "--import"; gpg.start(arguments); gpg.waitForStarted(); gpg.write(key.toUtf8()); gpg.closeWriteChannel(); gpg.waitForFinished(); QString from = stanza.attribute("from"); // Cut trash from gpg command output QString res = QString::fromUtf8(gpg.readAllStandardError()); res = _stanzaSending->escape(res.mid(0, res.indexOf('\n'))); _accountHost->appendSysMsg(account, from, res); // Don't hide message if an error occurred if (gpg.exitCode()) { return false; } if (!_optionHost->getPluginOption("hide-key-message", true).toBool()) { return false; } else { return true; } } QList GnuPG::getButtonParam() { QList l; QVariantHash hash; hash["tooltip"] = QVariant(tr("Send GnuPG Public Key")); hash["icon"] = QVariant(QString("gnupg/icon")); hash["reciver"] = qVariantFromValue(qobject_cast(this)); hash["slot"] = QVariant(SLOT(actionActivated())); l << hash; return l; } void GnuPG::actionActivated() { if (_menu) { delete _menu; } _menu = new QMenu(); Model *model = new Model(_menu); model->listKeys(); for (int i = 0; i < model->rowCount(); i++) { if (model->item(i, Model::Type)->text() != "sec") { continue; } QString str; // User name if (!model->item(i, Model::Name)->text().isEmpty()) { str += model->item(i, Model::Name)->text(); } // Comment if (!model->item(i, Model::Comment)->text().isEmpty()) { if (!str.isEmpty()) { str += " "; } str += QString("(%1)").arg(model->item(i, Model::Comment)->text()); } // Email if (!model->item(i, Model::Email)->text().isEmpty()) { if (!str.isEmpty()) { str += " "; } str += QString("<%1>").arg(model->item(i, Model::Email)->text()); } // Short ID if (!str.isEmpty()) { str += " "; } str += model->item(i, Model::ShortId)->text(); QAction *action = _menu->addAction(str); action->setData(model->item(i, Model::Fingerprint)->text()); connect(action, SIGNAL(triggered()), SLOT(sendPublicKey())); } _menu->popup(QCursor::pos()); } void GnuPG::sendPublicKey() { QAction *action = qobject_cast(sender()); QString fingerprint = "0x" + action->data().toString(); GpgProcess gpg; QStringList arguments; arguments << "--armor" << "--export" << fingerprint; gpg.start(arguments); gpg.waitForFinished(); // do nothing if error is occurred if (gpg.exitCode()) { return; } QString key = QString::fromUtf8(gpg.readAllStandardOutput()); QString jid = _activeTab->getYourJid(); QString jidToSend = _activeTab->getJid(); int account = 0; QString tmpJid; while (jid != (tmpJid = _accountInfo->getJid(account))) { ++account; if (tmpJid == "-1") { return; } } _stanzaSending->sendMessage(account, jidToSend, key, "", "chat"); _accountHost->appendSysMsg(account, jidToSend, _stanzaSending->escape(QString(tr("Public key %1 sent")).arg(action->text()))); } plugins-1.5/generic/gnupgplugin/gnupg.h000066400000000000000000000071331336777360500203310ustar00rootroot00000000000000/* * gnupg.h - plugin main class * * Copyright (C) 2013 Ivan Romanov * * 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. */ #ifndef GNUPG_H #define GNUPG_H #include "psiplugin.h" #include "applicationinfoaccessinghost.h" #include "plugininfoprovider.h" #include "stanzafilter.h" #include "stanzasender.h" #include "psiaccountcontroller.h" #include "optionaccessor.h" #include "toolbariconaccessor.h" #include "iconfactoryaccessor.h" #include "activetabaccessor.h" #include "accountinfoaccessor.h" class Options; class QMenu; class GnuPG : public QObject , public PsiPlugin , public PluginInfoProvider , public StanzaFilter , public PsiAccountController , public OptionAccessor , public ToolbarIconAccessor , public IconFactoryAccessor , public StanzaSender , public ActiveTabAccessor , public AccountInfoAccessor { Q_OBJECT #ifdef HAVE_QT5 Q_PLUGIN_METADATA(IID "com.psi-plus.GnuPG") #endif Q_INTERFACES(PsiPlugin PluginInfoProvider StanzaFilter PsiAccountController OptionAccessor ToolbarIconAccessor IconFactoryAccessor StanzaSender ActiveTabAccessor AccountInfoAccessor) public: GnuPG(); ~GnuPG(); // from PsiPlugin QString name() const { return "GnuPG Key Manager"; } QString shortName() const { return "gnupg"; } QString version() const { return "0.3.9"; } QWidget *options(); bool enable(); bool disable(); void applyOptions(); void restoreOptions(); QPixmap icon() const; // from PluginInfoProvider QString pluginInfo(); // from StanzaSender void setStanzaSendingHost(StanzaSendingHost *host) { _stanzaSending = host; } // from StanzaFilter bool incomingStanza(int account, const QDomElement &stanza); bool outgoingStanza(int /*account*/, QDomElement &/*stanza*/) { return false; } // from PsiAccountController void setPsiAccountControllingHost(PsiAccountControllingHost *host) { _accountHost = host; } // from OptionAccessor void setOptionAccessingHost(OptionAccessingHost *host) { _optionHost = host; } void optionChanged(const QString &/*option*/) { } // from ToolbarIconAccessor QList getButtonParam(); QAction* getAction(QObject * /*parent*/, int /*account*/, const QString &/*contact*/) { return 0; } // from IconFactoryAccessor void setIconFactoryAccessingHost(IconFactoryAccessingHost *host) { _iconFactory = host; } // from ActiveTabAccessor void setActiveTabAccessingHost(ActiveTabAccessingHost* host) { _activeTab = host; } // from AccountInfoAccessor void setAccountInfoAccessingHost(AccountInfoAccessingHost* host) { _accountInfo = host; } private slots: void actionActivated(); void sendPublicKey(); private: bool _enabled; Options *_optionsForm; PsiAccountControllingHost *_accountHost; OptionAccessingHost *_optionHost; IconFactoryAccessingHost *_iconFactory; QMenu *_menu; StanzaSendingHost *_stanzaSending; ActiveTabAccessingHost *_activeTab; AccountInfoAccessingHost *_accountInfo; }; #endif // GNUPG_H plugins-1.5/generic/gnupgplugin/gnupg.png000066400000000000000000000065111336777360500206650ustar00rootroot00000000000000PNG  IHDRa 9iCCPPhotoshop ICC profileHǝwTTϽwz0R޻{^Ea`(34!ED"HPĀP$VDT$(1ET,oF֋oZ/K<Qt`)LVF_{ͅ!r_zXp3NY|9,8%K.ϊ,f%f(Aˉ9a >,٩<9SbL!GĈ 3,F0+7T3IlpX"61"H _qW,d ėrIKst.ښAdp&+g]RәY2EE44432PuoJEzg`̉j- -b8o׿M]9La.+-%Mȧg3YះuAxEK i<:ŹPcu*@~(  ]o0 ~y*s7g%9%(3H*@C`-pn VH@ A1 jPA3hA'8΃Kn`Lg` a!2D!H҇ dAP B Byf*z: @]h ~L CUp΅ p%;56< ?" GxG iE>&2 oQEGlQP UFFuzQ7QcYG4G۠t]nB/o'Я1 xb"1I>Lf3bX} *QYvGĩp( &q x)&gsF|7:~@&h!$&B%pH$D.q#xx8F|K!\H$!i.%L";r3EHK-AFCbH$^RSIrdd 3Rx)-))zR#RsiSiT#Wd2Z2n2l2d)EBaQ6S))T UEMSPgeedɆfȞ!4--VJ;N g%K-sɵݖ{'OwO%)P_RRۥEK/+))U<د8䡔TtAiF쨜\|FyZbU)W9.Kw+YUEUOUjꂚZZZCu:C=^\G}VCEO#OE&^WOs^K[+\kV֔vv[]n>z^^u}XROm`m3h01$:fь|:kG23hbabhrT4ߴw3=3Y-s.q_vǂbgբ⃥%߲rJ*֪jAe0JOY6rvvtXLǎl&I']$NϝM.6.\ι"En2nnn[g=,=t٪E2}4\j5loDŽǞ~q=''Z^utv&vvEv >mяN9-{ LOgsΝK?7s>xOL n\x }N}g/]>uɫ,u[dS@u]7ot.<30tKn]p;;SwSyoEVɬh;˲XXXpD,..f,-;]mە&QZNV.Vn%n<\9uӕ2`+i`S}E0T\oAZ̝0~:?B!L˥bWp.P(X"0gOtiv>rFԷy6+%tD!4KxT@A(ŒDa(JJ]#J) ek>&Vj%Z!O+ܢ",=ߓ֠# .У:f}|p&v2bۅfMy@?C4ToIENDB`plugins-1.5/generic/gnupgplugin/gnupgplugin.pro000066400000000000000000000011361336777360500221160ustar00rootroot00000000000000isEmpty(PSISDK) { include(../../psiplugin.pri) } else { include($$PSISDK/plugins/psiplugin.pri) } INCLUDEPATH += $$PWD DEPENDPATH += $$PWD SOURCES += options.cpp \ model.cpp \ gpgprocess.cpp \ addkeydlg.cpp \ gnupg.cpp \ lineeditwidget.cpp \ datewidget.cpp HEADERS += options.h \ model.h \ gpgprocess.h \ addkeydlg.h \ gnupg.h \ lineeditwidget.h \ datewidget.h FORMS += options.ui \ addkeydlg.ui RESOURCES += resources.qrc win32:LIBS += -ladvapi32 plugins-1.5/generic/gnupgplugin/gpgprocess.cpp000066400000000000000000000076551336777360500217310ustar00rootroot00000000000000/* * gpgprocess.cpp - QProcess wrapper makes it easy to handle gpg * * Copyright (C) 2013 Ivan Romanov * * 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 #include "gpgprocess.h" #include #include #ifdef Q_OS_WIN #include #endif GpgProcess::GpgProcess(QObject *parent) : QProcess(parent) , _bin("") { _bin = findBin(); } inline bool checkBin(const QString &bin) { QFileInfo fi(bin); return fi.exists(); } #ifdef Q_OS_WIN static bool getRegKey(HKEY root, const char *path, QString &value) { HKEY hkey = 0; bool res = false; if(RegOpenKeyExA(root, path, 0, KEY_QUERY_VALUE, &hkey) == ERROR_SUCCESS) { DWORD dwLen = 256; char szValue[256]; if (RegQueryValueExA(hkey, "Install Directory", NULL, NULL, (LPBYTE)szValue, &dwLen) == ERROR_SUCCESS) { value = QString::fromLocal8Bit(szValue); res = true; } RegCloseKey(hkey); } return res; } static QString findRegGpgProgram() { QStringList bins; bins << "gpg.exe" << "gpg2.exe"; HKEY root; root = HKEY_CURRENT_USER; const char *path = "Software\\GNU\\GnuPG"; const char *path2 = "Software\\Wow6432Node\\GNU\\GnuPG"; QString dir; getRegKey(HKEY_CURRENT_USER, path, dir) || getRegKey(HKEY_CURRENT_USER, path2, dir) || getRegKey(HKEY_LOCAL_MACHINE, path, dir) || getRegKey(HKEY_LOCAL_MACHINE, path2, dir); if (!dir.isEmpty()) { foreach (const QString &bin, bins) { if (checkBin(dir + "\\" + bin)) { return dir + "\\" + bin; } } } return QString(); } #endif QString GpgProcess::findBin() const { // gpg and gpg2 has identical semantics // so any from them can be used QStringList bins; #ifdef Q_OS_WIN bins << "gpg.exe" << "gpg2.exe"; #else bins << "gpg" << "gpg2"; #endif // Prefer bundled gpg foreach (const QString &bin, bins) { if (checkBin(QCoreApplication::applicationDirPath() + "/" + bin)) { return QCoreApplication::applicationDirPath() + "/" + bin; } } #ifdef Q_OS_WIN // On Windows look up at registry QString bin = findRegGpgProgram(); if (!bin.isEmpty()) return bin; #endif // Look up at PATH environment #ifdef Q_OS_WIN QString pathSep = ";"; #else QString pathSep = ":"; #endif QStringList paths = QString::fromLocal8Bit(qgetenv("PATH")).split(pathSep, QString::SkipEmptyParts); #ifdef Q_OS_MAC // On Mac OS bundled always uses system default PATH // so it need explicity add extra paths which can // contain gpg // Mac GPG and brew use /usr/local/bin // MacPorts uses /opt/local/bin paths << "/usr/local/bin" << "/opt/local/bin"; #endif paths.removeDuplicates(); foreach (const QString &path, paths) { foreach (const QString &bin, bins) { if (checkBin(path + "/" + bin)) { return path + "/" + bin; } } } // Return nothing if gpg not found return QString(); } bool GpgProcess::info(QString &message) { QStringList arguments; arguments << "--version" << "--no-tty"; start(arguments); waitForFinished(); bool res = false; if (!_bin.isEmpty()) { if (error() == FailedToStart) { message = trUtf8("Can't start ") + _bin; } else { message = QString("%1 %2\n%3").arg(QDir::toNativeSeparators(_bin)).arg(arguments.join(" ")).arg(QString::fromLocal8Bit(readAll())); res = true; } } else { message = trUtf8("GnuPG program not found"); } return res; } plugins-1.5/generic/gnupgplugin/gpgprocess.h000066400000000000000000000024361336777360500213660ustar00rootroot00000000000000/* * gpgprocess.h - QProcess wrapper makes it easy to handle gpg * * Copyright (C) 2013 Ivan Romanov * * 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. */ #ifndef GPGPROCESS_H #define GPGPROCESS_H #include class GpgProcess : public QProcess { Q_OBJECT public: GpgProcess(QObject *parent = 0); inline void start(const QStringList &arguments, OpenMode mode = ReadWrite) { QProcess::start(_bin, arguments, mode); } inline void start(OpenMode mode = ReadWrite) { QProcess::start(_bin, mode); } bool info(QString &message); private: QString findBin() const; QString _bin; }; #endif // GPGPROCESS_H plugins-1.5/generic/gnupgplugin/key.png000066400000000000000000000014511336777360500203330ustar00rootroot00000000000000PNG  IHDRabKGD pHYs  tIME";h !liT4% ")*(.ӈ2>DI,VasnME_;8?HQUvO9S^a|J41tsXjf4 U{0TsJU]4ں^ շ9@(pn,}7oTј`Pkah9̉y? K@)abS!/qr;-JjɭX`l&ҟPsj L8y2iXSCL;Dž!²My%Cjqa4GDoGtf0O[N@\jYk5?S0kV'< LxA։PTF8x3/ 1(W׀W$( L8[/;4c+bg4x{42E=끻!DLy #㾲nW? ~OfZ=ccUݚ7v)6OmIl𘎱ZiZ_ۚD"S \>01} 믳L2Z./a\S L /+ sR& a#_Jrb W_6X_ZosWIENDB`plugins-1.5/generic/gnupgplugin/lineeditwidget.cpp000066400000000000000000000050131336777360500225400ustar00rootroot00000000000000#include #include #include #include #include #include "lineeditwidget.h" LineEditWidget::LineEditWidget(QWidget *parent) : QLineEdit(parent) , _layout(new QHBoxLayout()) , _popup(0) , _optimalLength(0) { _layout->setSpacing(0); _layout->setContentsMargins(1, 3, 2, 3); _layout->addWidget(new QWidget()); setLayout(_layout); setContentsMargins(0, 0, 0, 0); installEventFilter(this); } LineEditWidget::~LineEditWidget() { _toolbuttons.clear(); } QSize LineEditWidget::sizeHint() const { QSize size; size = QLineEdit::sizeHint(); int width = 0; if(_optimalLength) { width += fontMetrics().width("0") * _optimalLength; } else { width += size.width(); } width += textMargins().right(); size.setWidth(width); return size; } void LineEditWidget::showEvent(QShowEvent *e) { // Width of standard QLineEdit plus extended tool buttons int width = 0; for(int i = _toolbuttons.size() - 1; i >= 0; i--) { width += _toolbuttons[i]->width(); } setTextMargins(0, 0, width, 0); QLineEdit::showEvent(e); } bool LineEditWidget::eventFilter(QObject *o, QEvent *e) { return QLineEdit::eventFilter(o, e); } void LineEditWidget::setRxValidator(const QString &str) { _rxValidator = str; if (str.isEmpty()) { return; } QRegExp rx(str); QRegExpValidator *validator = new QRegExpValidator(rx, this); setValidator(validator); } void LineEditWidget::addWidget(QWidget *w) { _toolbuttons << w; _layout->addWidget(w); } void LineEditWidget::setPopup(QWidget *w) { if(_popup) { delete _popup; _popup = 0; } _popup = new QFrame(this); _popup->setWindowFlags(Qt::Popup); _popup->setFrameStyle(QFrame::StyledPanel); _popup->setAttribute(Qt::WA_WindowPropagation); _popup->setAttribute(Qt::WA_X11NetWmWindowTypeCombo); QBoxLayout *layout = new QBoxLayout(QBoxLayout::TopToBottom); layout->setSpacing(0); layout->setMargin(0); layout->setContentsMargins(0, 0, 0, 0); layout->addWidget(w); _popup->setLayout(layout); } void LineEditWidget::showPopup() { _popup->adjustSize(); _popup->move(mapToGlobal(QPoint(width() - _popup->geometry().width(), height()))); QSize size = qApp->desktop()->size(); QRect rect = _popup->geometry(); // if widget is beyond edge of display if(rect.right() > size.width()) { rect.moveRight(size.width()); } if(rect.bottom() > size.height()) { rect.moveBottom(size.height()); } _popup->move(rect.topLeft()); _popup->show(); } void LineEditWidget::hidePopup() { if (_popup->isVisible()) { _popup->hide(); } } plugins-1.5/generic/gnupgplugin/lineeditwidget.h000066400000000000000000000021601336777360500222050ustar00rootroot00000000000000#ifndef LINEEDITWIDGET_H #define LINEEDITWIDGET_H #include #include #include class QFrame; class QHBoxLayout; class LineEditWidget : public QLineEdit { Q_OBJECT Q_PROPERTY(int optimalLength READ optimalLenth WRITE setOptimalLength) Q_PROPERTY(QString rxValidator READ rxValidator WRITE setRxValidator) public: explicit LineEditWidget(QWidget *parent = 0); ~LineEditWidget(); // reimplemented QSize sizeHint() const; void showEvent(QShowEvent *e); bool eventFilter(QObject *o, QEvent *e); // Properties int optimalLenth() const { return _optimalLength; } void setOptimalLength(int optimalLength) { _optimalLength = optimalLength; } QString rxValidator() const { return _rxValidator; } void setRxValidator(const QString &str); protected: void addWidget(QWidget *w); void setPopup(QWidget* w); QFrame *popup() const { return _popup; }; protected slots: virtual void showPopup(); virtual void hidePopup(); private: QHBoxLayout *_layout; QList _toolbuttons; QFrame *_popup; // Properties int _optimalLength; QString _rxValidator; }; #endif // LINEEDITWIDGET_H plugins-1.5/generic/gnupgplugin/model.cpp000066400000000000000000000117551336777360500206510ustar00rootroot00000000000000/* * model.cpp - key view model * * Copyright (C) 2013 Ivan Romanov * * 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 "model.h" #include "gpgprocess.h" #include inline QString epochToHuman(const QString &seconds) { qint64 ms = seconds.toLongLong() * 1000; if (ms) return QDateTime::fromMSecsSinceEpoch(ms).date().toString(); else return QString(); } inline QString uidToName(const QString &uid) { if (uid.contains('(')) { return uid.section('(', 0, 0).trimmed(); } else if (uid.contains('<')) { return uid.section('<', 0, 0).trimmed(); } else { return uid.trimmed(); } } inline QString uidToEMail(const QString &uid) { if (uid.contains('<') && uid.contains('>')) { return uid.section('<', 1).section('>', 0, 0).trimmed(); } else return ""; } inline QString uidToComment(const QString &uid) { if (uid.contains('(') && uid.contains(')')) { return uid.section('(', 1).section(')', 0, 0).trimmed(); } else { return ""; } } QList parseLine(const QString &line) { QList rows; // Used ID QString uid = line.section(':', 9, 9); // Type rows << new QStandardItem(line.section(':', 0, 0)); // Name rows << new QStandardItem(uidToName(uid)); // E-mail rows << new QStandardItem(uidToEMail(uid)); // Creation key time in human readable format rows << new QStandardItem(epochToHuman(line.section(':', 5, 5))); // Expiration time rows << new QStandardItem(epochToHuman(line.section(':', 6, 6))); // Length of key rows << new QStandardItem(line.section(':', 2, 2)); // Comment rows << new QStandardItem(uidToComment(uid)); // Algorithm int alg = line.section(':', 3, 3).toInt(); switch(alg) { case 1: rows << new QStandardItem("RSA"); break; case 16: rows << new QStandardItem("ELG-E"); break; case 17: rows << new QStandardItem("DSA"); break; case 18: rows << new QStandardItem("ECC"); break; default: rows << new QStandardItem(""); break; } // Short ID rows << new QStandardItem(line.section(':', 4, 4).right(8)); // Fingerprint rows << new QStandardItem(""); return rows; } Model::Model(QObject *parent) : QStandardItemModel(parent) { } void Model::listKeys() { clear(); static QStringList headerLabels; if (headerLabels.isEmpty()) { for (int i = 0; i < Model::Count; ++i) { headerLabels << QString(); } headerLabels[Type] = tr("Type"); headerLabels[Name] = tr("Name"); headerLabels[Email] = tr("E-Mail"); headerLabels[Created] = tr("Created"); headerLabels[Expiration] = tr("Expiration"); headerLabels[Length] = tr("Length"); headerLabels[Comment] = tr("Comment"); headerLabels[Algorithm] = tr("Algorithm"); headerLabels[ShortId] = tr("Short ID"); headerLabels[Fingerprint] = tr("Fingerprint"); } setHorizontalHeaderLabels(headerLabels); QStringList arguments; arguments << "--with-fingerprint" << "--list-secret-keys" << "--with-colons" << "--fixed-list-mode"; GpgProcess process; process.start(arguments); process.waitForFinished(); QString keysRaw = QString::fromUtf8(process.readAll()); arguments.clear(); arguments << "--with-fingerprint" << "--list-public-keys" << "--with-colons" << "--fixed-list-mode"; process.start(arguments); process.waitForFinished(); keysRaw += QString::fromUtf8(process.readAll()); showKeys(keysRaw); } void Model::showKeys(const QString &keysRaw) { QStringList list = keysRaw.split("\n"); QList lastRow; QList row; QStringList secretKeys; foreach (QString line, list) { QString type = line.section(':', 0, 0); if (type == "pub" || type == "sec") { row = parseLine(line); // Show only secret part for keys pair if (type == "sec") { secretKeys << row.at(Algorithm)->text(); } else if (secretKeys.indexOf(row.at(ShortId)->text()) >= 0) { lastRow.clear(); continue; } appendRow(row); lastRow = row; } else if ((type == "uid" || type == "ssb" || type == "sub") && !lastRow.isEmpty()) { row = parseLine(line); lastRow.first()->appendRow(row); if (lastRow.first()->rowCount() == 1) { lastRow.at(Name)->setText(row.at(Name)->text()); lastRow.at(Email)->setText(row.at(Email)->text()); lastRow.at(Comment)->setText(row.at(Comment)->text()); } } else if (type == "fpr") { row.at(Fingerprint)->setText(line.section(':', Fingerprint, Fingerprint)); } } } plugins-1.5/generic/gnupgplugin/model.h000066400000000000000000000023751336777360500203140ustar00rootroot00000000000000/* * model.h - key view model * * Copyright (C) 2013 Ivan Romanov * * 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. */ #ifndef MODEL_H #define MODEL_H #include class Model : public QStandardItemModel { Q_OBJECT public: enum Columns { Type, Name, Email, Created, Expiration, Length, Comment, Algorithm, ShortId, Fingerprint, Count, // Trick to count items in enum First = 0, Last = Count - 1 }; Model(QObject *parent = 0); public slots: void listKeys(); private: void showKeys(const QString &keysRaw); }; #endif // MODEL_H plugins-1.5/generic/gnupgplugin/options.cpp000066400000000000000000000240171336777360500212370ustar00rootroot00000000000000/* * options.cpp - plugin widget * * Copyright (C) 2013 Ivan Romanov * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include "options.h" #include "ui_options.h" #include "model.h" #include "gpgprocess.h" #include "addkeydlg.h" #include "optionaccessinghost.h" Options::Options(QWidget *parent) : QWidget(parent) , ui(new Ui::Options) { ui->setupUi(this); Model *model = new Model(this); ui->keys->setModel(model); updateKeys(); // Import key QAction *action; QMenu *menu = new QMenu(this); action = menu->addAction(trUtf8("from file")); connect(action, SIGNAL(triggered()), SLOT(importKeyFromFile())); action = menu->addAction(trUtf8("from clipboard")); connect(action, SIGNAL(triggered()), SLOT(importKeyFromClipboard())); ui->btnImport->setMenu(menu); // Export key menu = new QMenu(this); action = menu->addAction(trUtf8("to file")); connect(action, SIGNAL(triggered()), SLOT(exportKeyToFile())); ui->btnExport->addAction(action); action = menu->addAction(trUtf8("to clipboard")); connect(action, SIGNAL(triggered()), SLOT(exportKeyToClipboard())); ui->btnExport->setMenu(menu); } Options::~Options() { delete ui; } void Options::update() { } void Options::loadSettings() { ui->chkAutoImport->setChecked(_optionHost->getPluginOption("auto-import", true).toBool()); ui->chkHideKeyMessage->setChecked(_optionHost->getPluginOption("hide-key-message", true).toBool()); } void Options::saveSettings() { _optionHost->setPluginOption("auto-import", ui->chkAutoImport->isChecked()); _optionHost->setPluginOption("hide-key-message", ui->chkHideKeyMessage->isChecked()); } void Options::addKey() { AddKeyDlg dlg(this); if (dlg.exec() == QDialog::Rejected) { return; } QString key; QString type, stype, length, name, comment, email, expiration, pass; switch (dlg.type()) { case 0: type = stype = "RSA"; break; case 1: type = "DSA"; stype = "ELG-E"; break; case 2: type = "DSA"; break; case 3: type = "RSA"; break; } length = QString::number(dlg.length()); name = dlg.name(); comment = dlg.comment(); email = dlg.email(); expiration = dlg.expiration().isValid() ? dlg.expiration().toString(Qt::ISODate) : "0"; pass = dlg.pass(); key += QString("Key-Type: %1\n").arg(type); key += QString("Key-Length: %2\n").arg(length); if (!stype.isEmpty()) { key += QString("Subkey-Type: %1\n").arg(stype); key += QString("Subkey-Length: %2\n").arg(length); } if (!name.isEmpty()) { key += QString("Name-Real: %1\n").arg(name); } if (!comment.isEmpty()) { key += QString("Name-Comment: %1\n").arg(comment); } if (!email.isEmpty()) { key += QString("Name-Email: %1\n").arg(email); } key += QString("Expire-Date: %1\n").arg(expiration); if (!pass.isEmpty()) { key += QString("Passphrase: %1\n").arg(pass); } key += "%commit\n"; QProgressDialog waitingDlg("", trUtf8("Cancel"), 0, 0, this); QLabel progressTextLabel(trUtf8( "Please wait!
" "We need to generate a lot of random bytes. It is a good idea to perform " "some other action (type on the keyboard, move the mouse, utilize the " "disks) during the prime generation; this gives the random number " "generator a better chance to gain enough entropy."), &waitingDlg); progressTextLabel.setAlignment(Qt::AlignHCenter); progressTextLabel.setWordWrap(true); waitingDlg.setLabel(&progressTextLabel); QProgressBar progressBar(&waitingDlg); progressBar.setAlignment(Qt::AlignHCenter); progressBar.setMinimum(0); progressBar.setMaximum(0); waitingDlg.setBar(&progressBar); waitingDlg.setWindowModality(Qt::WindowModal); waitingDlg.setWindowTitle(trUtf8("Key pair generating")); waitingDlg.show(); GpgProcess gpg; QStringList arguments; arguments << "--batch" << "--gen-key"; gpg.start(arguments); gpg.waitForStarted(); gpg.write(key.toUtf8()); gpg.closeWriteChannel(); while (gpg.state() == QProcess::Running) { gpg.waitForFinished(1); if (waitingDlg.wasCanceled()) { gpg.terminate(); break; } qApp->processEvents(); } updateKeys(); } void Options::removeKey() { QItemSelectionModel *selModel = ui->keys->selectionModel(); if (!selModel->hasSelection()) { return; } QModelIndexList indexes = selModel->selectedIndexes(); QModelIndexList pkeys; // Key IDs foreach (QModelIndex index, indexes) { // Every selection contains all columns. Need to work only with first if (index.column() > 0) { continue; } // Choose only primary keys QModelIndex pIndex = index; if (index.parent().isValid()) { pIndex = index.parent(); } if (pkeys.indexOf(pIndex) < 0) { pkeys << pIndex; } } if (!pkeys.isEmpty()) { if (QMessageBox::question(this, tr("Delete"), tr("Do you want to delete the selected keys?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::No) { return; } } // Remove primary keys foreach (QModelIndex key, pkeys) { GpgProcess gpg; QStringList arguments; arguments << "--yes" << "--batch" << "--delete-secret-and-public-key" << "0x" + key.sibling(key.row(), Model::Fingerprint).data().toString(); gpg.start(arguments); gpg.waitForFinished(); } updateKeys(); } void Options::importKeyFromFile() { QFileDialog dlg(this); dlg.setFileMode(QFileDialog::ExistingFiles); QStringList nameFilters; nameFilters << trUtf8("ASCII (*.asc)") << trUtf8("All files (*)"); dlg.setNameFilters(nameFilters); if (dlg.exec() == QDialog::Rejected) { return; } QStringList allFiles = dlg.selectedFiles(); foreach (QString filename, allFiles) { GpgProcess gpg; QStringList arguments; arguments << "--batch" << "--import" << filename; gpg.start(arguments); gpg.waitForFinished(); } updateKeys(); } void Options::exportKeyToFile() { QItemSelectionModel *selModel = ui->keys->selectionModel(); if (!selModel->hasSelection()) { return; } QModelIndexList indexes = selModel->selectedIndexes(); QModelIndexList pkeys; // Key IDs foreach (QModelIndex index, indexes) { // Every selection contains all columns. Need to work only with first if (index.column() > 0) { continue; } // Choose only primary keys QModelIndex pIndex = index; if (index.parent().isValid()) { pIndex = index.parent(); } if (pkeys.indexOf(pIndex) < 0) { pkeys << pIndex; } } // Remove primary keys foreach (QModelIndex key, pkeys) { QString filename = key.sibling(key.row(), 1).data().toString() + " " + key.sibling(key.row(), 2).data().toString() + ".asc"; QFileDialog dlg(this); dlg.setAcceptMode(QFileDialog::AcceptSave); dlg.setFileMode(QFileDialog::AnyFile); QStringList nameFilters; nameFilters << trUtf8("ASCII (*.asc)"); dlg.setNameFilters(nameFilters); dlg.selectFile(filename); if (dlg.exec() == QDialog::Rejected) { break; } filename = dlg.selectedFiles().first(); if (filename.right(4) != ".asc") { filename += ".asc"; } GpgProcess gpg; QStringList arguments; QString fingerprint = "0x" + key.sibling(key.row(), 8).data().toString(); arguments << "--output" << filename << "--armor" << "--export" << fingerprint; gpg.start(arguments); gpg.waitForFinished(); } } void Options::importKeyFromClipboard() { QClipboard *clipboard = QApplication::clipboard(); QString key = clipboard->text().trimmed(); if (!key.startsWith("-----BEGIN PGP PUBLIC KEY BLOCK-----") || !key.endsWith("-----END PGP PUBLIC KEY BLOCK-----")) { return; } GpgProcess gpg; QStringList arguments; arguments << "--batch" << "--import"; gpg.start(arguments); gpg.waitForStarted(); gpg.write(key.toUtf8()); gpg.closeWriteChannel(); gpg.waitForFinished(); updateKeys(); } void Options::exportKeyToClipboard() { QItemSelectionModel *selModel = ui->keys->selectionModel(); if (!selModel->hasSelection()) { return; } QModelIndexList indexes = selModel->selectedIndexes(); QModelIndexList pkeys; // Key IDs foreach (QModelIndex index, indexes) { // Every selection contains all columns. Need to work only with first if (index.column() > 0) { continue; } // Choose only primary keys QModelIndex pIndex = index; if (index.parent().isValid()) { pIndex = index.parent(); } if (pkeys.indexOf(pIndex) < 0) { pkeys << pIndex; } } // Remove primary keys QString strKey = ""; foreach (QModelIndex key, pkeys) { GpgProcess gpg; QStringList arguments; QString fingerprint = "0x" + key.sibling(key.row(), 8).data().toString(); arguments << "--armor" << "--export" << fingerprint; gpg.start(arguments); gpg.waitForFinished(); strKey += QString::fromUtf8(gpg.readAllStandardOutput()); } QClipboard *clipboard = QApplication::clipboard(); clipboard->setText(strKey.toUtf8().trimmed()); } void Options::showInfo() { GpgProcess gpg; QString info; QMessageBox::Icon icon; if (gpg.info(info)) { icon = QMessageBox::Information; } else { icon = QMessageBox::Critical; } QMessageBox box(icon, trUtf8("GnuPG info"), info, QMessageBox::Ok, this); box.exec(); } void Options::updateKeys() { qobject_cast(ui->keys->model())->listKeys(); int columns = ui->keys->model()->columnCount(); for (int i = 0; i < columns; i++) { ui->keys->resizeColumnToContents(i); } } plugins-1.5/generic/gnupgplugin/options.h000066400000000000000000000027431336777360500207060ustar00rootroot00000000000000/* * options.h - plugin widget * * Copyright (C) 2013 Ivan Romanov * * 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. */ #ifndef OPTIONS_H #define OPTIONS_H #include class GPGProc; class OptionAccessingHost; namespace Ui { class Options; } class Options : public QWidget { Q_OBJECT public: explicit Options(QWidget *parent = 0); ~Options(); void update(); void setOptionAccessingHost(OptionAccessingHost* host) { _optionHost = host; } void loadSettings(); void saveSettings(); public slots: void addKey(); void removeKey(); void importKeyFromFile(); void importKeyFromClipboard(); void exportKeyToFile(); void exportKeyToClipboard(); void showInfo(); void updateKeys(); private: Ui::Options *ui; GPGProc *_gpgProc; OptionAccessingHost* _optionHost; }; #endif // OPTIONS_H plugins-1.5/generic/gnupgplugin/options.ui000066400000000000000000000115421336777360500210710ustar00rootroot00000000000000 Options 0 0 490 451 Form 0 0 Manager QAbstractItemView::NoEditTriggers QAbstractItemView::ExtendedSelection true false Add Remove Import Export Qt::Vertical 20 40 Info Settings Auto import a key from the message body Filter the message with a key Qt::Vertical 20 40 btnAdd clicked() Options addKey() 437 51 490 6 btnRemove clicked() Options removeKey() 421 77 492 80 btnInfo clicked() Options showInfo() 431 420 492 418 addKey() removeKey() showInfo() plugins-1.5/generic/gnupgplugin/resources.qrc000066400000000000000000000002731336777360500215570ustar00rootroot00000000000000 calendar.png clean.png key.png gnupg.png plugins-1.5/generic/gomokugameplugin/000077500000000000000000000000001336777360500200475ustar00rootroot00000000000000plugins-1.5/generic/gomokugameplugin/CMakeLists.txt000066400000000000000000000032621336777360500226120ustar00rootroot00000000000000unset(_HDRS) unset(_UIS) unset(_SRCS) unset(_RSCS) unset(PLUGIN) set( PLUGIN gomokugameplugin ) project(${PLUGIN}) cmake_minimum_required(VERSION 3.1.0) set( CMAKE_AUTOMOC TRUE ) IF( NOT WIN32 ) set( LIB_SUFFIX "" CACHE STRING "Define suffix of directory name (32/64)" ) set( PLUGINS_PATH "lib${LIB_SUFFIX}/psi-plus/plugins" CACHE STRING "Install suffix for plugins" ) ELSE() set( PLUGINS_PATH "psi-plus/plugins" CACHE STRING "Install suffix for plugins" ) ENDIF() add_definitions( -DQT_PLUGIN -DHAVE_QT5 ) include_directories( ${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ../../include . ) set( _HDRS ${PLUGIN}.h pluginwindow.h boardview.h boardmodel.h boarddelegate.h gameelement.h invatedialog.h gamesessions.h common.h options.h gamemodel.h ) set( _SRCS ${PLUGIN}.cpp pluginwindow.cpp boardview.cpp boardmodel.cpp boarddelegate.cpp gameelement.cpp invatedialog.cpp gamesessions.cpp options.cpp gamemodel.cpp ) set( _UIS pluginwindow.ui invatedialog.ui invitationdialog.ui options.ui ) set( _RSCS ${PLUGIN}.qrc ) find_package( Qt5 COMPONENTS Widgets Xml REQUIRED ) set(QT_DEPLIBS Qt5::Widgets Qt5::Xml ) qt5_wrap_ui(UIS ${_UIS}) qt5_add_resources(RSCS ${_RSCS}) add_library( ${PLUGIN} MODULE ${_SRCS} ${UIS} ${RSCS} ) target_link_libraries( ${PLUGIN} ${QT_DEPLIBS} ) if( UNIX AND NOT( APPLE OR CYGWIN ) ) install( TARGETS ${PLUGIN} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} ) endif() if( WIN32 ) install( TARGETS ${PLUGIN} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} ) endif() plugins-1.5/generic/gomokugameplugin/boarddelegate.cpp000066400000000000000000000150771336777360500233470ustar00rootroot00000000000000/* * boarddelegate.cpp - Gomoku Game plugin * Copyright (C) 2011 Aleksey Andreev * * 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. * * You can also redistribute and/or modify this program under the * terms of the Psi License, specified in the accompanied COPYING * file, as published by the Psi Project; either dated January 1st, * 2005, 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include "boarddelegate.h" #include "common.h" using namespace GomokuGame; BoardPixmaps::BoardPixmaps(QObject *parent) : QObject(parent), width(-1), height(-1), w_cnt(1), h_cnt(1) { boardPixmap = new QPixmap(":/gomokugameplugin/goban1"); } BoardPixmaps::~BoardPixmaps() { clearPix(); delete boardPixmap; } void BoardPixmaps::clearPix() { QList values = scaledPixmap.values(); while (!values.isEmpty()) { delete values.takeLast(); } scaledPixmap.clear(); } QPixmap *BoardPixmaps::getBoardPixmap(int x, int y, double w, double h) { if (w != width || h != height) { width = w; height = h; clearPix(); } QPixmap *scPixmap = scaledPixmap.value(0, NULL); if (scPixmap == NULL) { // Масштабирование картинки под целое количество единиц ширины и высоты scPixmap = new QPixmap(); w_cnt = boardPixmap->width() / w; h_cnt = boardPixmap->height() / h; // Тут можно ограничить максимальное количество кусков //-- *scPixmap = boardPixmap->scaled(QSize(w_cnt * w, h_cnt * h), Qt::IgnoreAspectRatio, Qt::FastTransformation); scaledPixmap[0] = scPixmap; } int curr_key = (x % w_cnt) * 100 + (y % h_cnt) + 1; QPixmap *scPixmap2 = scaledPixmap.value(curr_key, NULL); if (scPixmap2 == NULL) { // Вырезаем необходимый кусок картинки scPixmap2 = new QPixmap(); int xpixpos = (x % w_cnt) * w; int ypixpos = (y % h_cnt) * h; *scPixmap2 = scPixmap->copy(xpixpos, ypixpos, w, h); scaledPixmap[curr_key] = scPixmap2; } return scPixmap2; } // ----------------------------------------------------------------------------- BoardDelegate::BoardDelegate(BoardModel *model, QObject *parent) : QItemDelegate(parent), model_(model), skin(0), pixmaps(NULL) { } void BoardDelegate::setSkin(int skin_num) { if (skin != skin_num) { skin = skin_num; if (skin == 0) { if (pixmaps != NULL) { delete pixmaps; pixmaps = NULL; } } else { if (pixmaps == NULL) { pixmaps = new BoardPixmaps(this); } } } } void BoardDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { // Проверки if (!index.isValid()) return; int row = index.row(); if (row <= 0 || row >= model_->rowCount() - 1) return; int col = index.column(); if (col <= 0 || col >= model_->columnCount() - 1) return; painter->save(); QRectF rect(option.rect); // Отрисовка фона if (skin == 0) { QBrush fill_brush(QColor(220, 179, 92, 255), Qt::SolidPattern); painter->fillRect(rect, fill_brush); } else { QPixmap *pixmap = pixmaps->getBoardPixmap(col - 1, row - 1, rect.width(), rect.height()); painter->drawPixmap(rect, *pixmap, pixmap->rect()); } QBrush brush1(Qt::SolidPattern); int row_min = 2; int row_max = model_->rowCount() - 3; int col_min = 2; int col_max = model_->columnCount() - 3; if (row >= row_min && row <= row_max && col >= col_min && col <= col_max) { // Отрисовка центральных линий qreal x = rect.left() + rect.width() / 2.0; qreal y = rect.top() + rect.height() / 2.0; painter->setPen(Qt::darkGray); painter->drawLine(rect.left(), y - 1, rect.right(), y - 1); painter->drawLine(x - 1, rect.top(), x - 1, rect.bottom()); painter->setPen(Qt::lightGray); painter->drawLine(rect.left(), y, rect.right(), y); painter->drawLine(x, rect.top(), x, rect.bottom()); // Отрисовка разделителя if (row == row_min || col == col_min || row == row_max || col == col_max) { painter->setPen(Qt::black); if (row == row_min) { painter->drawLine(rect.topLeft(), rect.topRight()); } else if (row == row_max) { QPointF p1 = rect.bottomLeft(); p1.setY(p1.y() - 1.0); QPointF p2 = rect.bottomRight(); p2.setY(p2.y() - 1.0); painter->drawLine(p1, p2); } if (col == col_min) { painter->drawLine(rect.topLeft(), rect.bottomLeft()); } else if (col == col_max) { QPointF p1 = rect.topRight(); p1.setX(p1.x() - 1); QPointF p2 = rect.bottomRight(); p2.setX(p2.x() - 1); painter->drawLine(p1, p2); } } if (model_->selectX == col && model_->selectY == row) { brush1.setColor(QColor(0, 255, 0, 64)); painter->fillRect(rect, brush1); } // Отрисовка если курсор мыши над клеткой if (option.state & QStyle::State_MouseOver) { brush1.setColor(QColor(0, 0, 0, 32)); painter->fillRect(rect, brush1); } rect.setWidth(rect.width() - 1); rect.setHeight(rect.height() - 1); // Отрисовка если клетка выбрана if (option.state & QStyle::State_Selected) { QRectF rect2(rect); rect2.setLeft(rect2.left() + 1); rect2.setTop(rect2.top() + 1); rect2.setWidth(rect2.width() - 1); rect2.setHeight(rect2.height() - 1); painter->setPen(Qt::gray); painter->drawRect(rect2); } // Отрисовка элемента const GameElement *el = model_->getGameElement(col, row); if (el) { el->paint(painter, rect); } } else { // Рисуем координаты if ((row == 1 || row == model_->columnCount() - 2) && col >= 2 && col <= model_->columnCount() - 3) { // Буквы QString text = horHeaderString.at(col - 2); painter->drawText(rect, Qt::AlignCenter,text, 0); } else if ((col == 1 || model_->rowCount() - 2) && row >= 2 && row <= model_->rowCount() - 3) { // Цифры QString text = QString::number(row - 1); painter->drawText(rect, Qt::AlignCenter,text, 0); } } painter->restore(); } plugins-1.5/generic/gomokugameplugin/boarddelegate.h000066400000000000000000000035131336777360500230040ustar00rootroot00000000000000/* * boarddelegate.h - Gomoku Game plugin * Copyright (C) 2011 Aleksey Andreev * * 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. * * You can also redistribute and/or modify this program under the * terms of the Psi License, specified in the accompanied COPYING * file, as published by the Psi Project; either dated January 1st, * 2005, 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef BOARDDELEGATE_H #define BOARDDELEGATE_H #include #include #include "boardmodel.h" namespace GomokuGame { class BoardPixmaps : public QObject { public: BoardPixmaps(QObject *parent = 0); ~BoardPixmaps(); void clearPix(); QPixmap *getBoardPixmap(int, int, double, double); private: QPixmap *boardPixmap; double width; double height; int w_cnt; int h_cnt; QHash scaledPixmap; }; class BoardDelegate : public QItemDelegate { Q_OBJECT public: explicit BoardDelegate(BoardModel *model, QObject *parent = 0); void setSkin(int skin_num); virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; private: BoardModel *model_; int skin; BoardPixmaps *pixmaps; }; } #endif // BOARDDELEGATE_H plugins-1.5/generic/gomokugameplugin/boardmodel.cpp000066400000000000000000000137401336777360500226700ustar00rootroot00000000000000/* * boardmodel.cpp - Gomoku Game plugin * Copyright (C) 2011 Aleksey Andreev * * 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. * * You can also redistribute and/or modify this program under the * terms of the Psi License, specified in the accompanied COPYING * file, as published by the Psi Project; either dated January 1st, * 2005, 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include "boardmodel.h" #include "common.h" using namespace GomokuGame; BoardModel::BoardModel(QObject *parent) : QAbstractTableModel(parent), selectX(-1), selectY(-1), columnCount_(0), rowCount_(0), gameModel(NULL) { } BoardModel::~BoardModel() { if (gameModel) delete gameModel; } void BoardModel::init(GameModel *gm) { if (gameModel) delete gameModel; gameModel = gm; selectX = -1; selectY = -1; setHeaders(); beginResetModel(); endResetModel(); connect(gameModel, SIGNAL(statusUpdated(GameModel::GameStatus)), this, SIGNAL(changeGameStatus(GameModel::GameStatus))); emit changeGameStatus(gm->gameStatus()); } void BoardModel::setHeaders() { rowCount_ = gameModel->boardSizeY() + 4; columnCount_ = gameModel->boardSizeX() + 4; } Qt::ItemFlags BoardModel::flags(const QModelIndex &index) const { Qt::ItemFlags flags = Qt::NoItemFlags | Qt::ItemIsEnabled; int row = index.row(); if (row < 2 || row > rowCount_ - 2) { return flags; } int col = index.column(); if (col < 2 || col > columnCount_ - 2) { return flags; } return (flags | Qt::ItemIsSelectable); } QVariant BoardModel::headerData(int /*section*/, Qt::Orientation /*orientation*/, int /*role*/) const { return QVariant(); } QVariant BoardModel::data(const QModelIndex & /*index*/, int /*role*/) const { return QVariant(); } bool BoardModel::setData(const QModelIndex &index, const QVariant &/*value*/, int role) { if (index.isValid() && role == Qt::DisplayRole) { emit dataChanged(index, index); return true; } return false; } int BoardModel::rowCount(const QModelIndex & /*parent*/) const { return rowCount_; } int BoardModel::columnCount(const QModelIndex & /*parent*/) const { return columnCount_; } const GameElement *BoardModel::getGameElement(int x, int y) { return gameModel->getElement(x - 2, y - 2); } /** * Был щелчек мышью по доске */ bool BoardModel::clickToBoard(QModelIndex index) { if (index.isValid()) { int x = index.column() - 2; int y = index.row() - 2; if (setElementToBoard(x, y, true)) { emit setupElement(x, y); return true; } } return false; } /** * Пришел ход от оппонента */ bool BoardModel::opponentTurn(int x, int y) { if (setElementToBoard(x, y, false)) { // После хода оппонента в модели производится проверка на проигрыш и ничью. GameModel::GameStatus status = gameModel->gameStatus(); if (status == GameModel::StatusLose) emit lose(); // Сообщаем оппоненту что мы проиграли else if (status == GameModel::StatusDraw) emit draw(); // Сообщаем оппоненту об ничьей return true; } gameModel->setErrorStatus(); return false; } void BoardModel::setAccept() { gameModel->accept(); } void BoardModel::setError() { gameModel->setErrorStatus(); } void BoardModel::setClose() { gameModel->breakGame(); } void BoardModel::setWin() { gameModel->setWin(); } void BoardModel::opponentDraw() { gameModel->setDraw(); } /** * Мы сдались. Сообщаем оппоненту и самому себе. */ void BoardModel::setResign() { emit lose(); gameModel->setLose(); } /** * Добавляет новый элемент (в данном случае камень) в игровую модель и обновляет игровую доску * Возвращает true в случае удачи. */ bool BoardModel::setElementToBoard(int x, int y, bool local) { if (gameModel->doTurn(x, y, local)) { const QModelIndex mi = index(y + 2, x + 2); // Offset for margin emit dataChanged(mi, mi); return true; } const QString msg = gameModel->getLastError(); if (!msg.isEmpty()) emit doPopup(msg); return false; } /** * Возвращает номер ожидаемого хода */ int BoardModel::turnNum() { return (gameModel->turnsCount() + 1); } /** * Переключает цвет игрока (предусмотрено международными правилами) */ bool BoardModel::doSwitchColor(bool local) { if (gameModel->doSwitchColor(local)) { if (local) emit switchColor(); return true; } return false; } /** * Сохраняет состояние игры в строку */ QString BoardModel::saveToString() const { return gameModel->toString(); } /** * Устанавливает новые координаты подсвечиваемого объекта и дает команды на перисовку */ void BoardModel::setSelect(int x, int y) { int old_x = selectX; int old_y = selectY; selectX = x + 2; selectY = y + 2; if (old_x != selectX || old_y != selectY) { if (old_x != -1 && old_y != -1) { QModelIndex idx = index(old_y, old_x); emit dataChanged(idx, idx); } QModelIndex idx = index(selectY, selectX); emit dataChanged(idx, idx); } } GameElement::ElementType BoardModel::myElementType() const { if (gameModel) { return gameModel->myElementType(); } return GameElement::TypeNone; } plugins-1.5/generic/gomokugameplugin/boardmodel.h000066400000000000000000000052101336777360500223260ustar00rootroot00000000000000/* * boardmodel.h - Gomoku Game plugin * Copyright (C) 2011 Aleksey Andreev * * 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. * * You can also redistribute and/or modify this program under the * terms of the Psi License, specified in the accompanied COPYING * file, as published by the Psi Project; either dated January 1st, * 2005, 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef BOARDMODEL_H #define BOARDMODEL_H #include #include #include "gameelement.h" #include "gamemodel.h" namespace GomokuGame { class BoardModel : public QAbstractTableModel { Q_OBJECT public: explicit BoardModel(QObject *parent = 0); ~BoardModel(); void init(GameModel *gameModel); virtual Qt::ItemFlags flags(const QModelIndex & index) const; virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; virtual bool setData(const QModelIndex &index, const QVariant &value, int role); virtual int rowCount(const QModelIndex & parent = QModelIndex()) const; virtual int columnCount(const QModelIndex & parent = QModelIndex()) const; // -- const GameElement *getGameElement(int x, int y); bool clickToBoard(QModelIndex index); bool opponentTurn(int x, int y); void setAccept(); void setError(); void setClose(); void setWin(); void opponentDraw(); void setResign(); int turnNum(); bool doSwitchColor(bool local); QString saveToString() const; void setSelect(int x, int y); GameElement::ElementType myElementType() const; public: int selectX; int selectY; private: int columnCount_; int rowCount_; GameModel *gameModel; private: void setHeaders(); bool setElementToBoard(int x, int y, bool my_element); signals: void changeGameStatus(GameModel::GameStatus); void setupElement(int x, int y); void lose(); void draw(); void switchColor(); void doPopup(const QString); void playSound(const QString); }; } #endif // BOARDMODEL_H plugins-1.5/generic/gomokugameplugin/boardview.cpp000066400000000000000000000052171336777360500225420ustar00rootroot00000000000000/* * boardview.cpp - Gomoku Game plugin * Copyright (C) 2011 Aleksey Andreev * * 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. * * You can also redistribute and/or modify this program under the * terms of the Psi License, specified in the accompanied COPYING * file, as published by the Psi Project; either dated January 1st, * 2005, 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include "boardview.h" using namespace GomokuGame; BoardView::BoardView(QWidget *parent) : QTableView(parent), model_(NULL) { } void BoardView::setModel(QAbstractItemModel *model) { QTableView::setModel(model); model_ = static_cast(model); } void BoardView::resizeEvent(QResizeEvent * /*event*/) { setCellsSize(); } void BoardView::mouseReleaseEvent(QMouseEvent * /*event*/) { QModelIndex index = currentIndex(); if (index.isValid()) { model_->clickToBoard(index); } } void BoardView::setCellsSize() { if (!model_) return; int row_cnt = model()->rowCount() - 2; int col_cnt = model()->columnCount() - 2; int board_width = width() - verticalHeader()->width() - (lineWidth() + midLineWidth()) * 2; int board_height = height() - horizontalHeader()->height() - (lineWidth() + midLineWidth()) * 2; board_width -= 4; board_height -= 4; // Запас для гарантии отсутствия прокрутки int cell_width = board_width / (row_cnt) - 1; int cell_heigt = board_height / (col_cnt) - 1; int cell_size = qMin(cell_width, cell_heigt); int h_margin = board_width - cell_size * col_cnt; if (h_margin < 0) h_margin = 0; h_margin /= 2; int v_margin = board_height - cell_size * row_cnt; if (v_margin < 0) v_margin = 0; v_margin /= 2; horizontalHeader()->setDefaultSectionSize(cell_size); verticalHeader()->setDefaultSectionSize(cell_size); horizontalHeader()->resizeSection(0, h_margin); horizontalHeader()->resizeSection(col_cnt + 1, h_margin); verticalHeader()->resizeSection(0, v_margin); verticalHeader()->resizeSection(row_cnt + 1, v_margin); } plugins-1.5/generic/gomokugameplugin/boardview.h000066400000000000000000000027561336777360500222140ustar00rootroot00000000000000/* * boardview.h - Gomoku Game plugin * Copyright (C) 2011 Aleksey Andreev * * 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. * * You can also redistribute and/or modify this program under the * terms of the Psi License, specified in the accompanied COPYING * file, as published by the Psi Project; either dated January 1st, * 2005, 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef BOARDVIEW_H #define BOARDVIEW_H #include #include "boardmodel.h" namespace GomokuGame { class BoardView : public QTableView { Q_OBJECT public: explicit BoardView(QWidget *parent = 0); void setModel(QAbstractItemModel * model); private: BoardModel *model_; virtual void resizeEvent(QResizeEvent *event); virtual void mouseReleaseEvent(QMouseEvent *event); void setCellsSize(); signals: private slots: }; } #endif // BOARDVIEW_H plugins-1.5/generic/gomokugameplugin/changelog.txt000066400000000000000000000133651336777360500225470ustar00rootroot000000000000002013-09-02 v0.1.2 - taurus * Использовать слово Groupchat вместо Conference 2013-08-13 v0.1.1 - taurus + Иконка плагина 2011-07-10 v0.1.0 + добавлена фильтрация файлов в диалогах загрузки и сохранения игры + перед загрузкой игры показывается диалог с информацией об игре. Добавлена возможность отказаться от загрузки игры отправленной оппонентом + в сохраненные игры добавлена информация о смене цвета и контрольная сумма. + при загрузке игры так же загружается история ходов * исправлен формат вывода истории ходов * исправлена обработка ошибочных станз * редизайн кода 2011-05-15 v0.0.8 * исправлена ошибка вызывающая крах плагина при отказе от игры. Проявляется только при наличии открытой игровой доски того же контакта * исправлена ошибка из за которой невозможно отправить приглашение при определенных условиях * исправлена ошибка, позволяющая ходить за пределы игровой доски * увеличина ширина виджета, отображающего ходы * исправлена станза отклонения приглашения если статус dnd 2011-04-18 v0.0.7 * частично переписан код менеджера игровых сессий * снова подсвечивается последний ход + прирост идентификатора в iq запросах теперь случайный * изменено поведение игры при сдаче. Сдаться можно не на своем ходу. Востановлена возможность сдачи после загрузки игры + добавлена возможность начать новую игру не закрывая игровую доску через пункт меню "New game" * если доска полностью заполнена камнями и при этом ряд не составлен, объявляется ничья + добавлен тестовый режим смены оформления игровой доски. Выбор не запоминается * несколько мелких исправлений 2011-03-27 v0.0.6 * изменена модель игровой доски. необходимо для гибкости управления поведением и оформлением в будущем + теперь координаты доски отображаются с двух сторон, доска выравнивается по центру * исправлена ошибка отрисовки выдеденной клетки на игровой доске * исправлены опечатки на вкладке с настройками плагина 2011-03-27 v0.0.5 * отключена возможность сдаться после завершения игры * запрещена отправка приглашения если не закрыта доска предыдущей завершенной игры 2011-02-22 v0.0.4 * исправлены опечатки на вкладке с настройками плагина 2011-02-22 v0.0.3 * исправлена ошибка, приводящая к тому, что невозможно отправить повторное приглашение * исправлена ссылка на вики плагина * небольшие изменения игровой доски, в частности для адресации по горизонтали теперь используются буквы + добавлена подсказка для первого хода + добавлена подсветка последнего/выбранного хода + добавлены опции сохранения позиции и размера окна * мелкие исправления и улучшения 2011-02-17 v0.0.2 * исправлены правила игры в части смены цвета игроком. теперь смена цвета предлагается после третьего хода + добавлены звуки + добавлена возможность автоматически отклонять приглашения для статуса "Не беспокоить" и для игры через конференцию (опционально) + вызов плагина добавлен в меню ростера * увеличен размер окна игры по умолчанию * мелкие улучшения 2011-02-15 v0.0.1 ! initial version Данный плагин позволяет вам играть с вашими знакомыми в игру Гомоку. Реализована разновидность правил "Международное гомоку". О правилах и самой игре можно прочитать тут: http://ru.wikipedia.org/wiki/Гомоку Для передачи команд используются обычные сообщения, поэтому плагин будет работать везде, где у вас есть возможность выйти в онлайн. plugins-1.5/generic/gomokugameplugin/common.h000066400000000000000000000023721336777360500215140ustar00rootroot00000000000000/* * common.h - Gomoku Game plugin * Copyright (C) 2011 Aleksey Andreev * * 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. * * You can also redistribute and/or modify this program under the * terms of the Psi License, specified in the accompanied COPYING * file, as published by the Psi Project; either dated January 1st, * 2005, 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef COMMON_H #define COMMON_H #include #define constPluginName "Gomoku Game Plugin" #define constProtoType "gomoku" const QString horHeaderString = "ABCDEFGHJKLMNOP"; #endif // COMMON_H plugins-1.5/generic/gomokugameplugin/gameelement.cpp000066400000000000000000000055031336777360500230410ustar00rootroot00000000000000/* * gameelement.cpp - Gomoku Game plugin * Copyright (C) 2011 Aleksey Andreev * * 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. * * You can also redistribute and/or modify this program under the * terms of the Psi License, specified in the accompanied COPYING * file, as published by the Psi Project; either dated January 1st, * 2005, 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include "gameelement.h" GameElement::GameElement(ElementType type, int x, int y) : type_(type) , posX(x) , posY(y) { ++GameElement::usesCnt; } GameElement::GameElement(const GameElement *from) { if (this == from) return; type_ = from->type(); posX = from->x(); posY = from->y(); } GameElement::~GameElement() { --GameElement::usesCnt; if (!GameElement::usesCnt) { if (GameElement::blackstonePixmap) { delete GameElement::blackstonePixmap; GameElement::blackstonePixmap = NULL; } if (GameElement::whitestonePixmap) { delete GameElement::whitestonePixmap; GameElement::whitestonePixmap = NULL; } } } int GameElement::x() const { return posX; } int GameElement::y() const { return posY; } GameElement::ElementType GameElement::type() const { return type_; } void GameElement::paint(QPainter *painter, const QRectF &rect) const { if (type_ == TypeNone) return; painter->save(); painter->setRenderHint(QPainter::Antialiasing, true); painter->setRenderHint(QPainter::SmoothPixmapTransform, true); QPixmap *pixmap; if (type_ == TypeBlack) { pixmap = getBlackstonePixmap(); } else { pixmap = getWhitestonePixmap(); } if (pixmap) { painter->drawPixmap(rect, *pixmap, pixmap->rect()); } painter->restore(); } int GameElement::usesCnt = 0; QPixmap *GameElement::blackstonePixmap = NULL; QPixmap *GameElement::getBlackstonePixmap() const { if (!GameElement::blackstonePixmap) { GameElement::blackstonePixmap = new QPixmap(":/gomokugameplugin/black-stone"); } return GameElement::blackstonePixmap; } QPixmap *GameElement::whitestonePixmap = NULL; QPixmap *GameElement::getWhitestonePixmap() const { if (!GameElement::whitestonePixmap) { GameElement::whitestonePixmap = new QPixmap(":/gomokugameplugin/white-stone"); } return GameElement::whitestonePixmap; } plugins-1.5/generic/gomokugameplugin/gameelement.h000066400000000000000000000032351336777360500225060ustar00rootroot00000000000000/* * gameelement.h - Gomoku Game plugin * Copyright (C) 2011 Aleksey Andreev * * 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. * * You can also redistribute and/or modify this program under the * terms of the Psi License, specified in the accompanied COPYING * file, as published by the Psi Project; either dated January 1st, * 2005, 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef GAMEELEMENT_H #define GAMEELEMENT_H #include class GameElement { public: enum ElementType { TypeNone, TypeBlack, TypeWhite }; GameElement(ElementType type, int x, int y); GameElement(const GameElement *from); ~GameElement(); int x() const; int y() const; ElementType type() const; void paint(QPainter *painter, const QRectF &rect) const; private: ElementType type_; int posX; int posY; static int usesCnt; static QPixmap *blackstonePixmap; static QPixmap *whitestonePixmap; private: QPixmap *getBlackstonePixmap() const; QPixmap *getWhitestonePixmap() const; }; #endif // GAMEELEMENT_H plugins-1.5/generic/gomokugameplugin/gamemodel.cpp000066400000000000000000000400461336777360500225110ustar00rootroot00000000000000/* * gamemodel.cpp - Gomoku Game plugin * Copyright (C) 2011 Aleksey Andreev * * 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. * * You can also redistribute and/or modify this program under the * terms of the Psi License, specified in the accompanied COPYING * file, as published by the Psi Project; either dated January 1st, * 2005, 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include #include "gamemodel.h" GameModel::GameModel(GameElement::ElementType my, int row_count, int col_count, QObject *parent) : QObject(parent), valid_(true), status_(StatusNone), accepted_(true), turnsCount_(0), blackCount_(0), whiteCount_(0), my_el(my), switchColor(false), boardSizeX_(col_count), boardSizeY_(row_count), loadedTurnsCount(0), chksum(ChksumNone) { if (my_el == GameElement::TypeNone || col_count <= 0 || row_count <= 0) valid_ = false; selectGameStatus(); emit statusUpdated(status_); } GameModel::GameModel(const QString load_str, bool local, QObject *parent) : QObject(parent), valid_(false), status_(StatusNone), accepted_(!local), turnsCount_(0), blackCount_(0), whiteCount_(0), my_el(GameElement::TypeNone), switchColor(false), boardSizeX_(0), boardSizeY_(0), loadedTurnsCount(0), chksum(ChksumNone) { QStringList loadList = load_str.split(";"); if (loadList.isEmpty() || loadList.takeFirst() != "gomokugameplugin.save.1") return; bool res = true; int black_cnt = 0; int white_cnt = 0; int maxCol = 0; int maxRow = 0; while (!loadList.isEmpty()) { QString str1 = loadList.takeFirst().trimmed(); if (str1.isEmpty()) continue; QStringList setStrList = str1.split(":", QString::SkipEmptyParts); if (setStrList.size() != 2) { res = false; break; } QString parName = setStrList.at(0).trimmed().toLower(); if (parName == "element") { QStringList elemPar = setStrList.at(1).trimmed().split(","); if (elemPar.size() != 3) { res = false; break; } bool fOk; int x = elemPar.at(0).toInt(&fOk); if (!fOk || x < 0) { res = false; break; } if (x > maxCol) maxCol = x; int y = elemPar.at(1).toInt(&fOk); if (!fOk || y < 0) { res = false; break; } if (y > maxRow) maxRow = y; GameElement::ElementType type; if (elemPar.at(2) == "black") { type = GameElement::TypeBlack; ++black_cnt; } else if (elemPar.at(2) == "white") { type = GameElement::TypeWhite; ++white_cnt; } else { res = false; break; } GameElement *el = new GameElement(type, x, y); if (!el) { res = false; break; } elementsList.push_back(el); } else if (parName == "color") { if (setStrList.at(1) == "black") { my_el = GameElement::TypeBlack; } else if (setStrList.at(1) == "white") { my_el = GameElement::TypeWhite; } } else if (parName == "status") { if (setStrList.at(1) == "error") { status_ = StatusError; } else if (setStrList.at(1) == "win") { status_ = (local) ? StatusWin : StatusLose; } else if (setStrList.at(1) == "lose") { status_ = (local) ? StatusLose : StatusWin; } else if (setStrList.at(1) == "draw") { status_ = StatusDraw; } } else if (parName == "switchcolor") { if (setStrList.at(1) == "yes") switchColor = true; } } boardSizeX_ = 15; boardSizeY_ = 15; int delta = black_cnt - white_cnt; if (!res || delta < 0 || delta > 1 || my_el == GameElement::TypeNone || maxRow >= boardSizeY_ || maxCol >= boardSizeX_) { // Неудачная загрузка, удаляем созданные объекты while (!elementsList.isEmpty()) delete elementsList.takeFirst(); return; } if (!local) { if (my_el == GameElement::TypeBlack) my_el = GameElement::TypeWhite; else my_el = GameElement::TypeBlack; } blackCount_ = black_cnt; whiteCount_ = white_cnt; turnsCount_ = black_cnt + white_cnt; if (switchColor) turnsCount_++; loadedTurnsCount = turnsCount_; const int pos = load_str.indexOf("sha1sum:", 0, Qt::CaseInsensitive); if (pos != -1) { const QString sum_str = QCryptographicHash::hash(load_str.left(pos).toLatin1().data(), QCryptographicHash::Sha1).toHex().constData(); if (sum_str == load_str.mid(pos + 8, 40)) chksum = ChksumCorrect; else chksum = ChksumIncorrect; } valid_ = true; if (status_ == StatusNone) selectGameStatus(); emit statusUpdated(gameStatus()); return; } GameModel::~GameModel() { while (!elementsList.isEmpty()) delete elementsList.takeFirst(); } GameModel::GameStatus GameModel::gameStatus() const { if (!accepted_) return StatusWaitingAccept; return status_; } bool GameModel::selectGameStatus() { if (status_ == StatusError || status_ == StatusBreak || status_ == StatusWin || status_ == StatusLose || status_ == StatusDraw) return false; // Эти статусы автоматически не меняются. GameStatus new_status; if (!accepted_) { new_status = StatusWaitingAccept; } else if (turnsCount_ == 0) { new_status = (my_el == GameElement::TypeBlack) ? StatusWaitingLocalAction : StatusWaitingOpponent; } else { bool my_last_turn = (elementsList.last()->type() == my_el); //if (turnsCount_ == 4 && switchColor) // my_last_turn = !my_last_turn; new_status = (my_last_turn) ? StatusWaitingOpponent : StatusWaitingLocalAction; } if (status_ != new_status) { status_ = new_status; return true; } return false; } const GameElement *GameModel::getElement(int x, int y) const { const int idx = getElementIndex(x, y); if (idx == -1) return NULL; return elementsList.at(idx); } int GameModel::getElementIndex(int x, int y) const { if (x >= 0 && x < boardSizeX_ && y >= 0 && y < boardSizeY_) { for (int i = 0, cnt = elementsList.size(); i < cnt; i++) { const GameElement *el = elementsList.at(i); if (el->x() == x && el->y() == y) return i; } } return -1; } /** * Добавление нового хода в модель */ bool GameModel::doTurn(int x, int y, bool local) { lastErrorStr = QString(); // Проверяем возможность хода if (!accepted_) return false; // Нет подтверждения if (local) { if (status_ != GameModel::StatusWaitingLocalAction) return false; // Не наш ход } else { if (status_ != GameModel::StatusWaitingOpponent) return false; } if (x < 0 || x >= boardSizeX_ || y < 0 || y >= boardSizeY_) return false; if (turnsCount_ == 0 && (x != 7 || y != 7)) { lastErrorStr = tr("The first turn can be only H8."); return false; } if (getElementIndex(x, y) != -1) return false; // Место уже занято // Определяем цвет элемента GameElement::ElementType type; if (local) type = my_el; else type = (my_el == GameElement::TypeBlack) ? GameElement::TypeWhite : GameElement::TypeBlack; // Create new element GameElement *el = new GameElement(type, x, y); if (!el) return false; // Insert new element into game model elementsList.push_back(el); if (type == GameElement::TypeBlack) blackCount_++; else whiteCount_++; turnsCount_++; if (local) { accepted_ = false; } else { if (checkForLose()) { status_ = StatusLose; emit statusUpdated(status_); } else if (checkForDraw()) { status_ = StatusDraw; emit statusUpdated(status_); } } if (selectGameStatus()) emit statusUpdated(status_); return true; } /** * Переключение цвета камней на 4м ходу */ bool GameModel::doSwitchColor(bool local) { lastErrorStr = QString(); // Проверяем возможность хода if (!accepted_) return false; // Нет подтверждения if (local) { if (status_ != GameModel::StatusWaitingLocalAction) return false; // Не наш ход } else { if (status_ != GameModel::StatusWaitingOpponent) return false; } if (turnsCount_ != 3) return false; // Переключаем my_el = (my_el == GameElement::TypeBlack) ? GameElement::TypeWhite : GameElement::TypeBlack; switchColor = true; accepted_ = !local; turnsCount_++; if (selectGameStatus()) emit statusUpdated(status_); return true; } bool GameModel::accept() { if (!accepted_) { accepted_ = true; selectGameStatus(); emit statusUpdated(status_); return true; } return false; } void GameModel::setErrorStatus() { if (status_ != StatusError) { status_ = StatusError; accepted_ = true; emit statusUpdated(status_); } } void GameModel::breakGame() { if (status_ == StatusWaitingAccept || status_ == StatusWaitingLocalAction || status_ == StatusWaitingOpponent) { status_ = StatusBreak; accepted_ = true; emit statusUpdated(status_); } } void GameModel::setWin() { if (status_ == StatusWaitingAccept || status_ == StatusWaitingLocalAction || status_ == StatusWaitingOpponent) { status_ = StatusWin; accepted_ = true; emit statusUpdated(status_); } } void GameModel::setDraw() { if (status_ == StatusWaitingAccept || status_ == StatusWaitingLocalAction || status_ == StatusWaitingOpponent) { status_ = StatusDraw; accepted_ = true; emit statusUpdated(status_); } } void GameModel::setLose() { if (status_ == StatusWaitingAccept || status_ == StatusWaitingLocalAction || status_ == StatusWaitingOpponent) { status_ = StatusLose; accepted_ = true; emit statusUpdated(status_); } } bool GameModel::checkForLose() { int max_x = boardSizeX_ - 1; int max_y = boardSizeY_ - 1; int last_x = lastX(); int last_y = lastY(); if (last_x < 0 || last_x >= max_x || last_y < 0 || last_y >= max_y) return false; if (turnsCount_ == 4 && switchColor) return false; // Переключение цвета, незачем проверять // Проверяем вверх int vert = 1; if (last_y > 0) { int tmp_y = last_y - 1; for (; tmp_y >= 0; tmp_y--) { const GameElement *el = getElement(last_x, tmp_y); if (!el || el->type() == my_el) break; } vert = last_y - tmp_y; if (vert > 5) return false; } // Проверяем вниз if (last_y < max_y) { int tmp_y = last_y + 1; for (; tmp_y <= max_y; tmp_y++) { const GameElement *el = getElement(last_x, tmp_y); if (!el || el->type() == my_el) break; } vert += tmp_y - last_y - 1; if (vert > 5) return false; } // Слева int horiz = 1; if (last_x > 0) { int tmp_x = last_x - 1; for (; tmp_x >= 0; tmp_x--) { const GameElement *el = getElement(tmp_x, last_y); if (!el || el->type() == my_el) break; } horiz = last_x - tmp_x; if (horiz > 5) return false; } // Справа if (last_x < max_x) { int tmp_x = last_x + 1; for (; tmp_x <= max_x; tmp_x++) { const GameElement *el = getElement(tmp_x, last_y); if (!el || el->type() == my_el) break; } horiz += tmp_x - last_x - 1; if (horiz > 5) return false; } // Лево вверх int diag1 = 1; if (last_x > 0 && last_y > 0) { int tmp_y = last_y - 1; for (int tmp_x = last_x - 1; tmp_x >= 0; tmp_x--) { const GameElement *el = getElement(tmp_x, tmp_y); if (!el || el->type() == my_el) break; tmp_y--; if (tmp_y < 0) break; } diag1 = last_y - tmp_y; if (diag1 > 5) return false; } // Право вниз if (last_x < max_x && last_y < max_y) { int tmp_y = last_y + 1; for (int tmp_x = last_x + 1; tmp_x <= max_x; tmp_x++) { const GameElement *el = getElement(tmp_x, tmp_y); if (!el || el->type() == my_el) break; tmp_y++; if (tmp_y > max_y) break; } diag1 += tmp_y - last_y - 1; if (diag1 > 5) return false; } // Право верх int diag2 = 1; if (last_x < max_x && last_y > 0) { int tmp_y = last_y - 1; for (int tmp_x = last_x + 1; tmp_x <= max_x; tmp_x++) { const GameElement *el = getElement(tmp_x, tmp_y); if (!el || el->type() == my_el) break; tmp_y--; if (tmp_y < 0) break; } diag2 = last_y - tmp_y; if (diag2 > 5) return false; } // Лево низ if (last_x > 0 && last_y < max_y) { int tmp_y = last_y + 1; for (int tmp_x = last_x - 1; tmp_x >= 0; tmp_x--) { const GameElement *el = getElement(tmp_x, tmp_y); if (!el || el->type() == my_el) break; tmp_y++; if (tmp_y > max_y) break; } diag2 += tmp_y - last_y - 1; if (diag2 > 5) return false; } if (vert == 5 || horiz == 5 || diag1 == 5 || diag2 == 5) return true; return false; } bool GameModel::checkForDraw() { // Если доска заполнена return (turnsCount_ == (boardSizeX_ * boardSizeY_)); } QString GameModel::toString() const { QString res_str = "gomokugameplugin.save.1;\n"; GameElement *lastEl = NULL; if (!elementsList.isEmpty()) lastEl = elementsList.last(); foreach (GameElement *el, elementsList) { if (el == lastEl && !accepted_) continue; // Не сохраняем не подтвержденное res_str.append(QString("Element:%1,%2,%3;\n") .arg(el->x()).arg(el->y()) .arg((el->type() == GameElement::TypeBlack) ? "black" : "white")); } res_str.append(QString("SwitchColor:%1;\n").arg((switchColor) ? "yes" : "no")); res_str.append(QString("Color:%1;\n").arg((my_el == GameElement::TypeBlack) ? "black" : "white")); res_str.append(QString("Status:%1;\n").arg(statusString())); QString tmp_str = res_str; QString crcStr = QCryptographicHash::hash(tmp_str.replace("\n", "").toLatin1().data(), QCryptographicHash::Sha1).toHex().constData(); res_str.append(QString("Sha1Sum:%1;\n").arg(crcStr)); return res_str; } int GameModel::lastX() const { if (elementsList.isEmpty()) return -1; return elementsList.last()->x(); } int GameModel::lastY() const { if (elementsList.isEmpty()) return -1; return elementsList.last()->y(); } /** * Возвращает статус игры в виде строки */ QString GameModel::statusString() const { QString stat_str; if (status_ == StatusError) { stat_str = "error"; } else if (status_ == StatusWin) { stat_str = "win"; } else if (status_ == StatusLose) { stat_str = "lose"; } else if (status_ == StatusDraw) { stat_str = "draw"; } else { stat_str = "play"; } return stat_str; } bool GameModel::isLoaded() const { return (loadedTurnsCount > 0 && loadedTurnsCount == turnsCount_); } QString GameModel::gameInfo() const { QString text = "Game info:\n"; text.append(QString("Black stones: %1\n").arg(blackCount_)); text.append(QString("White stones: %1\n").arg(whiteCount_)); text.append(QString("Your color: %1\n").arg((my_el == GameElement::TypeBlack) ? "black" : "white")); text.append(QString("SwitchColor: %1\n").arg((switchColor) ? "yes" : "no")); text.append(QString("Game status: %1").arg(statusString())); if (isLoaded()) { QString chksumStr; if (chksum == ChksumNone) { chksumStr = "none"; } else if (chksum == ChksumCorrect) { chksumStr = "correct"; } else if (chksum == ChksumIncorrect) { chksumStr = "!!! incorrect !!!"; } text.append(QString("\nCheck sum: %1").arg(chksumStr)); } return text; } /** * Информация о ходе. Информация возвращается в структуре */ GameModel::TurnInfo GameModel::turnInfo(int num) const { TurnInfo res; res.x = 0; res.y = 0; res.my = GameElement::TypeNone; if (num > 0 && num <= turnsCount_) { int i = num - 1; bool myInvert = false; if (switchColor) { if (num >= 4) { i--; if (num == 4) { // Этот ход - переключение цвета res.x = -1; res.y = -1; res.my = (elementsList.at(i)->type() == my_el); return res; } } else { myInvert = true; } } const GameElement *el = elementsList.at(i); res.x = el->x(); res.y = el->y(); res.my = (elementsList.at(i)->type() == my_el); if (myInvert) res.my = !res.my; } return res; } plugins-1.5/generic/gomokugameplugin/gamemodel.h000066400000000000000000000057661336777360500221700ustar00rootroot00000000000000/* * gamemodel.h - Gomoku Game plugin * Copyright (C) 2011 Aleksey Andreev * * 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. * * You can also redistribute and/or modify this program under the * terms of the Psi License, specified in the accompanied COPYING * file, as published by the Psi Project; either dated January 1st, * 2005, 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef GAMEMODEL_H #define GAMEMODEL_H #include #include "gameelement.h" class GameModel : public QObject { Q_OBJECT public: enum GameStatus { StatusNone, StatusWaitingLocalAction, StatusWaitingAccept, StatusWaitingOpponent, StatusWin, StatusLose, StatusDraw, StatusBreak, // Игра прервана. Например закрытие доски оппонента StatusError }; struct TurnInfo { int x; int y; bool my; }; GameModel(GameElement::ElementType my, int row_count, int col_count, QObject *parent = 0); GameModel(const QString load_str, bool local, QObject *parent = 0); ~GameModel(); bool isValid() const {return valid_;} GameStatus gameStatus() const; int boardSizeX() const {return boardSizeX_;}; int boardSizeY() const {return boardSizeY_;}; int turnsCount() const {return turnsCount_;}; GameElement::ElementType myElementType() const {return my_el;}; const GameElement *getElement(int x, int y) const; bool doTurn(int x, int y, bool local); bool doSwitchColor(bool local); bool accept(); void setErrorStatus(); QString getLastError() const {return lastErrorStr;}; void breakGame(); void setWin(); void setDraw(); void setLose(); QString toString() const; int lastX() const; int lastY() const; bool isLoaded() const; QString gameInfo() const; TurnInfo turnInfo(int num) const; private: enum ChksumStatus { ChksumNone, ChksumCorrect, ChksumIncorrect }; bool valid_; GameStatus status_; bool accepted_; int turnsCount_; int blackCount_; int whiteCount_; GameElement::ElementType my_el; bool switchColor; int boardSizeX_; int boardSizeY_; int loadedTurnsCount; ChksumStatus chksum; QString lastErrorStr; QList elementsList; private: bool selectGameStatus(); int getElementIndex(int x, int y) const; bool checkForLose(); bool checkForDraw(); QString statusString() const; signals: void statusUpdated(GameModel::GameStatus); public slots: }; #endif // GAMEMODEL_H plugins-1.5/generic/gomokugameplugin/gamesessions.cpp000066400000000000000000000657131336777360500232670ustar00rootroot00000000000000/* * gamesessions.cpp - Gomoku Game plugin * Copyright (C) 2011 Aleksey Andreev * * 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. * * You can also redistribute and/or modify this program under the * terms of the Psi License, specified in the accompanied COPYING * file, as published by the Psi Project; either dated January 1st, * 2005, 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include "gamesessions.h" #include "invatedialog.h" #include "common.h" #include "options.h" GameSessions::GameSessions(QObject *parent) : QObject(parent), stanzaId(qrand() % 10000), // Получаем псевдослучайный стартовый id errorStr("") { gameSessions.clear(); } GameSessions::~GameSessions() { while (!gameSessions.isEmpty()) { GameSession gs = gameSessions.first(); if (!gs.wnd.isNull()) { gs.wnd.data()->close(); // В результате сигнала будет удалена соотв. запись сессии. } else { gameSessions.removeFirst(); } } } GameSessions *GameSessions::instance_ = NULL; GameSessions *GameSessions::instance() { if (!instance_) { instance_ = new GameSessions(); } return instance_; } void GameSessions::reset() { if (instance_) { delete instance_; instance_ = NULL; } } /** * Обработка входящей станзы и вызов соответствующих методов */ bool GameSessions::processIncomingIqStanza(int account, const QDomElement &xml, const QString &acc_status, bool conf_priv) { const QString iq_type = xml.attribute("type"); if(iq_type == "set") { QDomElement childElem = xml.firstChildElement("create"); if(!childElem.isNull() && childElem.attribute("xmlns") == "games:board" && childElem.attribute("type") == constProtoType) { const QString from = xml.attribute("from"); const QString id = xml.attribute("id"); const QString protoId = childElem.attribute("id"); if (protoId != constProtoId) { sendErrorIq(account, from, id, "Incorrect protocol version"); return true; } Options *options = Options::instance(); if ((options->getOption(constDndDisable).toBool() && acc_status == "dnd") || (options->getOption(constConfDisable).toBool() && conf_priv)) { sendErrorIq(account, from, id, ""); return true; } if (incomingInvitation(account, from, childElem.attribute("color"), id)) { emit doInviteEvent(account, from, tr("%1: Invitation from %2").arg(constPluginName).arg(from), this, SLOT(showInvitation(QString))); } return true; } if (activeCount() == 0) // Нет ни одной активной игровой сессии (наиболее вероятный исход большую часть времени) return false; // Остальные проверки бессмысленны childElem = xml.firstChildElement("turn"); if (!childElem.isNull() && childElem.attribute("xmlns") == "games:board" && childElem.attribute("type") == constProtoType) { const QString from = xml.attribute("from"); const QString id = xml.attribute("id"); const QString protoId = childElem.attribute("id"); if (protoId != constProtoId) { sendErrorIq(account, from, id, "Incorrect protocol version"); return true; } QDomElement turnChildElem = childElem.firstChildElement("move"); if (!turnChildElem.isNull()) { return doTurnAction(account, from, id, turnChildElem.attribute("pos")); } turnChildElem = childElem.firstChildElement("resign"); if (!turnChildElem.isNull()) { return youWin(account, from, id); } turnChildElem = childElem.firstChildElement("draw"); if (!turnChildElem.isNull()) { return setDraw(account, from, id); } return false; } childElem = xml.firstChildElement("close"); if (!childElem.isNull() && childElem.attribute("xmlns") == "games:board" && childElem.attribute("type") == constProtoType) { const QString from = xml.attribute("from"); const QString id = xml.attribute("id"); const QString protoId = childElem.attribute("id"); if (protoId != constProtoId) { sendErrorIq(account, from, id, "Incorrect protocol version"); return true; } return closeRemoteGameBoard(account, from, id); } childElem = xml.firstChildElement("load"); if (!childElem.isNull() && childElem.attribute("xmlns") == "games:board" && childElem.attribute("type") == constProtoType) { const QString from = xml.attribute("from"); const QString id = xml.attribute("id"); const QString protoId = childElem.attribute("id"); if (protoId != constProtoId) { sendErrorIq(account, from, id, "Incorrect protocol version"); return true; } return remoteLoad(account, from, id, childElem.text()); } } else if (iq_type == "result") { if (doResult(account, xml.attribute("from"), xml.attribute("id"))) { return true; } } else if (iq_type == "error") { if (doReject(account, xml.attribute("from"), xml.attribute("id"))) { return true; } } return false; } /** * Вызов окна для приглашения к игре */ void GameSessions::invite(int account, const QString jid, const QStringList res_list, QWidget *parent) { InvateDialog *dialog = new InvateDialog(account, jid, res_list, parent); connect(dialog, SIGNAL(acceptGame(int, QString, QString)), this, SLOT(sendInvite(int, QString, QString))); connect(dialog, SIGNAL(rejectGame(int,QString)), this, SLOT(cancelInvite(int, QString))); dialog->show(); } /** * Отправка приглашения поиграть выбранному джиду */ void GameSessions::sendInvite(int account, QString full_jid, QString element) { QString new_id = newId(true); if (!regGameSession(StatusInviteSend, account, full_jid, new_id, element)) { emit doPopup(getLastError()); return; } emit sendStanza(account, QString("") .arg(XML::escapeString(full_jid)) .arg(new_id) .arg(constProtoId) .arg(constProtoType) .arg(element)); } /** * Отмена приглашения. Мы передумали приглашать. :) */ void GameSessions::cancelInvite(int account, QString full_jid) { removeGameSession(account, full_jid); } /** * Обработка и регистрация входящего приглашения */ bool GameSessions::incomingInvitation(int account, QString from, QString color, QString iq_id) { errorStr = ""; if (color != "black" && color != "white") { errorStr = tr("Incorrect parameters"); } if (regGameSession(StatusInviteInDialog, account, from, iq_id, color)) { const int idx = findGameSessionById(account, iq_id); if (!gameSessions.at(idx).wnd.isNull()) { QMetaObject::invokeMethod(this, "doInviteDialog", Qt::QueuedConnection, Q_ARG(int, account), Q_ARG(QString, from)); return false; } return true; } sendErrorIq(account, from, iq_id, errorStr); return false; } /** * Отображение окна приглашения */ void GameSessions::showInvitation(QString from) { int account_ = 0; const int idx = findGameSessionByJid(from); if (idx == -1 || gameSessions.at(idx).status != StatusInviteInDialog) return; account_ = gameSessions.at(idx).my_acc; doInviteDialog(account_, from); } /** * Отображение формы входящего приглашения. */ void GameSessions::doInviteDialog(int account, QString from) { const int idx = findGameSessionByJid(account, from); if (idx == -1 || gameSessions.at(idx).status != StatusInviteInDialog) return; InvitationDialog *wnd = new InvitationDialog(account, from, gameSessions.at(idx).element, gameSessions.at(idx).last_iq_id, gameSessions.at(idx).wnd); connect(wnd, SIGNAL(accepted(int, QString)), this, SLOT(acceptInvite(int, QString))); connect(wnd, SIGNAL(rejected(int, QString)), this, SLOT(rejectInvite(int, QString))); wnd->show(); } /** * Принимаем приглашение на игру */ void GameSessions::acceptInvite(int account, QString id) { const int idx = findGameSessionById(account, id); if (idx != -1) { if (gameSessions.at(idx).status == StatusInviteInDialog) { QString my_el = (gameSessions.at(idx).element == "black") ? "white" : "black"; gameSessions[idx].element = my_el; startGame(idx); QString stanza = QString("") .arg(XML::escapeString(gameSessions.at(idx).full_jid)) .arg(XML::escapeString(id)) .arg(constProtoType) .arg(constProtoId); emit sendStanza(account, stanza); } else { sendErrorIq(account, gameSessions.at(idx).full_jid, id, getLastError()); emit doPopup(tr("You are already playing!")); } } } /** * Отклоняем приглашение на игру */ void GameSessions::rejectInvite(int account, QString id) { const int idx = findGameSessionById(account, id); if (idx != -1 && gameSessions.at(idx).status == StatusInviteInDialog) { QString jid = gameSessions.at(idx).full_jid; if (gameSessions.at(idx).wnd.isNull()) { removeGameSession(account, jid); } else { gameSessions[idx].status = StatusNone; } sendErrorIq(account, jid, id, getLastError()); } } /** * Инициализация сессии игры и игровой доски */ void GameSessions::startGame(int sess_index) { newId(true); GameSession *sess = &gameSessions[sess_index]; if (sess->wnd.isNull()) { PluginWindow *wnd = new PluginWindow(sess->full_jid, NULL); connect(wnd, SIGNAL(changeGameSession(QString)), this, SLOT(setSessionStatus(QString))); connect(wnd, SIGNAL(closeBoard(bool, int, int, int, int)), this, SLOT(closeGameWindow(bool, int, int, int, int))); connect(wnd, SIGNAL(setElement(int, int)), this, SLOT(sendMove(int, int))); connect(wnd, SIGNAL(switchColor()), this, SLOT(switchColor())); connect(wnd, SIGNAL(accepted()), this, SLOT(sendAccept())); connect(wnd, SIGNAL(error()), this, SLOT(sendError())); connect(wnd, SIGNAL(lose()), this, SLOT(youLose())); connect(wnd, SIGNAL(draw()), this, SLOT(sendDraw())); connect(wnd, SIGNAL(load(QString)), this, SLOT(sendLoad(QString))); connect(wnd, SIGNAL(sendNewInvite()), this, SLOT(newGame())); connect(wnd, SIGNAL(doPopup(const QString)), this, SIGNAL(doPopup(const QString))); connect(wnd, SIGNAL(playSound(const QString)), this, SIGNAL(playSound(const QString))); sess->wnd = wnd; Options *options = Options::instance(); if (options->getOption(constSaveWndPosition).toBool()) { const int topPos = options->getOption(constWindowTop).toInt(); if (topPos > 0) { const int leftPos = options->getOption(constWindowLeft).toInt(); if (leftPos > 0) { sess->wnd->move(leftPos, topPos); } } } if (options->getOption(constSaveWndWidthHeight).toBool()) { const int width = options->getOption(constWindowWidth).toInt(); if (width > 0) { const int height = options->getOption(constWindowHeight).toInt(); if (height > 0) { sess->wnd->resize(width, height); } } } } sess->status = StatusNone; sess->wnd->init(sess->element); sess->wnd->show(); } /** * Обработка iq ответа result для игры. */ bool GameSessions::doResult(int account, QString from, QString iq_id) { if (iq_id.isEmpty()) return false; const int idx = findGameSessionById(account, iq_id); if (idx != -1) { GameSession *sess = &gameSessions[idx]; if (sess->full_jid == from) { if (sess->status == StatusInviteSend) { startGame(idx); return true; } if (sess->status == StatusWaitOpponentAccept) { if (!sess->wnd.isNull()) { QMetaObject::invokeMethod(sess->wnd.data(), "setAccept", Qt::QueuedConnection); return true; } } } } // Видимо не наша станза return false; } /** * Отклонение игры или приглашения на основании iq ответа об ошибке */ bool GameSessions::doReject(int account, QString from, QString iq_id) { if (iq_id.isEmpty()) return false; // Сначала ищем в запросах const int idx = findGameSessionById(account, iq_id); if (idx != -1) { GameSession *sess = &gameSessions[idx]; if (sess->full_jid == from) { SessionStatus status = sess->status; if (status == StatusInviteSend) { if (sess->wnd.isNull()) { removeGameSession(account, from); } else { gameSessions[idx].status = StatusNone; } emit doPopup(tr("From: %1
The game was rejected").arg(from)); return true; } if (!sess->wnd.isNull()) { QMetaObject::invokeMethod(sess->wnd.data(), "setError", Qt::QueuedConnection); emit doPopup(tr("From: %1
Game error.").arg(from)); } else { removeGameSession(account, from); } return true; } } return false; } /** * Обработка действия оппонента */ bool GameSessions::doTurnAction(int account, QString from, QString iq_id, QString value) { if (iq_id.isEmpty()) return false; const int idx = findGameSessionByJid(account, from); if (idx == -1) return false; GameSession *sess = &gameSessions[idx]; if (sess->full_jid == from) { if (!sess->wnd.isNull()) { if (value == "switch-color") { sess->last_iq_id = iq_id; QMetaObject::invokeMethod(sess->wnd.data(), "setSwitchColor", Qt::QueuedConnection); return true; } else { QStringList val_lst = value.split(","); if (val_lst.size() == 2) { bool fOk; int x = val_lst.at(0).trimmed().toInt(&fOk); if (fOk) { int y = val_lst.at(1).trimmed().toInt(&fOk); if (fOk) { sess->last_iq_id = iq_id; QMetaObject::invokeMethod(sess->wnd.data(), "setTurn", Qt::QueuedConnection, Q_ARG(int, x), Q_ARG(int, y)); return true; } } } } } } return false; } /** * Пришло сообщение оппонента о нашей победе */ bool GameSessions::youWin(int account, QString from, QString iq_id) { const int idx = findGameSessionByJid(account, from); if (idx == -1) return false; GameSession *sess = &gameSessions[idx]; sess->last_iq_id = iq_id; // Отправляем подтверждение получения станзы QString stanza = QString("") .arg(XML::escapeString(from)) .arg(XML::escapeString(iq_id)) .arg(constProtoType) .arg(constProtoId); emit sendStanza(account, stanza); // Отправляем окну уведомление о выигрыше QMetaObject::invokeMethod(sess->wnd.data(), "setWin", Qt::QueuedConnection); return true; } /** * Пришло собщение оппонента о ничьей */ bool GameSessions::setDraw(int account, QString from, QString iq_id) { const int idx = findGameSessionByJid(account, from); if (idx != -1) { GameSession *sess = &gameSessions[idx]; sess->last_iq_id = iq_id; // Отправляем подтверждение QString stanza = QString("") .arg(XML::escapeString(from)) .arg(XML::escapeString(iq_id)) .arg(constProtoType) .arg(constProtoId); emit sendStanza(account, stanza); // Уведомляем окно QMetaObject::invokeMethod(sess->wnd.data(), "opponentDraw", Qt::QueuedConnection); return true; } return false; } /** * Оппонент закрыл доску */ bool GameSessions::closeRemoteGameBoard(int account, QString from, QString iq_id) { const int idx = findGameSessionByJid(account, from); if (idx == -1) return false; GameSession *sess = &gameSessions[idx]; if (sess->full_jid != from) return false; sess->last_iq_id = iq_id; QString stanza = QString("") .arg(XML::escapeString(from)) .arg(XML::escapeString(iq_id)) .arg(constProtoType) .arg(constProtoId); emit sendStanza(account, stanza); // Отправляем окну уведомление о закрытии окна QMetaObject::invokeMethod(gameSessions.at(idx).wnd.data(), "setClose", Qt::QueuedConnection); return true; } /** * Оппонент прислал загруженную игру */ bool GameSessions::remoteLoad(int account, QString from, QString iq_id, QString value) { const int idx = findGameSessionByJid(account, from); if (idx == -1) return false; gameSessions[idx].last_iq_id = iq_id; QMetaObject::invokeMethod(gameSessions.at(idx).wnd.data(), "loadRemoteGame", Qt::QueuedConnection, Q_ARG(QString, value)); return true; } /** * Возвращает количество активных игровых сессий */ int GameSessions::activeCount() const { int cnt = 0; for (int i = 0, size = gameSessions.size(); i < size; i++) { if (gameSessions.at(i).status != StatusNone) cnt++; } return cnt; } /** * Установка статуса сессии игры. Статус может устанавливать только сама игра (окно), * т.к. только игра может достоверно знать кто ходит дальше/снова а кто ждет хода и т.д. * Этот статус только сессии передачи данных игры и отвечает за минимальную целостность и безопасность. * Не имеет ни какого отношения к статусу самой игры. */ void GameSessions::setSessionStatus(QString status_str) { // Ищем сессию по отославшему статус объекту const int idx = findGameSessionByWnd(sender()); if (idx == -1) return; // Выставляем статус if (status_str == "wait-opponent-command") { gameSessions[idx].status = StatusWaitOpponentCommand; } else if (status_str == "wait-game-window") { gameSessions[idx].status = StatusWaitGameWindow; } else if (status_str == "wait-opponent-accept") { gameSessions[idx].status = StatusWaitOpponentAccept; } else if (status_str == "none") { gameSessions[idx].status = StatusNone; } } /** * Мы закрыли игровую доску. Посылаем сигнал оппоненту. * Note: Сообщение о закрытии доски отправляется оппоненту только если игра не закончена * и не произошла ошибка (например подмена команды) */ void GameSessions::closeGameWindow(bool send_for_opponent, int top, int left, int width, int height) { const int idx = findGameSessionByWnd(sender()); if (idx == -1) return; if (send_for_opponent) { QString id_str = newId(); gameSessions[idx].last_iq_id = id_str; emit sendStanza(gameSessions.at(idx).my_acc, QString("") .arg(XML::escapeString(gameSessions.at(idx).full_jid)) .arg(id_str) .arg(constProtoId) .arg(constProtoType)); } gameSessions.removeAt(idx); Options *options = Options::instance(); options->setOption(constWindowTop, top); options->setOption(constWindowLeft, left); options->setOption(constWindowWidth, width); options->setOption(constWindowHeight, height); } /** * Мы походили, отправляем станзу нашего хода оппоненту */ void GameSessions::sendMove(int x, int y) { const int idx = findGameSessionByWnd(sender()); if (idx == -1) return; QString id_str = newId(); gameSessions[idx].last_iq_id = id_str; QString stanza = QString("") .arg(XML::escapeString(gameSessions.at(idx).full_jid)) .arg(id_str) .arg(constProtoType) .arg(constProtoId) .arg(x) .arg(y); emit sendStanza(gameSessions.at(idx).my_acc, stanza); } /** * Мы меняем цвет камней */ void GameSessions::switchColor() { const int idx = findGameSessionByWnd(sender()); if (idx == -1) return; QString id_str = newId(); gameSessions[idx].last_iq_id = id_str; QString stanza = QString("") .arg(XML::escapeString(gameSessions.at(idx).full_jid)) .arg(id_str) .arg(constProtoType) .arg(constProtoId); emit sendStanza(gameSessions.at(idx).my_acc, stanza); } /** * Отправка подтверждения сопернику его хода */ void GameSessions::sendAccept() { int idx = findGameSessionByWnd(sender()); if (idx == -1) return; QString to_jid = gameSessions.at(idx).full_jid; if (to_jid.isEmpty()) return; QString stanza = QString("") .arg(XML::escapeString(to_jid)) .arg(XML::escapeString(gameSessions.at(idx).last_iq_id)) .arg(constProtoType) .arg(constProtoId); emit sendStanza(gameSessions.at(idx).my_acc, stanza); } /** * Отправка оппоненту сообщения об ошибке */ void GameSessions::sendError() { int idx = findGameSessionByWnd(sender()); if (idx == -1) return; QString to_jid = gameSessions.at(idx).full_jid; if (to_jid.isEmpty()) return; QString id_str = newId(); gameSessions[idx].last_iq_id = id_str; sendErrorIq(gameSessions.at(idx).my_acc, to_jid, id_str, getLastError()); } /** * Отправка оппоненту запрос на ничью */ void GameSessions::sendDraw() { const int idx = findGameSessionByWnd(sender()); if (idx != -1) { GameSession *sess = &gameSessions[idx]; QString new_id = newId(); sess->last_iq_id = new_id; QString stanza = QString("") .arg(XML::escapeString(sess->full_jid)) .arg(new_id) .arg(constProtoType) .arg(constProtoId); emit sendStanza(sess->my_acc, stanza); } } void GameSessions::youLose() { const int idx = findGameSessionByWnd(sender()); if (idx == -1) return; QString to_str = gameSessions.at(idx).full_jid; if (to_str.isEmpty()) return; QString id_str = newId(); gameSessions[idx].last_iq_id = id_str; QString stanza = QString("") .arg(XML::escapeString(to_str)) .arg(id_str) .arg(constProtoType) .arg(constProtoId); emit sendStanza(gameSessions.at(idx).my_acc, stanza); } /** * Посылаем оппоненту загруженную игру */ void GameSessions::sendLoad(QString save_str) { const int idx = findGameSessionByWnd(sender()); if (idx == -1) return; QString to_str = gameSessions.at(idx).full_jid; if (to_str.isEmpty()) return; QString new_id = newId(); gameSessions[idx].last_iq_id = new_id; QString stanza = QString("%5") .arg(XML::escapeString(to_str)) .arg(new_id) .arg(constProtoId) .arg(constProtoType) .arg(save_str); emit sendStanza(gameSessions.at(idx).my_acc, stanza); } /** * Запрос новой игры через игровую доску */ void GameSessions::newGame() { const int idx = findGameSessionByWnd(sender()); if (idx != -1) { GameSession *sess = &gameSessions[idx]; sess->status = StatusNone; QStringList tmpList = sess->full_jid.split("/"); QString jid = tmpList.takeFirst(); if (tmpList.size() != 0) { invite(sess->my_acc, jid, QStringList(tmpList.join("/")), sess->wnd); } } } // ----------------------------------------- bool GameSessions::regGameSession(SessionStatus status, int account, QString jid, QString id, QString element) { const int cnt = gameSessions.size(); errorStr = ""; for (int i = 0; i < cnt; i++) { GameSession *sess = &gameSessions[i]; if (sess->my_acc == account && sess->full_jid == jid) { if (sess->status != StatusNone) { errorStr = tr("You are already playing!"); return false; } sess->status = status; sess->last_iq_id = id; sess->element = element; return true; } } GameSession session; session.status = status; session.my_acc = account; session.full_jid = jid; session.last_iq_id = id; session.wnd = NULL; session.element = element; gameSessions.push_back(session); return true; } int GameSessions::findGameSessionByWnd(QObject *wnd) const { int res = -1; int cnt = gameSessions.size(); for (int i = 0; i < cnt; i++) { if (gameSessions.at(i).wnd == wnd) { res = i; break; } } return res; } int GameSessions::findGameSessionById(int account, const QString id) const { int res = -1; int cnt = gameSessions.size(); for (int i = 0; i < cnt; i++) { if (gameSessions.at(i).last_iq_id == id && gameSessions.at(i).my_acc == account) { res = i; break; } } return res; } int GameSessions::findGameSessionByJid(int account, QString jid) const { int cnt = gameSessions.size(); for (int i = 0; i < cnt; i++) { if (gameSessions.at(i).my_acc == account) { if (gameSessions.at(i).full_jid == jid) { return i; } } } return -1; } int GameSessions::findGameSessionByJid(QString jid) const { int cnt = gameSessions.size(); for (int i = 0; i < cnt; i++) { if (gameSessions.at(i).full_jid == jid) { return i; } } return -1; } bool GameSessions::removeGameSession(int account, QString jid) { const int idx = findGameSessionByJid(account, jid); if (idx != -1) { QPointer wnd = gameSessions.at(idx).wnd; if (!wnd.isNull()) { delete(wnd); } gameSessions.removeAt(idx); return true; } return false; } void GameSessions::sendErrorIq(int account, QString jid, QString id, const QString &/*err_str*/) { emit sendStanza(account, XML::iqErrorString(jid, id)); } QString XML::escapeString(const QString &str) { #ifdef HAVE_QT5 return str.toHtmlEscaped().replace("\"", """); #else return Qt::escape(str).replace("\"", """); #endif } QString XML::iqErrorString(const QString &jid, const QString &id) { QString stanza = QString("") .arg(XML::escapeString(jid)) .arg(XML::escapeString(id)); return stanza; } QString GameSessions::newId(bool big_add) { stanzaId += 1; if (big_add) { stanzaId += (qrand() % 50) + 4; } else { stanzaId += (qrand() % 5) + 1; } return "gg_" + QString::number(stanzaId); } QString GameSessions::getLastError() const { return errorStr; } plugins-1.5/generic/gomokugameplugin/gamesessions.h000066400000000000000000000111521336777360500227200ustar00rootroot00000000000000/* * gamesessions.h - Gomoku Game plugin * Copyright (C) 2011 Aleksey Andreev * * 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. * * You can also redistribute and/or modify this program under the * terms of the Psi License, specified in the accompanied COPYING * file, as published by the Psi Project; either dated January 1st, * 2005, 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef GAMESESSIONS_H #define GAMESESSIONS_H #include #include #include #include "pluginwindow.h" #define constProtoId "gomoku_01" namespace XML { QString escapeString(const QString &str); QString iqErrorString(const QString &jid, const QString &id); } class GameSessions : public QObject { Q_OBJECT public: explicit GameSessions(QObject *parent = 0); ~GameSessions(); static GameSessions *instance(); static void reset(); bool processIncomingIqStanza(int accont, const QDomElement& xml, const QString &acc_status, bool conf_priv); void invite(int account, const QString jid, const QStringList res_list, QWidget *parent = NULL); int activeCount() const; private: enum SessionStatus { StatusNone, StatusInviteOutDialog, // Окно приглашения с нашей стороны StatusInviteSend, // Отправлено приглашение StatusInviteInDialog, // Окно приглашения к нам (входящий инвайт) StatusWaitOpponentCommand, // Ожидается входящая команда от оппонента (ход, сдача, загрузка игры и т.д.) StatusWaitGameWindow, // Ожидается активность от окна игры StatusWaitOpponentAccept // Ожидается входящий ответ от оппонента на нашу команду (Accept или Error) }; struct GameSession { SessionStatus status; int my_acc; QString full_jid; QPointer wnd; QString last_iq_id; QString element; }; QList gameSessions; int stanzaId; static GameSessions *instance_; QString errorStr; private: bool incomingInvitation(int account, QString from, QString color, QString iq_id); bool doResult(int account, QString from, QString iq_id); bool doReject(int account, QString from, QString iq_id); bool doTurnAction(int account, QString from, QString iq_id, QString value); bool youWin(int account, QString from, QString iq_id); bool setDraw(int account, QString from, QString iq_id); bool closeRemoteGameBoard(int account, QString from, QString iq_id); bool remoteLoad(int account, QString from, QString iq_id, QString value); bool regGameSession(SessionStatus status, int account, QString jid, QString id = "", QString element = ""); void startGame(int sess_index); int findGameSessionByWnd(QObject *wnd) const; int findGameSessionById(int account, const QString id) const; int findGameSessionByJid(int account, const QString jid) const; int findGameSessionByJid(const QString jid) const; bool removeGameSession(int account, const QString jid); QString newId(bool big_add = false); QString getLastError() const; void sendErrorIq(int account, const QString jid, const QString id, const QString &/*err_str*/); private slots: void showInvitation(QString from); void doInviteDialog(int account, QString from); void sendInvite(int account, QString full_jid, QString element); void cancelInvite(int account, QString full_jid); void acceptInvite(int, QString); void rejectInvite(int, QString); void setSessionStatus(QString); void closeGameWindow(bool, int, int, int, int); void sendMove(int, int); void switchColor(); void sendAccept(); void sendError(); void sendDraw(); void youLose(); void sendLoad(QString); void newGame(); signals: void sendStanza(int, QString); void doInviteEvent(int, QString, QString, QObject *, const char *); void doPopup(const QString); void playSound(const QString); }; #endif // GAMESESSIONS_H plugins-1.5/generic/gomokugameplugin/gomokugameplugin.cpp000066400000000000000000000332041336777360500241270ustar00rootroot00000000000000/* * gomokugameplugin.cpp - Gomoku Game plugin * Copyright (C) 2011 Aleksey Andreev * * 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. * * You can also redistribute and/or modify this program under the * terms of the Psi License, specified in the accompanied COPYING * file, as published by the Psi Project; either dated January 1st, * 2005, 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include "gomokugameplugin.h" #include "gamesessions.h" #include "common.h" #include "options.h" #include #define constVersion "0.1.2" #define constShortPluginName "gomokugameplugin" #ifndef HAVE_QT5 Q_EXPORT_PLUGIN(GomokuGamePlugin); #endif GomokuGamePlugin::GomokuGamePlugin(QObject *parent) : QObject(parent), enabled_(false), psiTab(NULL), psiIcon(NULL), psiAccInfo(NULL), psiContactInfo(NULL), psiSender(NULL), psiEvent(NULL), psiSound(NULL), psiPopup(NULL) { Options::psiOptions = NULL; } QString GomokuGamePlugin::name() const { return constPluginName; } QString GomokuGamePlugin::shortName() const { return constShortPluginName; } QString GomokuGamePlugin::version() const { return constVersion; } QWidget *GomokuGamePlugin::options() { QWidget *options = new QWidget; ui_.setupUi(options); ui_.play_error->setIcon(psiIcon->getIcon("psi/play")); ui_.play_finish->setIcon(psiIcon->getIcon("psi/play")); ui_.play_move->setIcon(psiIcon->getIcon("psi/play"));; ui_.play_start->setIcon(psiIcon->getIcon("psi/play")); ui_.select_error->setIcon(psiIcon->getIcon("psi/browse")); ui_.select_finish->setIcon(psiIcon->getIcon("psi/browse")); ui_.select_move->setIcon(psiIcon->getIcon("psi/browse")); ui_.select_start->setIcon(psiIcon->getIcon("psi/browse")); restoreOptions(); connect(ui_.play_error, SIGNAL(clicked()), this, SLOT(testSound())); connect(ui_.play_finish, SIGNAL(clicked()), this, SLOT(testSound())); connect(ui_.play_move, SIGNAL(clicked()), this, SLOT(testSound())); connect(ui_.play_start, SIGNAL(clicked()), this, SLOT(testSound())); connect(ui_.select_error, SIGNAL(clicked()), this, SLOT(getSound())); connect(ui_.select_finish, SIGNAL(clicked()), this, SLOT(getSound())); connect(ui_.select_start, SIGNAL(clicked()), this, SLOT(getSound())); connect(ui_.select_move, SIGNAL(clicked()), this, SLOT(getSound())); return options; } bool GomokuGamePlugin::enable() { if (enabled_) return true; // Грузим иконку плагина QFile file(":/gomokugameplugin/gomoku"); if(file.open(QIODevice::ReadOnly)) { QByteArray ico = file.readAll(); psiIcon->addIcon("gomokugameplugin/gomoku", ico); file.close(); } // Грузим настройки плагина // -- загрузятся по требованию // Создаем соединения с менеджером игровых сессий GameSessions *sessions = GameSessions::instance(); connect(sessions, SIGNAL(sendStanza(int, QString)), this, SLOT(sendGameStanza(int, QString)), Qt::QueuedConnection); connect(sessions, SIGNAL(doPopup(const QString)), this, SLOT(doPopup(const QString)), Qt::QueuedConnection); connect(sessions, SIGNAL(playSound(const QString)), this, SLOT(playSound(const QString)), Qt::QueuedConnection); connect(sessions, SIGNAL(doInviteEvent(int,QString,QString,QObject*,const char*)), this, SLOT(doPsiEvent(int,QString,QString,QObject*,const char*)), Qt::QueuedConnection); // Выставляем флаг и уходим enabled_ = true; return true; } bool GomokuGamePlugin::disable() { enabled_ = false; GameSessions::reset(); Options::reset(); return true; } void GomokuGamePlugin::applyOptions() { Options *options = Options::instance(); options->setOption(constDefSoundSettings, ui_.cb_sound_override->isChecked()); options->setOption(constSoundStart, ui_.le_start->text()); options->setOption(constSoundFinish, ui_.le_finish->text()); options->setOption(constSoundMove, ui_.le_move->text()); options->setOption(constSoundError, ui_.le_error->text()); options->setOption(constDndDisable, ui_.cb_disable_dnd->isChecked()); options->setOption(constConfDisable, ui_.cb_disable_conf->isChecked()); options->setOption(constSaveWndPosition, ui_.cb_save_pos->isChecked()); options->setOption(constSaveWndWidthHeight, ui_.cb_save_w_h->isChecked()); } void GomokuGamePlugin::restoreOptions() { Options *options = Options::instance(); ui_.cb_sound_override->setChecked(options->getOption(constDefSoundSettings).toBool()); ui_.le_start->setText(options->getOption(constSoundStart).toString()); ui_.le_finish->setText(options->getOption(constSoundFinish).toString()); ui_.le_move->setText(options->getOption(constSoundMove).toString()); ui_.le_error->setText(options->getOption(constSoundError).toString()); ui_.cb_disable_dnd->setChecked(options->getOption(constDndDisable).toBool()); ui_.cb_disable_conf->setChecked(options->getOption(constConfDisable).toBool()); ui_.cb_save_pos->setChecked(options->getOption(constSaveWndPosition).toBool()); ui_.cb_save_w_h->setChecked(options->getOption(constSaveWndWidthHeight).toBool()); } QPixmap GomokuGamePlugin::icon() const { return QPixmap(":/gomokugameplugin/img/gomoku_16.png"); } /** * Получение списка ресурсов и вызов формы для отправки приглашения */ void GomokuGamePlugin::invite(int account, QString full_jid) { QStringList jid_parse = full_jid.split("/"); QString jid = jid_parse.takeFirst(); if (jid.isEmpty()) return; QStringList res_list; if (psiContactInfo->isPrivate(account, full_jid)) { // Это конференция if (jid_parse.size() == 0) return; res_list.push_back(jid_parse.join("/")); } else { // Получаем список ресурсов оппонента res_list = psiContactInfo->resources(account, jid); } // Отображение окна отправки приглашения GameSessions::instance()->invite(account, jid, res_list); } // ------------------------------------------ Slots ------------------------------------------ /** * Кто то кликнул по кнопке тулбара в окне чата */ void GomokuGamePlugin::toolButtonPressed() { if (!enabled_) return; // Получаем наш account id QString jid = psiTab->getYourJid(); int account = -1; for (int i = 0; ; i++) { QString str1 = psiAccInfo->getJid(i); if (str1 == jid) { account = i; break; } if (str1 == "-1") return; } // Проверяем статус аккаунта if (account == -1 || psiAccInfo->getStatus(account) == "offline") return; // -- invite(account, psiTab->getJid()); } /** * Кто то выбрал плагин в меню ростера */ void GomokuGamePlugin::menuActivated() { if(!enabled_) return; int account = sender()->property("account").toInt(); if (psiAccInfo->getStatus(account) == "offline") return; QString jid = sender()->property("jid").toString(); invite(account, jid); } /** * Создания события для приглашения */ void GomokuGamePlugin::doPsiEvent(int account, QString from, QString text, QObject *receiver, const char *method) { psiEvent->createNewEvent(account, from, text, receiver, method); } /** * Отсылка станзы по запросу игры */ void GomokuGamePlugin::sendGameStanza(int account, QString stanza) { if (!enabled_ || psiAccInfo->getStatus(account) == "offline") return; psiSender->sendStanza(account, stanza); } void GomokuGamePlugin::testSound() { QObject *sender_ = sender(); if (sender_ == (ui_.play_error)) { psiSound->playSound(ui_.le_error->text()); } else if (sender_ == ui_.play_finish) { psiSound->playSound(ui_.le_finish->text()); } else if (sender_ == ui_.play_move) { psiSound->playSound(ui_.le_move->text()); } else if (sender_ == ui_.play_start) { psiSound->playSound(ui_.le_start->text()); } } void GomokuGamePlugin::getSound() { QObject *sender_ = sender(); QLineEdit *le = 0; if (sender_ == ui_.select_error) { le = ui_.le_error; } else if (sender_ == ui_.select_finish) { le = ui_.le_finish; } else if (sender_ == ui_.select_move) { le = ui_.le_move; } else if (sender_ == ui_.select_start) { le = ui_.le_start; } if (!le) return; QString file_name = QFileDialog::getOpenFileName(0, tr("Choose a sound file"), "", tr("Sound (*.wav)")); if (file_name.isEmpty()) return; le->setText(file_name); } void GomokuGamePlugin::doPopup(const QString text) { psiPopup->initPopup(text, tr(constPluginName), "gomokugameplugin/gomoku"); } void GomokuGamePlugin::playSound(const QString sound_id) { Options *options = Options::instance(); if (options->getOption(constDefSoundSettings).toBool() || Options::psiOptions->getGlobalOption("options.ui.notifications.sounds.enable").toBool()) { if (sound_id == constSoundMove) { psiSound->playSound(options->getOption(constSoundMove).toString()); } else if (sound_id == constSoundStart) { psiSound->playSound(options->getOption(constSoundStart).toString()); } else if (sound_id == constSoundFinish) { psiSound->playSound(options->getOption(constSoundFinish).toString()); } else if (sound_id == constSoundError) { psiSound->playSound(options->getOption(constSoundError).toString()); } } } // --------------------- Plugin info provider --------------------------- QString GomokuGamePlugin::pluginInfo() { return tr("Author: ") + "Liuch\n" + tr("Email: ") + "liuch@mail.ru\n\n" + trUtf8("This plugin allows you to play gomoku with your friends.\n" "For sending commands, normal messages are used, so this plugin will always work wherever you are able to log in." "To invite a friend for a game, you can use contact menu item or the button on the toolbar in a chat window."); } // --------------------- Option accessor --------------------------- void GomokuGamePlugin::setOptionAccessingHost(OptionAccessingHost *host) { Options::psiOptions = host; } void GomokuGamePlugin::optionChanged(const QString &/*option*/) { } // --------------------- Iconfactory accessor --------------------------- void GomokuGamePlugin::setIconFactoryAccessingHost(IconFactoryAccessingHost *host) { psiIcon = host; } // --------------------- Toolbar icon accessor --------------------------- QList GomokuGamePlugin::getButtonParam() { QList list; QVariantHash hash; hash["tooltip"] = QVariant(tr("Gomoku game")); hash["icon"] = QVariant(QString("gomokugameplugin/gomoku")); hash["reciver"] = qVariantFromValue(qobject_cast(this)); hash["slot"] = QVariant(SLOT(toolButtonPressed())); list.push_back(hash); return list; } QAction* GomokuGamePlugin::getAction(QObject* /*parent*/, int /*account*/, const QString& /*contact*/) { return NULL; } // --------------------- Activetab accessor --------------------------- void GomokuGamePlugin::setActiveTabAccessingHost(ActiveTabAccessingHost *host) { psiTab = host; } // --------------------- Account info accessor --------------------------- void GomokuGamePlugin::setAccountInfoAccessingHost(AccountInfoAccessingHost * host) { psiAccInfo = host; } // --------------------- Contact info accessor --------------------------- void GomokuGamePlugin::setContactInfoAccessingHost(ContactInfoAccessingHost * host) { psiContactInfo = host; } // --------------------- Stanza sender --------------------------- void GomokuGamePlugin::setStanzaSendingHost(StanzaSendingHost *host) { psiSender = host; } // --------------------- Stanza filter --------------------------- bool GomokuGamePlugin::incomingStanza(int account, const QDomElement& xml) { if(xml.tagName() == "iq") { QString acc_status = ""; bool confPriv = false; if (xml.attribute("type") == "set") { acc_status = psiAccInfo->getStatus(account); confPriv = psiContactInfo->isPrivate(account, xml.attribute("from")); } return GameSessions::instance()->processIncomingIqStanza(account, xml, acc_status, confPriv); } return false; } bool GomokuGamePlugin::outgoingStanza(int /*account*/, QDomElement& /*xml*/) { return false; } // --------------------- Event creator --------------------------- void GomokuGamePlugin::setEventCreatingHost(EventCreatingHost *host) { psiEvent = host; } // --------------------- Sound accessor --------------------------- void GomokuGamePlugin::setSoundAccessingHost(SoundAccessingHost *host) { psiSound = host; } // --------------------- Menu accessor --------------------------- QList GomokuGamePlugin::getAccountMenuParam() { return QList(); } QList GomokuGamePlugin::getContactMenuParam() { QList menu_list; QVariantHash hash; hash["name"] = QVariant(tr("Gomoku game!")); hash["icon"] = QVariant(QString("gomokugameplugin/gomoku")); hash["reciver"] = qVariantFromValue(qobject_cast(this)); hash["slot"] = QVariant(SLOT(menuActivated())); menu_list.push_back(hash); return menu_list; } QAction* GomokuGamePlugin::getContactAction(QObject*, int, const QString&) { return NULL; } QAction* GomokuGamePlugin::getAccountAction(QObject*, int) { return NULL; } // --------------------- Popup accessor --------------------------- void GomokuGamePlugin::setPopupAccessingHost(PopupAccessingHost *host) { psiPopup = host; } plugins-1.5/generic/gomokugameplugin/gomokugameplugin.h000066400000000000000000000116721336777360500236010ustar00rootroot00000000000000/* * gomokugameplugin.h - Gomoku Game plugin * Copyright (C) 2011 Aleksey Andreev * * 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. * * You can also redistribute and/or modify this program under the * terms of the Psi License, specified in the accompanied COPYING * file, as published by the Psi Project; either dated January 1st, * 2005, 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef GOMOKUGAMEPLUGIN_H #define GOMOKUGAMEPLUGIN_H #include #include #include "psiplugin.h" #include "plugininfoprovider.h" #include "optionaccessor.h" #include "optionaccessinghost.h" #include "iconfactoryaccessor.h" #include "iconfactoryaccessinghost.h" #include "toolbariconaccessor.h" #include "activetabaccessor.h" #include "activetabaccessinghost.h" #include "accountinfoaccessor.h" #include "accountinfoaccessinghost.h" #include "contactinfoaccessor.h" #include "contactinfoaccessinghost.h" #include "stanzasender.h" #include "stanzasendinghost.h" #include "stanzafilter.h" #include "eventcreator.h" #include "eventcreatinghost.h" #include "soundaccessor.h" #include "soundaccessinghost.h" #include "menuaccessor.h" #include "popupaccessor.h" #include "popupaccessinghost.h" #include "ui_options.h" class GomokuGamePlugin : public QObject, public PsiPlugin, public PluginInfoProvider, public OptionAccessor, public IconFactoryAccessor, public ToolbarIconAccessor, public ActiveTabAccessor, public AccountInfoAccessor, public ContactInfoAccessor, public StanzaSender, public StanzaFilter, public EventCreator, public SoundAccessor, public MenuAccessor, public PopupAccessor { Q_OBJECT #ifdef HAVE_QT5 Q_PLUGIN_METADATA(IID "com.psi-plus.GomokuGamePlugin") #endif Q_INTERFACES(PsiPlugin PluginInfoProvider OptionAccessor IconFactoryAccessor ToolbarIconAccessor ActiveTabAccessor AccountInfoAccessor ContactInfoAccessor StanzaSender StanzaFilter EventCreator SoundAccessor MenuAccessor PopupAccessor) public: explicit GomokuGamePlugin(QObject *parent = 0); // Psiplugin virtual QString name() const; virtual QString shortName() const; virtual QString version() const; virtual QWidget* options(); virtual bool enable(); virtual bool disable(); virtual void applyOptions(); virtual void restoreOptions(); virtual QPixmap icon() const; // Plugin info provider virtual QString pluginInfo(); // Option accessor virtual void setOptionAccessingHost(OptionAccessingHost*); virtual void optionChanged(const QString&); // Iconfactory accessor virtual void setIconFactoryAccessingHost(IconFactoryAccessingHost*); // Toolbar icon accessor virtual QList getButtonParam(); virtual QAction* getAction(QObject* , int , const QString& ); // Activetab accessor virtual void setActiveTabAccessingHost(ActiveTabAccessingHost*); // Account info accessor virtual void setAccountInfoAccessingHost(AccountInfoAccessingHost*); // Contact info accessor virtual void setContactInfoAccessingHost(ContactInfoAccessingHost*); // Stanza sender virtual void setStanzaSendingHost(StanzaSendingHost*); // Stanza filter virtual bool incomingStanza(int account, const QDomElement& xml); virtual bool outgoingStanza(int account, QDomElement& xml); // Event creator virtual void setEventCreatingHost(EventCreatingHost*); // Sound accessor virtual void setSoundAccessingHost(SoundAccessingHost*); // Menu accessor virtual QList getAccountMenuParam(); virtual QList getContactMenuParam(); virtual QAction* getContactAction(QObject*, int, const QString&); virtual QAction* getAccountAction(QObject*, int); // Popup accessor virtual void setPopupAccessingHost(PopupAccessingHost*); private: bool enabled_; ActiveTabAccessingHost *psiTab; IconFactoryAccessingHost *psiIcon; AccountInfoAccessingHost *psiAccInfo; ContactInfoAccessingHost *psiContactInfo; StanzaSendingHost *psiSender; EventCreatingHost *psiEvent; SoundAccessingHost *psiSound; PopupAccessingHost *psiPopup; // -- Ui::options ui_; private: void invite(int account, QString full_jid); private slots: void toolButtonPressed(); void menuActivated(); void doPsiEvent(int, QString, QString, QObject *, const char *); void sendGameStanza(int account, const QString stanza); void testSound(); void getSound(); void doPopup(const QString text); void playSound(const QString); }; #endif // GOMOKUGAMEPLUGIN_H plugins-1.5/generic/gomokugameplugin/gomokugameplugin.pro000066400000000000000000000013161336777360500241440ustar00rootroot00000000000000isEmpty(PSISDK) { include(../../psiplugin.pri) } else { include($$PSISDK/plugins/psiplugin.pri) } INCLUDEPATH += $$PWD DEPENDPATH += $$PWD HEADERS += gomokugameplugin.h \ pluginwindow.h \ boardview.h \ boardmodel.h \ boarddelegate.h \ gameelement.h \ invatedialog.h \ gamesessions.h \ common.h \ options.h \ gamemodel.h SOURCES += gomokugameplugin.cpp \ pluginwindow.cpp \ boardview.cpp \ boardmodel.cpp \ boarddelegate.cpp \ gameelement.cpp \ invatedialog.cpp \ gamesessions.cpp \ options.cpp \ gamemodel.cpp FORMS += pluginwindow.ui \ invatedialog.ui \ invitationdialog.ui \ options.ui RESOURCES += gomokugameplugin.qrc plugins-1.5/generic/gomokugameplugin/gomokugameplugin.qrc000066400000000000000000000005201336777360500241250ustar00rootroot00000000000000 img/black-stone.png img/white-stone.png img/gomoku.png img/gomoku_16.png img/goban1.png plugins-1.5/generic/gomokugameplugin/img/000077500000000000000000000000001336777360500206235ustar00rootroot00000000000000plugins-1.5/generic/gomokugameplugin/img/black-stone.png000066400000000000000000001246731336777360500235500ustar00rootroot00000000000000PNG  IHDRddpT jiCCPPhotoshop ICC profilexH HLinomntrRGB XYZ  1acspMSFTIEC sRGB-HP cprtP3desclwtptbkptrXYZgXYZ,bXYZ@dmndTpdmddvuedLview$lumimeas $tech0 rTRC< gTRC< bTRC< textCopyright (c) 1998 Hewlett-Packard CompanydescsRGB IEC61966-2.1sRGB IEC61966-2.1XYZ QXYZ XYZ o8XYZ bXYZ $descIEC http://www.iec.chIEC http://www.iec.chdesc.IEC 61966-2.1 Default RGB colour space - sRGB.IEC 61966-2.1 Default RGB colour space - sRGBdesc,Reference Viewing Condition in IEC61966-2.1,Reference Viewing Condition in IEC61966-2.1view_. \XYZ L VPWmeassig CRT curv #(-27;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Km>;, pHYs  tIME  G IDATxr111 000 #&& @@@ 1G;"::: EU4GGG)aN!666[g!FFFPp4rɎ IDATKKK{$   )>MMM7Z   ;???...F6  ,!@@@X"  "*>>> W (<<< R% 7  . iGGG%.  DDD K  "TU   QFFF-    BBB k$  5 9 3P   C???f   !1 :N  =888Y,A09666I :VH IDAT#4///7  *    & >= IDATH G9 C2 C 22< 50' '(#   aїIDAT2       pU #ƢIENDB`plugins-1.5/generic/gomokugameplugin/img/goban1.png000066400000000000000000000046471336777360500225130ustar00rootroot00000000000000PNG  IHDRddsRGB pHYs   LIDATxڽ]n: :@Ȑ7  NY")z+˖Dϟ=RJ)}.L)tn7]Lg+V]\y/#m՚߫}bm֣slI4)φ`|ZX4}NOgkԕ:41 hGĐ3^[PG!U9.}k`3H+lL u'Ѓ֣X)V7 +I)s{PfLyhl%=&Y\AVq4NZ<$V{GR>Λ٥_z[JPF>0eo^l%/vuk8“KɚxrEF(5&1`oyq~!13Oz\sZ*g0!oSVfs TCSn|=J]1!!AHro|nDc(epIPk̇ϣű %8 Bd=$vV:p_?7]ir5ҳaܝqWfw;3S^YsŁZrP&͢q .DҤ>|4OIImԼ̐Kg9WY4e~ϹLnd1)Gl }F(Eڍzhn)VFHY3:=/Q,O!V$,zNƷGm.2QH|(t4Zϼx Ӱ&[zrR.vmvhr!+М̵q1ې^t\>C8L ^Edr云׻{SN5HcWwxS.1 OJ1i&"#{0}DGie5|O6 2F:U6FHXm`YG߽]дLbN0⍯9Hb(Vz<rj|&Q$f#{CA!䡚]'P4c8$U"cvِ`\)  N\!١O{!%7zbeAVQ+cf\fU* =-iMs"66{huQ^{)ZXĽߌt%vS6.adQv=Smv3XN^Gq30"lG;*ct2Yn<ڧlS\'NVNXE]{[92y1fo['dc,>k&{]=ϡbh{:@,'9cDddr/9^ ېjߋlSk 8QVIÏkj4)핒Z)#o,zM 8rዚd%b1` 7DuL6Pb,|+ww)!k-B784S: $øA<#)}XE(kHֳwj\<$# n rI+G0Qf Η5 wA_di rb3*M:[_oWea8W4B[/:=A$Ny?:[; UB<٨!PM@kqacpC:9 ~Ό-rgdIp]CO+ɪ5%={R1[#3\em{β7+yl/{ʍ_7|ȟmV9.>)+#x+b&H;~|Vnqq.)17 d8iX 1̺іǕ4)oE!sT t8D7Z:ݝhϥ,К)jpiG-'2?Y[iV\ [d{(z>RΝwzD#va. KN;hsi[3)hOs kA#0ny"IENDB`plugins-1.5/generic/gomokugameplugin/img/gomoku.png000066400000000000000000000656231336777360500226460ustar00rootroot00000000000000PNG  IHDR\rfsRGBbKGD pHYs  tIME)\? IDATxwxy qO84-۱-Cb'miƧu'u~u[7MOsi6IS'uIXLZN$[rdkX{Q[p`~nB}]E@s{~oINr$'9INr$'9INr$'9INr$'׊rKp־X \.Wǹܪ '٭k8~ lu:FrLRnF"n7OI0TU?~<9rr 7`6`0`0tt$X,F4% A@`0霌ߔ8Oǻ5*--B|>N'DєoS3x)!q?6C k |r ~Cwww҃F#RPPhzH fD~~ ~YJ&kL^իWq-,XdB#IW^̙3;w'NDF=d2QXXy64\~zzzdX,:466RQQ^\q匿sy4i^^H$ ׺4 l\rŲj*z=gΜ7zii)~;r f9iS;\7hbPQQA}}|ݻxl_ey!Y _fL&P(ᠷ`0([>3UWWSQQ{Xd K.\z}]vޭ[V$I" KW&\USrdwvvʧP{{;wy'fp8ݻy7q:477a/_N}}=EEEc0D"~n7Ü;wwy}r(**bvmDسgoƨ@`-NUD?###ٳw}`0Hqq17p7|3---RXX(G`Pr1z-Ξ=Kee%z++WvohP @ 62S5 !LaYfl򗖖я~F$IbϞ=k|>y衇Xt)UUUɧ^hepp]v_׋dbƍlܸg?٨\3sd>1VXiii!???i_I˖ŋ Btuuٿ?HF/;wY9l&`=l2˓_X,$Oaa!TTT0|:;;PSS X 0aHLlnu[ `Ⱥu8z(7nGl6_gb1l6ǩFF|z7R^\a^/ , ݍ$I?^/^ŋbtw+J>^+**s=kFe.,,tbXhll|>9B~~>555s^@X2ln9 v,gΜ! qFz! /رcl~-ZfɯX,x<555n$^zzzXt)Wo%^?gC'/g# %$D ʵFI^^՜9sH$Bgg'Z[[9u@`tK? 4b!o̒l6^JII ``ΝtttoDss3f^3s'rG"$RQQ˗ b1q: x[\}(O~ߟ ED8 n7ŋeWj@KK ǏU)lkW,{s*ZӧOO|ɓ'~&?K(..d2%)$a2lt:["NǡC`jr-wyVCk}`eڵrU٦MxeSDFtB6QsN'ӕCY$_޴onZe:@E>(E"o"d /1~ lr0墪J8yd%JdQۨA+^KDYY![r_.Zi:PlriFFFhnn7'94`DW[o>r䈜N'LaaaYSmTKe߅+5YUKp8- *S@ 0*6PPPr r'`/ ޒKrš5kRlYJڒl6'Ң_Iݥ)7sͯt yrAp fr?}^u$JkGeP B?$I,Z({x .S,' 1L\x|jkkx<&=FF 8s AB%(OA%jX`Wf!P&,z{{b,\03qodEgTrqA%JJ:GpIluVEI,^u?ەkj̘%E^^S,Z'cּh60֬ rt^0yyyIJ*r7} sxM. 8D~O]Q2P ^7*X,U P__ngppP,Z@f@D(/ME9-Ptnej.@&p Oul~ ޸7݀-O?ʯ|es FFF4k+(3_5@AAP~Mr63 ℰZ1T, zpp$_9D (Wʈ-<̄x^WWju؂ ]ISr"6V` )&% zt:l6\GY4sB4ɮ$V_bj/~kʆ(uIp `xxXhv$U`'NglmB< ihhfqePbry<bVUvDюH)An@ SQh m2V)m?΂?.{<H ,7-Q6 ʲٞUlp8,wމb 1'UbPdѴb2dPbrO4fuNsZn|[ x~T5.M ʂq8=jf@0v(&e=IɔTeOm (A Ԣ .,ܼx"[ |GY]).AtDE"2:K>'NQKWfPD*t"IUUUX,~CCCXV9œ* GSӤQUJHl[pP=vO;C`0P[[˷ut,\秓"Y=r w}7i\$ɥJTmhyu1ie' Μ M,Y TV_OeCCCxm'O\M?̅Zi~?~_ l6#[ P]]MSSNe(onb͓ >z(7A!A\$_"YlG#/1wƄGD"ϧB!FFFzʯRA^X%%ǿYTTK(V=Yv꨷VKRXX(7 XP>~mx6mӧ6(E]vZQ"p6ciZUU%[9R^^.O=x 6l`…,_#Gh"~V+EW(HLJWJ bTWWzj^/{%l_Vpw xޤ5Q틀?n?W4c\[ & R|'+hllyaZ去`0(Opϟܹs9)**G>J͆KKW^c= _גڃ+|m3//" e)}`5a^瓟$dϞ=B ,~GyuVDOQAw/.>ի=w\.N'===)˛"p8`Sb&3]*%Fimm>RjZST߰aw}7~[o-, z}>zY%h@3gpin762,YBYY "Cz^!>Xj~_fZ]b<;477a,Y"wӉaʕ+?~'Oj3,Y–-[G$z-~ &I͛ X,QkÆ ,['j+@yҋKY &y:v/__c5 0ONo_׳yfve>O:`XX,vvN<ݻq477:uQ:4jS&n<8sw9s,_|#,[bn+Wpy9r8pG z[}Cp8=[((șG4Snf|A o&/T(ہjPbpc?I8l^U+ee%weee|;'SOBH'}122O~Boo/K,h4r⇐-t PTTDgg'<whm۶sN|I{1-[FaafË$I )))TUUQ]]Moo(z*cѢErرcIO!DTH٩ͩ.iiiKӣٔ#P فo7b2b֭iӸ;/3*`Ѹ臡٠$IqFn wN$N-O?j*qK׳b L&L&JKKill{T&@ԞLV^e{ |{cdd}slذ* 7:7oG&0t:eB7n}QSS XbG*Ğ ZnF3"|uOX5(}/^N#fs.֛LMq--[PUUNK&[hkk )= JUUx<jjjR8tS!$ ~`07M(O>$VrVu)$IXVdMNGEEv!ihh`ҥ۷/) FxwzTWWS__ύ7ڵk)--<RYB-Z˗c xXnz}Mln>G|VF9p 78Awe~ßl6 ,`۶mB!멫IӀEEE\t<>bZOʻDss\xNe-e0p:IעF@V+ѣGYnMMMA.^81Po2 5{~Xd n={h(cUUUXB K,TةL^sx IDATxn$IwT DuuuIi/Á$I,_|Ry"xKYz%IiǺtIO'`Ŋ466oxhjjb׋Dx嗉byH$7:@OO8C${wN}%%%@9XYt$`PQ+˗/ 1LS1W7PWܓ{~~V秺4aX$;3P(޽{Xф`ժUrjӦMot:)//gr`,U9hU)/Wze/B״f}-R[eeeI~[eefGdMDpVd'O- 7mU}K;Zx-Qe{%^fhhdn&$Ib85ycccR7E*j@B9DQ{L,Oc^Dp:`q<\X$ΞIgC%^=Ss؟=3.66cB/^<1[[fYNu'SVi}0A|u1]D"VZ5偿LbfNI4ӿxK`0,NGOO$_$o”tvljkjg7Ze*I_~_z4ɵV^-WB1);{, .$//oLP;}__&ݕ21|I3)+WxD @RRP$.{7.w7f2ɎDV!n1P($7bpJ 0.\H ãHx fr  줢XՑk B Օ8Բ2RPP0f`:D|B<(IҨ/Dh4b24; VQ0SDmo]@ b_"Xtj $p8LWW4sꪧL̖ dvh4JOOOʓ_tU~"G-//gɒ%YS&HdrV@fUQTTnW%^/2`Ic.|>zzzRJիtB4eJA?e^lN,((fӀ$I" axxx<& N's\rUV@8u(g".|jeD[pPQQD[oX)E(+Cܕj,-LG>"^"xp8D)PAA].iT`0ӿxT#LҥKxK3K[JPClABQ SWٛZ鬀`08ʲUjUjn/ČZ%ԩSTVVfvڅ]8~8/NJciQiRT b&r 7ϕ+W&5tL} ESc 5 sn z.^(K\c^~>Z|rXj]tj @]T[PSNiƼ.\8f3( Hʹ:'Yfir8}~LyVn IرcǬ zj(S"ҀU:<$b. /bM#x:aeq)V_:Iuy^N>4WZqglv;Ü?>,X@}}拍pI,X R,2J !NXbXɓç[_ :F"!>N.`.EqY[ $e( mlldc ɾ]8y$˗/s΍ (;%2U4'ǥKRbZMt7{f=Iii)Ix+xz/Xn -᠒xC2U/=Wסڵ#A?LxV?׉h?_9ŋ)++am:D"8N Z:_49ΔN3Qp8Lqq\;qFXxqb˥EEEIM8HT6}\|yR Tc[Q vtvgqћnis$\6[\/\eZ4瓭|twwgT<D|'/ۍ3pBJJJp:r&*HJExZ) CҐJJJՅ7ʿf|ڵk\uJ?6j#?@|pVqx<ߏlx8:w=FX_p:3)WYY$I4;aHw\Ȉ(((oif h4r-҂cǎjOD ̙3|s=GvL 34 lJrtY^ٹL|xfk7䶍 d`:kpŒXCdhhQT(~)vkN%ؖhs!"ӣ[:;f |h4&?>mNqV?efk}@b89?[% _wR$6[Wl1 $dݿ;oL-Ff Rn41r$%]>%I^~ss)<;ߙ+GNJѢI I.KߋYl]oJg&_Mv}v);:|yyU|p}kOOѪU vdI ,^\%Iٷi0ΛwZTkblR| &/lV GO_F>ϏT1BbW:0)^Tr "q4XISK7a-b1^|şۦ.esJo)i)zCQ,1cdPOUx:D0Y&jP2n@nPrSͪGW*- P=DLar6̜O2R&1I(,<+j) U{-D%,A V*2e!_|^`3IK̙L+wiXnT R̈́u65 9;/ wd/ TUUب̀ZDQk,O1/~WK^:=`7~Z?w@Wz=ӁAnwÛDτUh{ɮ NQnf'v i~mNdh$sOtO ?VLgWϕnW ~\wt\(U_ DbXTxb*B<h76vg99e؜l8\rڵkVQQ$I @%r^y KD: Qsf"!IuSftcTk*@ xb/"@ V6ve IDAT(mmm'pX.:/~+R?Wa|9P^=G>`ϤT`-?a9P*7| {kc8ЂƦvuuۋdbɒ%rPP$~(] @Z8Vpqq| Ֆ'&@`g+Ƕ|\*Gܯ̖hR8{,كYFc0,lM{$b18$IxTVV"I###)LUj^ i)nW* [sO2EKe)S,@:7@-"X[[KMM ~.]!Y1nMe"8x"vMt:S6h JP[ R,WΙ~3Z\b L}}=$qE(ڙPEr@6NMtD">$Ip \.ט/&I`3 P VѨ_r;VΙ>}"=U߃~ ʪ@AAuuua.]8o31eXƧɃΟ?̟?Izi-d2e ـ x;*UX=uK*.b\u-@mm-:WHȳ׈xƑO'dA@'O"Ib19WXZ)xr>GD{0ϛ.+$RZtDQK-.W9z8pNe'N`:RbOU*\VNG'/D $0| & &.AD[SCFG\…(1|9sFz)U՛SJe;. M&~&RixtNdr*8 ?XI``PΝ;q:vejq^88z(HP(4a,_V[ j95}…>tY=zH{O?T@8z0X!i y8)L6I]u… LSgX!  _:\]2B nh? QMemz"hK.%izqkcժ!jx!nwFUbS pˁ+ f %zY"DA0>NZ鬭R~@lb0ǎeڔVU#j%NU>S0Un! YS?ONƲДrQ.Z:I j? `ܙ _f"f9igRK | ,b&z[J5,(gܭd׸qXf(B|ߤcZb0Le_ &Zf:&T?y:MQݕ+BaX,Tg,&Ǩ;eOKSXX8ɧV'zB&|ZAJ1LI4_-rq,zr0>9?#[bIg+З3n$I|+oMѶ)TlJͬX %\l ^dDt'~7:NK|,̦+ >u߄-0Thbh6 i#Hv :dS)p ց HFL&(?_9&݉t4aY[ȿtʋ1 dkxMT He r >5W#z'TXnXLIBenV0sgJ;p0 ZXWjESXAAk(ɥT!0֩?^0N`HO12 |&L?eTeflEC]cRJ3h )`By5Q\,GO292ZJӟ^$d)?MQ9)AeOO|1Sx ['nL -ߘUӝS1I>^0d`Kbќ@<1T*XYjᕧd&-Ÿ($RZp6T&xnJP3!_MSf*E+|։e|3kJXt'LTIDr\)O2sD@U0?4I.:SMK*=k;zM* ODnt=P4%*8 mw:zŧ* kCl|LMTc3%$}=h{ zwo:+?^j`x{ЖL5pd}fvrq`9QV,W-P '_*b^xW{" =1&G"Kڽ }6o z[[>8<^~ʼn%nN쾆*a|st;Vt^TAmQP71n&sik =v-ҏ^ L\.ڟM(#d֮}dN?pxiesn+M~ ngJe!eSِ*t p:BtKѧEz@ p*p1D:XS\o:;O&̴v$Itf:I&a^_wW<OS=O}gR+k3Ϥ+03W3{@HX,ףGvIL,L]/ dG8NsT}^ۨKgS=f"hGFFƐsװv D\OtI]` pxpx^~?Ph4:*0O/d ۲M؇"]ZDlC,k5[7A^_t eG K@gRPP@^^CCC)ݕT%{-NT^Jب'hRHVͿf%Q1)UL bbzlFWA^.pQǕ022rMlbDY=p;`0$QtBշմZWzrQ=KJ=YQz %wu q'vη:] lJP؜X j'H.:+.a˗^ȓ#V^kNh4bۉFxkbNwd1>CݒmYMje@PH;'\l8#/N\E$>X$ 11a/pD}ki%^Omߣj`0ח-5 Uvjj:.$8UGC!u{" Fސ0i_+ rO- HZU&{X >Hc)BEw [d2Kođ&@CO>+x0eY  TfIʺ %iY&z=EEEHDaxq#d|+J#0{W϶ZZdP1$VI*.Lzk*AA boid2aوD"kfgh+kDx6܋l:te(UOF^N c ZTBpDg$kmrE@Z ڤi" ;P! xgnwӉ=y~EmmC+D_Q$ˆⷢ93ǵy7g \.c"0O.rzx<#8$(Y #'ǧ~MOVZdUsfDݧ/"0  nտ:@%YГmY4m>/Zy[.CvIOE03 R_pEaXu-G=cl{^ d2V@_sRQJ0M.~>_aLFT D!Y!)8cm2HF{YO:)l 0MW@`Otd})wy3쳄@8I% A٬=:.ЅDB?X8*#(`Okߋܹ;z3 ς>)BeǛ-@zZCB9%xֺgYW7 p1 r#O3of}lYqMM '2Pvoo/r擛Oc!>zc?! 9%ǙihxxOLGX.$IZd000,..❣8o#+\໴:hPҎ@64Hˮd&7 +4O&ZC:Ts}_>pxul`۶mpX\\D$tɗFŒ*HR݋;vq̙e(D^k'_oU.3gWu1+ X`Íi7?? 衤7p5vp:in 8N:_VJfn\3xx3CĞ薁_F ,| <>DBXG?f sg aALOO[nțXt|>]m8\y߾l~'E:gr>3OZ4&'' 033%*4ZI <&LOOG"(?;[6x aI+*SѪ"⠁͚ 2;'UE x#Ec4.^D"" MaXttt`nn~!s1:8]vI8o^{M䤓gw(͘G<{pWmwՈwl.]6oތ. $]ׇt:>TJðKoMQH:`v,{shf+4/OGKS!@78vᐃg-xۯ?@609s01T!EV&)M:>6ZC4axx]]]ŋ״ٳuuuy&._*?o;}[0i;ΗYxp}9EףJ's*tTdx 5&goeGK`=|شialxUp8^$I:uJjc~n랭.]b$po˻/r||Fr[zU}vI/._3I|> ;wDSSfgg׬QkjjwނYz?l}~o<Iٵ/~K mk4ݔ`Q( O 4Kv^®]܌ /4M+_|yяĶZWr=u-1Zp`ESsu/di :]d!BQd|9E*X`C:ƭ[ގm۶apppc@[[fggL&сV,,,ŋZ_ʖ B狧[AuEș-^P?Bg州3RBMKtHL jd5챤ӏ(OA3ﵜQ455! " 'eڵ pnEss3~?n7۱yf|gV/TݴcX6k!k(\2P@?Tת/1D&JPVn$!G엑)477c۶mFV+X,&\nwi*ى1+wu`f8vXQluLc$kQ7؎BW"^G&s P~{='.{oյj` 3jVy6LfgY].v%腅LLL`rrR108px<˫ &ЙN: :Beuu!Mף4Mn9?{>Vkc Y3OM9O,e: GtޱDT}:P(ۑh4 z-"z*wށqF'j(C=χ)|VLDVx7+UK4Ǟ>d ؾ};5yiB}n1T|Qă8^~>ofggKuv{zQn/'@F\QNT!uuud2/+,)hMM q! ɓEtzUOp2cL_5Mn1_>l+#L&zp_'k/NdNhC%#e8xZ>'wR?|N~Yt >m_T" 4&!R#zzzHh^^UMd{l=A4-DlRnV6!<5щ>U;/э0n7 ڸGVLD2D0Dww7U/vDNޗJæBo%"[,iPf;?O+Kf4M=O?#J)TNOU`$%9t!U4C1ٕ!ܹ/nU4.arJE:XZCW<"N,JC#8:::ZH%qj^R͠Zj^g;ZzxwD<՝T$6Ȣvyf111Vlڴފ@GGthm-L"i+aGs^JF ,]chID@DDӚyz<@&k-Snw.PUEnrDHp}}}CAy,$O rh#nl1O'MDE-r4Q-< Z3ۏwKޟ4G<"<"Ӎe7p9~|tQҋ ލ,2O=gMUnN(lA zii*evx,:BvbUbr0E+N3 *^E5 ހGpDKWTd,򳫼iT@&2TıhkUcs d݋ur[ 5U!EQlٲ@@hM;DTrٛ2vDסZH4Cӯӣ^m9%JptVsQWJӜutge imFGGetww… W~]z4tݺyR٬Ж/yC+DY@9dcmL$꾏es:Dlai;ׇK. CvCx5#RQ"m3͙钺̤~ /~.tuۯFSCŗqXem%kPы iT+fU! 8t$iKyT#et^ߴpÃ!A™ˤe(cb 4ݨz 踹1,nF3I@LUl 7ԗ{3 1|5xdb!99FGqE^y <#`dk>}*z"Btq}!Aݒ#!iU t -%24>IHRI)"w +EϭmXXuzKr!VtdbL4 d}Tl'ILX$S /`~߯p[)u=>IENDB`plugins-1.5/generic/gomokugameplugin/img/white-stone.png000066400000000000000000001246731336777360500236140ustar00rootroot00000000000000PNG  IHDRddpT jiCCPPhotoshop ICC profilexH HLinomntrRGB XYZ  1acspMSFTIEC sRGB-HP cprtP3desclwtptbkptrXYZgXYZ,bXYZ@dmndTpdmddvuedLview$lumimeas $tech0 rTRC< gTRC< bTRC< textCopyright (c) 1998 Hewlett-Packard CompanydescsRGB IEC61966-2.1sRGB IEC61966-2.1XYZ QXYZ XYZ o8XYZ bXYZ $descIEC http://www.iec.chIEC http://www.iec.chdesc.IEC 61966-2.1 Default RGB colour space - sRGB.IEC 61966-2.1 Default RGB colour space - sRGBdesc,Reference Viewing Condition in IEC61966-2.1,Reference Viewing Condition in IEC61966-2.1view_. \XYZ L VPWmeassig CRT curv #(-27;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Km>;, pHYs  tIME 'h IDATxr  vvv...#&& 짧 1G;"EU4̫)aN!𬾾www888[g!皱Pp4 IDATӚ {$)>1117Z ;///nnnF6,$$$!)))X"""""* ...W (000R   %ooo8 %.   K  " TU  ,,,Q666$ -   }F  3P111C  : :N222=  v:A...0   9 I ))) :V  IDAT%%%#47 !!! *     + IDAT 222C񥥥777 2$$$2㸸$$$< 1115,,, 0*** '%%% '!!!(# 便垞 ݭ 壣  ꫫڵ8VIDAT2   666(5556#  000333*               @/IENDB`plugins-1.5/generic/gomokugameplugin/invatedialog.cpp000066400000000000000000000050511336777360500232220ustar00rootroot00000000000000/* * invitedialog.cpp - plugin * Copyright (C) 2010 Evgeny Khryukin, liuch * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "invatedialog.h" using namespace GomokuGame; InvateDialog::InvateDialog(int account, const QString jid, const QStringList resources, QWidget *parent) : QDialog(parent), ui(new Ui::InvateDialog), accepted(false), myAcc(account), jid_(jid) { setAttribute(Qt::WA_DeleteOnClose); ui->setupUi(this); ui->leJid->setText(jid_); ui->cbResource->addItems(resources); adjustSize(); } InvateDialog::~InvateDialog() { delete ui; } void InvateDialog::acceptBlack() { emit acceptGame(myAcc, jid_ + "/" + ui->cbResource->currentText(), "black"); accepted = true; accept(); close(); } void InvateDialog::acceptWhite() { emit acceptGame(myAcc, jid_ + "/" + ui->cbResource->currentText(), "white"); accepted = true; accept(); close(); } void InvateDialog::closeEvent(QCloseEvent *event) { if (!accepted) { reject(); emit rejectGame(myAcc, jid_); } event->accept(); } // ---------------------------------------- InvitationDialog::InvitationDialog(int account, QString jid, QString color, QString id, QWidget *parent) : QDialog(parent), accepted_(false), account_(account), id_(id) { setAttribute(Qt::WA_DeleteOnClose); setModal(false); ui_.setupUi(this); if(color == "white") color = tr("white"); else color = tr("black"); ui_.lbl_text->setText(tr("Player %1 invites you \nto play gomoku. He wants to play %2.") .arg(jid).arg(color)); connect(ui_.pb_accept, SIGNAL(clicked()), this, SLOT(buttonPressed())); connect(ui_.pb_reject, SIGNAL(clicked()), this, SLOT(close())); adjustSize(); setFixedSize(size()); } void InvitationDialog::buttonPressed() { emit accepted(account_, id_); accepted_ = true; close(); } void InvitationDialog::closeEvent(QCloseEvent *e) { if(!accepted_) emit rejected(account_, id_); e->accept(); close(); } plugins-1.5/generic/gomokugameplugin/invatedialog.h000066400000000000000000000035561336777360500226770ustar00rootroot00000000000000/* * invitedialog.h - plugin * Copyright (C) 2010 Evgeny Khryukin, liuch * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef INVATEDIALOG_H #define INVATEDIALOG_H #include #include #include "ui_invatedialog.h" #include "ui_invitationdialog.h" namespace Ui { class InvateDialog; } namespace GomokuGame { class InvateDialog : public QDialog { Q_OBJECT public: InvateDialog(int account, const QString jid, const QStringList resources, QWidget *parent = 0); ~InvateDialog(); private: Ui::InvateDialog *ui; bool accepted; int myAcc; QString jid_; protected: void closeEvent(QCloseEvent *event); private slots: void acceptBlack(); void acceptWhite(); signals: void acceptGame(int my_acc, QString jid, QString element); void rejectGame(int my_acc, QString jid); }; class InvitationDialog : public QDialog { Q_OBJECT public: InvitationDialog(int account, QString jid, QString color, QString id, QWidget *parent = 0); private: Ui::InvitationDialog ui_; bool accepted_; int account_; QString id_; private slots: void buttonPressed(); signals: void accepted(int, QString); void rejected(int, QString); protected: void closeEvent(QCloseEvent *e); }; } #endif // INVATEDIALOG_H plugins-1.5/generic/gomokugameplugin/invatedialog.ui000066400000000000000000000076321336777360500230640ustar00rootroot00000000000000 InvateDialog 0 0 413 78 Gomoku Game Plugin - Invite Opponent: 75 true Select resource: 0 0 Qt::Horizontal 0 20 Qt::Horizontal 0 20 Play Black Play White Cancel cbResource btnBlack btnWhite btnCancel btnBlack clicked() InvateDialog acceptBlack() 119 56 172 38 btnWhite clicked() InvateDialog acceptWhite() 217 56 172 38 btnCancel clicked() InvateDialog close() 303 56 172 38 acceptBlack() acceptWhite() plugins-1.5/generic/gomokugameplugin/invitationdialog.ui000066400000000000000000000030361336777360500237540ustar00rootroot00000000000000 InvitationDialog 0 0 202 72 0 0 Gomoku Game Plugin - Invitation Qt::Horizontal 0 20 Accept Reject plugins-1.5/generic/gomokugameplugin/options.cpp000066400000000000000000000104631336777360500222520ustar00rootroot00000000000000/* * options.cpp - Gomoku Game plugin * Copyright (C) 2011 Aleksey Andreev * * 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. * * You can also redistribute and/or modify this program under the * terms of the Psi License, specified in the accompanied COPYING * file, as published by the Psi Project; either dated January 1st, * 2005, 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include "options.h" #include "common.h" #include "optionaccessinghost.h" Options::Options(QObject *parent) : QObject(parent), dndDisable(false), confDisable(false), saveWndPosition(false), saveWndWidthHeight(false), windowTop(-1), windowLeft(-1), windowWidth(-1), windowHeight(-1), defSoundSettings(false), soundStart("sound/chess_start.wav"), soundFinish("sound/chess_finish.wav"), soundMove("sound/chess_move.wav"), soundError("sound/chess_error.wav") { if (psiOptions) { dndDisable = psiOptions->getPluginOption(constDndDisable, QVariant(dndDisable)).toBool(); confDisable = psiOptions->getPluginOption(constConfDisable, QVariant(confDisable)).toBool(); saveWndPosition = psiOptions->getPluginOption(constSaveWndPosition, QVariant(saveWndPosition)).toBool(); saveWndWidthHeight = psiOptions->getPluginOption(constSaveWndWidthHeight, QVariant(saveWndWidthHeight)).toBool(); windowTop = psiOptions->getPluginOption(constWindowTop, QVariant(windowTop)).toInt(); windowLeft = psiOptions->getPluginOption(constWindowLeft, QVariant(windowLeft)).toInt(); windowWidth = psiOptions->getPluginOption(constWindowWidth, QVariant(windowWidth)).toInt(); windowHeight = psiOptions->getPluginOption(constWindowHeight, QVariant(windowHeight)).toInt(); defSoundSettings = psiOptions->getPluginOption(constDefSoundSettings, QVariant(defSoundSettings)).toBool(); soundStart = psiOptions->getPluginOption(constSoundStart, QVariant(soundStart)).toString(); soundFinish = psiOptions->getPluginOption(constSoundFinish, QVariant(soundFinish)).toString(); soundMove = psiOptions->getPluginOption(constSoundMove, QVariant(soundMove)).toString(); soundError = psiOptions->getPluginOption(constSoundError, QVariant(soundError)).toString(); } } OptionAccessingHost *Options::psiOptions = NULL; Options *Options::instance_ = NULL; Options *Options::instance() { if (instance_ == NULL) Options::instance_ = new Options(); return Options::instance_; } void Options::reset() { if (instance_ != NULL) { delete Options::instance_; Options::instance_ = NULL; } } QVariant Options::getOption(const QString &option_name) const { if (option_name == constDndDisable) return dndDisable; if (option_name == constConfDisable) return confDisable; if (option_name == constSaveWndPosition) return saveWndPosition; if (option_name == constSaveWndWidthHeight) return saveWndWidthHeight; if (option_name == constWindowTop) return windowTop; if (option_name == constWindowLeft) return windowLeft; if (option_name == constWindowWidth) return windowWidth; if (option_name == constWindowHeight) return windowHeight; if (option_name == constDefSoundSettings) return defSoundSettings; if (option_name == constSoundStart) return soundStart; if (option_name == constSoundFinish) return soundFinish; if (option_name == constSoundMove) return soundMove; if (option_name == constSoundError) return soundError; return QVariant(); } void Options::setOption(const QString &option_name, const QVariant &option_value) { if ((saveWndPosition || (option_name != constWindowTop && option_name != constWindowLeft)) && (saveWndWidthHeight || (option_name != constWindowWidth && option_name != constWindowHeight))) { Options::psiOptions->setPluginOption(option_name, option_value); } } plugins-1.5/generic/gomokugameplugin/options.h000066400000000000000000000045201336777360500217140ustar00rootroot00000000000000/* * options.h - Gomoku Game plugin * Copyright (C) 2011 Aleksey Andreev * * 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. * * You can also redistribute and/or modify this program under the * terms of the Psi License, specified in the accompanied COPYING * file, as published by the Psi Project; either dated January 1st, * 2005, 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef OPTIONS_H #define OPTIONS_H #include #include "optionaccessor.h" #define constDndDisable "dnddsbl" #define constConfDisable "confdsbl" #define constSaveWndPosition "savewndpos" #define constSaveWndWidthHeight "savewndwh" #define constWindowTop "wndtop" #define constWindowLeft "wndleft" #define constWindowWidth "wndwidth" #define constWindowHeight "wndheight" #define constDefSoundSettings "defsndstngs" #define constSoundStart "soundstart" #define constSoundFinish "soundfinish" #define constSoundMove "soundmove" #define constSoundError "sounderror" class Options : public QObject { Q_OBJECT public: static OptionAccessingHost *psiOptions; static Options *instance(); static void reset(); QVariant getOption(const QString &option_name) const; void setOption(const QString &option_name, const QVariant &option_value); private: static Options *instance_; bool dndDisable; bool confDisable; bool saveWndPosition; bool saveWndWidthHeight; int windowTop; int windowLeft; int windowWidth; int windowHeight; bool defSoundSettings; QString soundStart; QString soundFinish; QString soundMove; QString soundError; private: Options(QObject *parent = 0); signals: public slots: }; #endif // OPTIONS_H plugins-1.5/generic/gomokugameplugin/options.ui000066400000000000000000000200431336777360500221000ustar00rootroot00000000000000 options 0 0 338 318 Form Select Sounds: Game started: Game finished: Your turn: Error message: 0 0 25 25 25 25 0 0 25 25 25 25 0 0 25 25 25 25 0 0 25 25 25 25 If checked, the sound will always enabled (or disabled) Override default sound settings Disable invitations if status is DND Disable invitations from groupchat Save window height and width Save window position http://psi-plus.com/wiki/plugins#gomoku_game_plugin <a href="http://psi-plus.com/wiki/plugins#gomoku_game_plugin">Wiki (online)</a> true Qt::Vertical 20 0 le_start select_start play_start le_finish select_finish play_finish le_move select_move play_move le_error select_error play_error cb_sound_override cb_disable_dnd cb_disable_conf cb_save_w_h cb_save_pos plugins-1.5/generic/gomokugameplugin/pluginwindow.cpp000066400000000000000000000354171336777360500233130ustar00rootroot00000000000000/* * pluginwindow.cpp - Gomoku Game plugin * Copyright (C) 2011 Aleksey Andreev * * 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. * * You can also redistribute and/or modify this program under the * terms of the Psi License, specified in the accompanied COPYING * file, as published by the Psi Project; either dated January 1st, * 2005, 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include #include #include #include "pluginwindow.h" #include "ui_pluginwindow.h" #include "common.h" #include "options.h" #include "gamemodel.h" const QString fileFilter = "Gomoku save files (*.gmk)"; //-------------------------- HintElementWidget ------------------------- HintElementWidget::HintElementWidget(QWidget *parent) : QFrame(parent), hintElement(NULL) { } HintElementWidget::~HintElementWidget() { if (hintElement) delete hintElement; } void HintElementWidget::setElementType(GameElement::ElementType type) { if (hintElement) delete hintElement; hintElement = new GameElement(type, 0, 0); QFrame::update(); } void HintElementWidget::paintEvent(QPaintEvent *event) { QFrame::paintEvent(event); if (!hintElement) return; QRect rect = this->rect(); QPainter painter(this); hintElement->paint(&painter, rect); } //------------------------ PluginWindow -------------------------- PluginWindow::PluginWindow(QString full_jid, QWidget *parent) : QMainWindow(parent), ui(new Ui::PluginWindow), bmodel(NULL), delegate(NULL), gameActive(false) { ui->setupUi(this); setAttribute(Qt::WA_DeleteOnClose); ui->lbOpponent->setText(full_jid); } PluginWindow::~PluginWindow() { delete ui; } void PluginWindow::init(QString element) { GameElement::ElementType elemType; if (element == "white") { elemType = GameElement::TypeWhite; } else { elemType = GameElement::TypeBlack; } // Инициируем модель доски if (bmodel == NULL) { bmodel = new BoardModel(this); connect(bmodel, SIGNAL(changeGameStatus(GameModel::GameStatus)), this, SLOT(changeGameStatus(GameModel::GameStatus))); connect(bmodel, SIGNAL(setupElement(int, int)), this, SLOT(setupElement(int, int))); connect(bmodel, SIGNAL(lose()), this, SLOT(setLose()), Qt::QueuedConnection); connect(bmodel, SIGNAL(draw()), this, SLOT(setDraw()), Qt::QueuedConnection); connect(bmodel, SIGNAL(switchColor()), this, SIGNAL(switchColor())); connect(bmodel, SIGNAL(doPopup(const QString)), this, SIGNAL(doPopup(const QString))); } bmodel->init(new GameModel(elemType, 15, 15)); // GameModel убивается при уничтожении BoardModel ui->board->setModel(bmodel); // Создаем делегат if (delegate == NULL) { delegate = new BoardDelegate(bmodel, ui->board); // Прописан родитель } // Инициируем BoardView ui->board->setItemDelegate(delegate); ui->board->reset(); // Объекты GUI ui->hintElement->setElementType(elemType); ui->actionNewGame->setEnabled(false); ui->actionResign->setEnabled(true); ui->actionSwitchColor->setEnabled(false); ui->lsTurnsList->clear(); //-- emit playSound(constSoundStart); gameActive = true; } void PluginWindow::changeGameStatus(GameModel::GameStatus status) { int step = bmodel->turnNum(); if (step == 4) { if (status == GameModel::StatusWaitingLocalAction && bmodel->myElementType() == GameElement::TypeWhite) { ui->actionSwitchColor->setEnabled(true); } } else if (step == 5) { ui->actionSwitchColor->setEnabled(false); } QString stat_str = "n/a"; if (status == GameModel::StatusWaitingOpponent) { stat_str = tr("Waiting for opponent"); ui->actionResign->setEnabled(true); emit changeGameSession("wait-opponent-command"); } else if (status == GameModel::StatusWaitingAccept) { stat_str = tr("Waiting for accept"); emit changeGameSession("wait-opponent-accept"); } else if (status == GameModel::StatusWaitingLocalAction) { stat_str = tr("Your turn"); emit changeGameSession("wait-game-window"); ui->actionResign->setEnabled(true); emit playSound(constSoundMove); } else if (status == GameModel::StatusBreak) { stat_str = tr("End of game"); endGame(); } else if (status == GameModel::StatusError) { stat_str = tr("Error"); endGame(); } else if (status == GameModel::StatusWin) { stat_str = tr("Win!"); endGame(); } else if (status == GameModel::StatusLose) { stat_str = tr("Lose."); endGame(); } else if (status == GameModel::StatusDraw) { stat_str = tr("Draw."); endGame(); } ui->lbStatus->setText(stat_str); } void PluginWindow::endGame() { gameActive = false; ui->actionResign->setEnabled(false); ui->actionNewGame->setEnabled(true); emit changeGameSession("none"); emit playSound(constSoundFinish); } /** * В списке ходов сменился активный элемент */ void PluginWindow::turnSelected() { QListWidgetItem *item = ui->lsTurnsList->currentItem(); if (item) { bmodel->setSelect(item->data(Qt::UserRole).toInt(), item->data(Qt::UserRole + 1).toInt()); } } /** * Пришел сигнал с модели доски об установки игроком нового элемента */ void PluginWindow::setupElement(int x, int y) { appendTurn(bmodel->turnNum() - 1, x, y, true); emit setElement(x, y); } /** * Добавление хода в список ходов */ void PluginWindow::appendTurn(int num, int x, int y, bool my_turn) { QString str1; if (my_turn) { str1 = tr("You"); } else { str1 = tr("Opp", "Opponent"); } QString msg; if (x == -1 && y == -1) { msg = tr("%1: %2 - swch", "Switch color").arg(num).arg(str1); } else { msg = QString("%1: %2 - %3%4").arg(num).arg(str1) .arg(horHeaderString.at(x)) .arg(QString::number(y + 1)); } QListWidgetItem *item = new QListWidgetItem(msg, ui->lsTurnsList); item->setData(Qt::UserRole, x); item->setData(Qt::UserRole + 1, y); //item->setFlags((item->flags() | Qt::ItemIsUserCheckable) & ~Qt::ItemIsUserCheckable); ui->lsTurnsList->addItem(item); ui->lsTurnsList->setCurrentItem(item); } /** * Подтверждение последнего хода в списке */ void PluginWindow::acceptStep() { // Визуальное отображение подтвержденного хода } /** * Пришло подтверждение от оппонента */ void PluginWindow::setAccept() { bmodel->setAccept(); acceptStep(); } /** * Пришел ход от противника */ void PluginWindow::setTurn(int x, int y) { if (bmodel) { if (bmodel->opponentTurn(x, y)) { appendTurn(bmodel->turnNum() - 1, x, y, false); emit accepted(); if (bmodel->turnNum() == 4) { // Ходы сквозные, значит 4й всегда белые ui->actionSwitchColor->setEnabled(true); doSwitchColor(); } return; } } emit error(); } /** * Оппонент поменял цвет */ void PluginWindow::setSwitchColor() { if (bmodel->doSwitchColor(false)) { ui->hintElement->setElementType(GameElement::TypeWhite); appendTurn(bmodel->turnNum() - 1, -1, -1, false); emit accepted(); } else { emit error(); } } /** * Пришла ошибка от противника */ void PluginWindow::setError() { bmodel->setError(); QMessageBox *msgBox = new QMessageBox(this); msgBox->setIcon(QMessageBox::Warning); msgBox->setWindowTitle(tr("Gomoku Plugin")); msgBox->setText(tr("Game Error!")); msgBox->setStandardButtons(QMessageBox::Ok); msgBox->setWindowModality(Qt::WindowModal); msgBox->exec(); delete msgBox; } /** * Оппонент закрыл игровую доску. */ void PluginWindow::setClose() { bmodel->setClose(); QMessageBox *msgBox = new QMessageBox(this); msgBox->setIcon(QMessageBox::Warning); msgBox->setWindowTitle(tr("Gomoku Plugin")); msgBox->setText(tr("Your opponent has closed the board!\n You can still save the game.")); msgBox->setStandardButtons(QMessageBox::Ok); msgBox->setWindowModality(Qt::WindowModal); msgBox->exec(); delete msgBox; } /** * Реакция на закрытие нашей доски */ void PluginWindow::closeEvent (QCloseEvent *event) { emit closeBoard(gameActive, y(), x(), width(), height()); // Отправляем сообщение оппоненту gameActive = false; event->accept(); } /** * Предлагаем сменить цвет */ void PluginWindow::doSwitchColor() { QMessageBox *msgBox = new QMessageBox(this); msgBox->setIcon(QMessageBox::Question); msgBox->setWindowTitle(tr("Gomoku Plugin")); msgBox->setText(tr("You want to switch color?")); msgBox->setStandardButtons(QMessageBox::Yes | QMessageBox::No); msgBox->setDefaultButton(QMessageBox::No); msgBox->setWindowModality(Qt::WindowModal); int res = msgBox->exec(); delete msgBox; if (res == QMessageBox::Yes) { if (bmodel->doSwitchColor(true)) { ui->hintElement->setElementType(GameElement::TypeBlack); appendTurn(bmodel->turnNum() - 1, -1, -1, true); } } } /** * Мы проиграли выставляем сигнал и показываем сообщение */ void PluginWindow::setLose() { emit lose(); QMessageBox *msgBox = new QMessageBox(this); msgBox->setIcon(QMessageBox::Information); msgBox->setWindowTitle(tr("Gomoku Plugin")); msgBox->setText(tr("You Lose.")); msgBox->setStandardButtons(QMessageBox::Ok); msgBox->setWindowModality(Qt::WindowModal); msgBox->exec(); delete msgBox; } /** * Ничья выставляем сигнал и показываем сообщение */ void PluginWindow::setDraw() { emit draw(); showDraw(); } /** * Мы сдались (выбран пункт меню "Resign" на доске) */ void PluginWindow::setResign() { bmodel->setResign(); } /** * Сообщение о том что оппонент проиграл, т.е. мы выиграли */ void PluginWindow::setWin() { bmodel->setWin(); QMessageBox *msgBox = new QMessageBox(this); msgBox->setIcon(QMessageBox::Information); msgBox->setWindowTitle(tr("Gomoku Plugin")); msgBox->setText(tr("You Win!")); msgBox->setStandardButtons(QMessageBox::Ok); msgBox->setWindowModality(Qt::WindowModal); msgBox->exec(); delete msgBox; } /** * Обработчик начала новой игры. Запрос у пользователя и отсылка сигнала */ void PluginWindow::newGame() { QMessageBox *msgBox = new QMessageBox(this); msgBox->setIcon(QMessageBox::Question); msgBox->setWindowTitle(tr("Gomoku Plugin")); msgBox->setText(tr("You really want to begin new game?")); msgBox->setStandardButtons(QMessageBox::Yes | QMessageBox::No); msgBox->setWindowModality(Qt::WindowModal); int res = msgBox->exec(); delete msgBox; if (res == QMessageBox::Yes) { emit sendNewInvite(); } } /** * Обработчик сохранения игры */ void PluginWindow::saveGame() { QString fileName = QFileDialog::getSaveFileName(this, tr("Save game"), "", fileFilter); if (fileName.isEmpty()) return; if (fileName.right(4) != ".gmk") fileName.append(".gmk"); QFile file(fileName); if (file.open(QIODevice::WriteOnly | QIODevice::Truncate)) { QTextStream out(&file); out.setCodec("UTF-8"); out.setGenerateByteOrderMark(false); out << bmodel->saveToString(); } } /** * Обработчик загрузки игры с локального файла */ void PluginWindow::loadGame() { QString fileName = QFileDialog::getOpenFileName(this, tr("Load game"), "", fileFilter); if (fileName.isEmpty()) return; QFile file(fileName); if(file.open(QIODevice::ReadOnly)) { QTextStream in(&file); in.setCodec("UTF-8"); QString saved_str = in.readAll(); saved_str.replace("\n", ""); if (tryLoadGame(saved_str, true)) { emit load(saved_str); } } } /** * Обработчик загрузки игры, посланной оппонентом */ void PluginWindow::loadRemoteGame(QString load_str) { if (tryLoadGame(load_str, false)) { emit accepted(); return; } emit error(); } /** * Попытка создать модель игры по данным из строки load_str * При удачной попытке модель игровой доски инициируется с новыми данными игры */ bool PluginWindow::tryLoadGame(const QString &load_str, bool local) { if (!load_str.isEmpty()) { GameModel *gm = new GameModel(load_str, local); if (gm->isValid()) { QString info = gm->gameInfo(); QMessageBox *msgBox = new QMessageBox(this); msgBox->setIcon(QMessageBox::Question); msgBox->setWindowTitle(tr("Gomoku Plugin")); info.append("\n").append(tr("You really want to begin loaded game?")); msgBox->setText(info); msgBox->setStandardButtons(QMessageBox::Yes | QMessageBox::No); msgBox->setWindowModality(Qt::WindowModal); int res = msgBox->exec(); delete msgBox; if (res == QMessageBox::Yes) { // Инициализация модели игровой доски новыми данными bmodel->init(gm); ui->hintElement->setElementType(gm->myElementType()); // Загрузка списка ходов ui->lsTurnsList->clear(); for (int i = 1, cnt = gm->turnsCount(); i <= cnt; i++) { GameModel::TurnInfo turn = gm->turnInfo(i); appendTurn(i, turn.x, turn.y, turn.my); } return true; } } delete gm; } return false; } /** * Выбрано новое оформление (Скин) */ void PluginWindow::setSkin() { QObject *sender_ = sender(); if (sender_ == ui->actionSkin0) { ui->actionSkin0->setChecked(true); ui->actionSkin1->setChecked(false); delegate->setSkin(0); } else if (sender_ == ui->actionSkin1) { ui->actionSkin1->setChecked(true); ui->actionSkin0->setChecked(false); delegate->setSkin(1); } ui->board->repaint(); } /** * Обработчик предложения оппонентом ничьей */ void PluginWindow::opponentDraw() { bmodel->opponentDraw(); showDraw(); } /** * Отображение стандартного диалогового окна, сообщающего об ничьей */ void PluginWindow::showDraw() { QMessageBox *msgBox = new QMessageBox(this); msgBox->setIcon(QMessageBox::Information); msgBox->setWindowTitle(tr("Gomoku Plugin")); msgBox->setText(tr("Draw.")); msgBox->setStandardButtons(QMessageBox::Ok); msgBox->setWindowModality(Qt::WindowModal); msgBox->exec(); delete msgBox; } plugins-1.5/generic/gomokugameplugin/pluginwindow.h000066400000000000000000000054431336777360500227540ustar00rootroot00000000000000/* * pluginwindow.h - Gomoku Game plugin * Copyright (C) 2011 Aleksey Andreev * * 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. * * You can also redistribute and/or modify this program under the * terms of the Psi License, specified in the accompanied COPYING * file, as published by the Psi Project; either dated January 1st, * 2005, 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef PLUGINWINDOW_H #define PLUGINWINDOW_H #include #include #include "gameelement.h" #include "boardmodel.h" #include "boarddelegate.h" namespace Ui { class PluginWindow; } using namespace GomokuGame; class HintElementWidget : public QFrame { Q_OBJECT public: HintElementWidget(QWidget *parent = 0); ~HintElementWidget(); void setElementType(GameElement::ElementType type); private: GameElement* hintElement; protected: virtual void paintEvent(QPaintEvent *event); }; class PluginWindow : public QMainWindow { Q_OBJECT public: PluginWindow(QString full_jid, QWidget *parent = 0); ~PluginWindow(); void init(QString element); private: Ui::PluginWindow *ui; BoardModel *bmodel; BoardDelegate *delegate; bool gameActive; private: void endGame(); void appendTurn(int num, int x, int y, bool my_turn); bool tryLoadGame(const QString &load_str, bool local); void showDraw(); protected: virtual void closeEvent (QCloseEvent *event); private slots: void changeGameStatus(GameModel::GameStatus status); void turnSelected(); void setupElement(int x, int y); void acceptStep(); void setAccept(); void setError(); void setTurn(int, int); void setSwitchColor(); void doSwitchColor(); void setLose(); void setDraw(); void setResign(); void setWin(); void setClose(); void newGame(); void saveGame(); void loadGame(); void loadRemoteGame(QString); void opponentDraw(); void setSkin(); signals: void changeGameSession(QString); void closeBoard(bool, int, int, int, int); void setElement(int, int); void accepted(); void error(); void lose(); void draw(); void switchColor(); void load(QString); void sendNewInvite(); void doPopup(const QString); void playSound(const QString); }; #endif // PLUGINWINDOW_H plugins-1.5/generic/gomokugameplugin/pluginwindow.ui000066400000000000000000000302611336777360500231360ustar00rootroot00000000000000 PluginWindow 0 0 535 488 Gomoku Game Opponent: 0 0 75 true Qt::Horizontal 40 20 Status: 0 0 75 true Qt::Horizontal 40 20 1 0 true QAbstractItemView::SingleSelection false false false Qt::Horizontal Qt::Horizontal 0 20 110 110 110 110 110 110 QFrame::StyledPanel QFrame::Raised Qt::Horizontal 0 20 Qt::Horizontal 135 0 135 16777215 Qt::ScrollBarAlwaysOn Qt::ScrollBarAlwaysOff 0 0 535 21 Game Skin File New game Load game Save game Quit Resign Switch color true true Standard true Yellow wood BoardView QTableView
boardview.h
HintElementWidget QFrame
pluginwindow.h
1
actionQuit triggered() PluginWindow close() -1 -1 205 198 actionSwitchColor triggered() PluginWindow doSwitchColor() -1 -1 205 198 actionSaveGame triggered() PluginWindow saveGame() -1 -1 205 198 actionLoadGame triggered() PluginWindow loadGame() -1 -1 205 198 actionResign triggered() PluginWindow setResign() -1 -1 205 198 lsTurnsList currentItemChanged(QListWidgetItem*,QListWidgetItem*) PluginWindow turnSelected() 438 328 249 234 actionNewGame triggered() PluginWindow newGame() -1 -1 249 234 actionSkin0 triggered() PluginWindow setSkin() -1 -1 249 234 actionSkin1 triggered() PluginWindow setSkin() -1 -1 249 234 doSwitchColor() saveGame() loadGame() setResign() turnSelected() newGame() setSkin()
plugins-1.5/generic/historykeeperplugin/000077500000000000000000000000001336777360500206115ustar00rootroot00000000000000plugins-1.5/generic/historykeeperplugin/CMakeLists.txt000066400000000000000000000024211336777360500233500ustar00rootroot00000000000000unset(_HDRS) unset(_UIS) unset(_SRCS) unset(_RSCS) unset(PLUGIN) set( PLUGIN historykeeperplugin ) project(${PLUGIN}) cmake_minimum_required(VERSION 3.1.0) set( CMAKE_AUTOMOC TRUE ) IF( NOT WIN32 ) set( LIB_SUFFIX "" CACHE STRING "Define suffix of directory name (32/64)" ) set( PLUGINS_PATH "lib${LIB_SUFFIX}/psi-plus/plugins" CACHE STRING "Install suffix for plugins" ) ELSE() set( PLUGINS_PATH "psi-plus/plugins" CACHE STRING "Install suffix for plugins" ) ENDIF() add_definitions( -DQT_PLUGIN -DHAVE_QT5 ) include_directories( ${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ../../include . ) set( _SRCS ${PLUGIN}.cpp ) set( _RSCS resources.qrc ) find_package( Qt5 COMPONENTS Widgets Xml REQUIRED ) set(QT_DEPLIBS Qt5::Widgets Qt5::Xml ) qt5_add_resources(RSCS ${_RSCS}) add_library( ${PLUGIN} MODULE ${_SRCS} ${UIS} ${RSCS} ) target_link_libraries( ${PLUGIN} ${QT_DEPLIBS} ) if( UNIX AND NOT( APPLE OR CYGWIN ) ) install( TARGETS ${PLUGIN} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} ) endif() if( WIN32 ) install( TARGETS ${PLUGIN} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} ) endif() plugins-1.5/generic/historykeeperplugin/changelog.txt000066400000000000000000000021351336777360500233020ustar00rootroot000000000000002013-08-13 v0.0.7 - taurus + Иконка плагина 2011-10-25 v0.0.6 * улучшен пункт меню контакта * некоторые иправления 2010-09-11 v0.0.5 * обновлена ссылка на wiki ( http://psi-plus.com/wiki/plugins#history_keeper_plugin ) 2010-05-17 v0.0.4 + добавлена информация о плагине 2010-05-04 v0.0.3 * исправлена ссылка на wiki 2010-03-10 v0.0.2 * исправлен вывод дебаг-информации + добавлена возможность снимать отметку с контактов через контекстное меню контакта 2010-03-09 v0.0.1 ! initial version Данный плагин предназначен для удаления истории отмеченных контактов при выходе из Psi+. Отметить контакт можно из контекстного меню контакта, либо через опции плагина. Удалить отметку - только через опции. plugins-1.5/generic/historykeeperplugin/historykeeper.png000066400000000000000000000012771336777360500242230ustar00rootroot00000000000000PNG  IHDRatEXtSoftwareAdobe ImageReadyqe<aIDATxڌR;hTA=]!)T ?Vv6V ʠXPh! bPbb)EĈ &}vgfwޮ,ـ̛ݙ{=#̼0d`} j_8x\c'wGAiM ϕ?3 m4JaQ c<"R+GwAS[A PJ g\} Ŗ{/u Tc(ޮ@(akD)j2"e ! Ǿsr⸈,,C$ 1XXE9rK׍o.!f ,2j[udriӤ Ul/gGQ@yFDYV!}{]~?!O@%)ꆝB8挹6:now,1҃/_)x,c-KH?lCW`68ؿ=q #t !ZCNH˩4^s0Ki#V-%BEahgb4^GR)~y~T\Zh7] S:py,4ä?[;/ԋ(Bnn/v?i/`e0 Q`IENDB`plugins-1.5/generic/historykeeperplugin/historykeeperplugin.cpp000066400000000000000000000170751336777360500254430ustar00rootroot00000000000000/* * historykeeperplugin.cpp - plugin * Copyright (C) 2010-2011 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include #include #include #include #include #include "psiplugin.h" #include "applicationinfoaccessor.h" #include "applicationinfoaccessinghost.h" #include "optionaccessor.h" #include "optionaccessinghost.h" #include "menuaccessor.h" #include "plugininfoprovider.h" #include "iconfactoryaccessinghost.h" #include "iconfactoryaccessor.h" #define cVer "0.0.7" #define constClearHistoryFor "clear-history-for" class HistoryKeeperPlugin: public QObject, public PsiPlugin, public ApplicationInfoAccessor, public OptionAccessor, public MenuAccessor, public PluginInfoProvider, public IconFactoryAccessor { Q_OBJECT #ifdef HAVE_QT5 Q_PLUGIN_METADATA(IID "com.psi-plus.HistoryKeeperPlugin") #endif Q_INTERFACES(PsiPlugin OptionAccessor ApplicationInfoAccessor MenuAccessor PluginInfoProvider IconFactoryAccessor) public: HistoryKeeperPlugin(); virtual QString name() const; virtual QString shortName() const; virtual QString version() const; virtual QWidget* options(); virtual bool enable(); virtual bool disable(); virtual void applyOptions(); virtual void restoreOptions(); virtual void setApplicationInfoAccessingHost(ApplicationInfoAccessingHost* host); virtual void setOptionAccessingHost(OptionAccessingHost* host); virtual void setIconFactoryAccessingHost(IconFactoryAccessingHost* host); virtual void optionChanged(const QString& /*option*/) {}; virtual QList < QVariantHash > getAccountMenuParam(); virtual QList < QVariantHash > getContactMenuParam(); virtual QAction* getContactAction(QObject* p, int acc, const QString& jid); virtual QAction* getAccountAction(QObject* , int ) { return 0; }; virtual QString pluginInfo(); virtual QPixmap icon() const; private: void removeHistory(); static QString nameToFilename(const QString& jid); void addContact(const QString& jid); void removeContact(const QString& jid); private slots: void actionActivated(bool); private: bool enabled; OptionAccessingHost* psiOptions; ApplicationInfoAccessingHost *appInfo; IconFactoryAccessingHost* icoHost; QPointer contactsWidget; QStringList contacts; }; #ifndef HAVE_QT5 Q_EXPORT_PLUGIN(HistoryKeeperPlugin); #endif HistoryKeeperPlugin::HistoryKeeperPlugin() : enabled(false) , psiOptions(0) , appInfo(0) , icoHost(0) , contactsWidget(0) { } QString HistoryKeeperPlugin::name() const { return "History Keeper Plugin"; } QString HistoryKeeperPlugin::shortName() const { return "historykeeper"; } QString HistoryKeeperPlugin::version() const { return cVer; } bool HistoryKeeperPlugin::enable() { if(psiOptions) { enabled = true; contacts = psiOptions->getPluginOption(constClearHistoryFor, QVariant(contacts)).toStringList(); } return enabled; } bool HistoryKeeperPlugin::disable() { removeHistory(); enabled = false; return true; } void HistoryKeeperPlugin::removeHistory() { if(!enabled) return; QString historyDir(appInfo->appHistoryDir()); foreach(QString jid, contacts) { jid = nameToFilename(jid); QString fileName = historyDir + QDir::separator() + jid; QFile file(fileName); if(file.open(QIODevice::ReadWrite)) { qDebug("Removing file %s", qPrintable(fileName)); file.remove(); } } } QString HistoryKeeperPlugin::nameToFilename(const QString& jid) { QString jid2; for(int n = 0; n < jid.length(); ++n) { if(jid.at(n) == '@') { jid2.append("_at_"); } else if(jid.at(n) == '.') { jid2.append('.'); } else if(!jid.at(n).isLetterOrNumber()) { // hex encode QString hex; hex.sprintf("%%%02X", jid.at(n).toLatin1()); jid2.append(hex); } else { jid2.append(jid.at(n)); } } return jid2.toLower() + ".history"; } QWidget* HistoryKeeperPlugin::options() { if(!enabled) { return 0; } QWidget *options = new QWidget(); QVBoxLayout *layout = new QVBoxLayout(options); contactsWidget = new QTextEdit(); QString text; foreach(QString contact, contacts) { text += contact + "\n"; } contactsWidget->setMaximumWidth(300); contactsWidget->setText(text); QLabel *wikiLink = new QLabel(tr("Wiki (Online)")); wikiLink->setOpenExternalLinks(true); layout->addWidget(new QLabel(tr("Remove history for contacts:"))); layout->addWidget(contactsWidget); layout->addWidget(wikiLink); return options; } void HistoryKeeperPlugin::addContact(const QString& jid) { if(!contacts.contains(jid)) { contacts.append(jid); psiOptions->setPluginOption(constClearHistoryFor, QVariant(contacts)); restoreOptions(); } } void HistoryKeeperPlugin::removeContact(const QString& jid) { if(contacts.contains(jid)) { contacts.removeAt(contacts.indexOf(jid)); psiOptions->setPluginOption(constClearHistoryFor, QVariant(contacts)); restoreOptions(); } } void HistoryKeeperPlugin::actionActivated(bool check) { QString jid = sender()->property("jid").toString(); if(check) addContact(jid) ; else removeContact(jid); } void HistoryKeeperPlugin::applyOptions() { if(!contactsWidget) return; contacts = contactsWidget->toPlainText().split(QRegExp("\\s+"), QString::SkipEmptyParts); psiOptions->setPluginOption(constClearHistoryFor, QVariant(contacts)); } void HistoryKeeperPlugin::restoreOptions() { if(!contactsWidget) return; QString text; foreach(const QString& contact, contacts) { text += contact + "\n"; } contactsWidget->setText(text); } void HistoryKeeperPlugin::setApplicationInfoAccessingHost(ApplicationInfoAccessingHost* host) { appInfo = host; } void HistoryKeeperPlugin::setIconFactoryAccessingHost(IconFactoryAccessingHost *host) { icoHost = host; } void HistoryKeeperPlugin::setOptionAccessingHost(OptionAccessingHost* host) { psiOptions = host; } QList < QVariantHash > HistoryKeeperPlugin::getAccountMenuParam() { return QList < QVariantHash >(); } QList < QVariantHash > HistoryKeeperPlugin::getContactMenuParam() { return QList < QVariantHash >(); } QAction* HistoryKeeperPlugin::getContactAction(QObject *p, int /*acc*/, const QString &jid) { QAction* act = new QAction(icoHost->getIcon("psi/clearChat"), tr("Clear history on exit"), p); act->setCheckable(true); act->setChecked(contacts.contains(jid)); act->setProperty("jid", jid); connect(act, SIGNAL(triggered(bool)), SLOT(actionActivated(bool))); return act; } QString HistoryKeeperPlugin::pluginInfo() { return tr("Author: ") + "Dealer_WeARE\n" + tr("Email: ") + "wadealer@gmail.com\n\n" + trUtf8("This plugin is designed to remove the history of selected contacts when the Psi+ is closed.\n" "You can select or deselect a contact for history removal from the context menu of a contact or via the plugin options."); } QPixmap HistoryKeeperPlugin::icon() const { return QPixmap(":/icons/historykeeper.png"); } #include "historykeeperplugin.moc" plugins-1.5/generic/historykeeperplugin/historykeeperplugin.pro000066400000000000000000000002501336777360500254440ustar00rootroot00000000000000isEmpty(PSISDK) { include(../../psiplugin.pri) } else { include($$PSISDK/plugins/psiplugin.pri) } SOURCES += historykeeperplugin.cpp RESOURCES += resources.qrc plugins-1.5/generic/historykeeperplugin/resources.qrc000066400000000000000000000001451336777360500233320ustar00rootroot00000000000000 historykeeper.png plugins-1.5/generic/httpuploadplugin/000077500000000000000000000000001336777360500201005ustar00rootroot00000000000000plugins-1.5/generic/httpuploadplugin/CMakeLists.txt000066400000000000000000000026571336777360500226520ustar00rootroot00000000000000unset(_HDRS) unset(_UIS) unset(_SRCS) unset(_RSCS) unset(PLUGIN) set( PLUGIN httpuploadplugin ) project(${PLUGIN}) cmake_minimum_required(VERSION 3.1.0) set( CMAKE_AUTOMOC TRUE ) IF( NOT WIN32 ) set( LIB_SUFFIX "" CACHE STRING "Define suffix of directory name (32/64)" ) set( PLUGINS_PATH "lib${LIB_SUFFIX}/psi-plus/plugins" CACHE STRING "Install suffix for plugins" ) ELSE() set( PLUGINS_PATH "psi-plus/plugins" CACHE STRING "Install suffix for plugins" ) ENDIF() add_definitions( -DQT_PLUGIN -DHAVE_QT5 ) include_directories( ${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ../../include . ) set( _SRCS ${PLUGIN}.cpp uploadservice.cpp previewfiledialog.cpp ) set( _HDRS currentupload.h previewfiledialog.h uploadservice.h ) set( _RSCS ${PLUGIN}.qrc ) add_definitions(-DHAVE_QT5) find_package( Qt5 COMPONENTS Widgets Xml Network REQUIRED ) set(QT_DEPLIBS Qt5::Widgets Qt5::Network Qt5::Xml ) qt5_add_resources(RSCS ${_RSCS}) add_library( ${PLUGIN} MODULE ${_SRCS} ${UIS} ${RSCS} ) target_link_libraries( ${PLUGIN} ${QT_DEPLIBS} ) if( UNIX AND NOT( APPLE OR CYGWIN ) ) install( TARGETS ${PLUGIN} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} ) endif() if( WIN32 ) install( TARGETS ${PLUGIN} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} ) endif() plugins-1.5/generic/httpuploadplugin/currentupload.h000066400000000000000000000006251336777360500231430ustar00rootroot00000000000000/* * CurrentUpload.h * * Created on: 24 Sep 2016 * Author: rkfg */ #ifndef SRC_PLUGINS_GENERIC_HTTPUPLOADPLUGIN_CURRENTUPLOAD_H_ #define SRC_PLUGINS_GENERIC_HTTPUPLOADPLUGIN_CURRENTUPLOAD_H_ struct CurrentUpload { QString from; QString to; int account; QString getUrl; QString type; CurrentUpload(): account(-1) {} }; #endif /* SRC_PLUGINS_GENERIC_HTTPUPLOADPLUGIN_CURRENTUPLOAD_H_ */ plugins-1.5/generic/httpuploadplugin/httpuploadplugin.cpp000066400000000000000000000542131336777360500242140ustar00rootroot00000000000000/* * httpuploadplugin.cpp - plugin * Copyright (C) 2016 rkfg * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "psiplugin.h" #include "activetabaccessinghost.h" #include "activetabaccessor.h" #include "toolbariconaccessor.h" #include "iconfactoryaccessor.h" #include "iconfactoryaccessinghost.h" #include "gctoolbariconaccessor.h" #include "stanzasender.h" #include "stanzasendinghost.h" #include "accountinfoaccessinghost.h" #include "accountinfoaccessor.h" #include "plugininfoprovider.h" #include "psiaccountcontroller.h" #include "psiaccountcontrollinghost.h" #include "optionaccessinghost.h" #include "optionaccessor.h" #include "applicationinfoaccessor.h" #include "applicationinfoaccessinghost.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "chattabaccessor.h" #include "stanzafilter.h" #include #include "uploadservice.h" #include "currentupload.h" #include #include #include "previewfiledialog.h" //#define DEBUG_UPLOAD #define constVersion "0.1.0" #define CONST_LAST_FOLDER "httpupload-lastfolder" #define SLOT_TIMEOUT 10000 #define OPTION_RESIZE "httpupload-do-resize" #define OPTION_SIZE "httpupload-image-size" #define OPTION_QUALITY "httpupload-image-quality" #define OPTION_PREVIEW_WIDTH "httpupload-preview-width" #if (!defined HAVE_QT5 && QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) #define HAVE_QT5 #endif QString escape(const QString &plain) { #ifdef HAVE_QT5 return plain.toHtmlEscaped(); #else return Qt::escape(plain); #endif } class HttpUploadPlugin: public QObject, public PsiPlugin, public ToolbarIconAccessor, public GCToolbarIconAccessor, public StanzaSender, public IconFactoryAccessor, public ActiveTabAccessor, public PluginInfoProvider, public AccountInfoAccessor, public PsiAccountController, public OptionAccessor, public ChatTabAccessor, public StanzaFilter, public ApplicationInfoAccessor { Q_OBJECT #ifdef HAVE_QT5 Q_PLUGIN_METADATA(IID "com.psi-plus.HttpUploadPlugin") #endif Q_INTERFACES(PsiPlugin ToolbarIconAccessor GCToolbarIconAccessor StanzaSender ActiveTabAccessor PsiAccountController OptionAccessor IconFactoryAccessor AccountInfoAccessor PluginInfoProvider ChatTabAccessor StanzaFilter ApplicationInfoAccessor) public: HttpUploadPlugin(); virtual QString name() const; virtual QString shortName() const; virtual QString version() const; virtual QWidget* options(); virtual bool enable(); virtual bool disable(); virtual void applyOptions(); virtual void restoreOptions(); virtual QList getButtonParam(); virtual QAction* getAction(QObject*, int, const QString&) { return 0; } virtual QList getGCButtonParam(); virtual QAction* getGCAction(QObject*, int, const QString&) { return 0; } virtual void setIconFactoryAccessingHost(IconFactoryAccessingHost* host); virtual void setStanzaSendingHost(StanzaSendingHost *host); virtual void setActiveTabAccessingHost(ActiveTabAccessingHost* host); virtual void setAccountInfoAccessingHost(AccountInfoAccessingHost* host); virtual void setPsiAccountControllingHost(PsiAccountControllingHost *host); virtual void setOptionAccessingHost(OptionAccessingHost *host); virtual void optionChanged(const QString &) { } virtual QString pluginInfo(); virtual QPixmap icon() const; virtual void setupChatTab(QWidget*, int account, const QString&) { checkUploadAvailability(account); } virtual void setupGCTab(QWidget*, int account, const QString&) { checkUploadAvailability(account); } virtual bool appendingChatMessage(int, const QString&, QString&, QDomElement&, bool) { return false; } virtual bool incomingStanza(int account, const QDomElement& xml); virtual bool outgoingStanza(int, QDomElement &) { return false; } QString getId(int account) { return stanzaSender->uniqueId(account); } void checkUploadAvailability(int account); void setApplicationInfoAccessingHost(ApplicationInfoAccessingHost* host); void updateProxy(); private slots: void uploadFile(); void uploadImage(); void uploadComplete(QNetworkReply* reply); void timeout(); void resizeStateChanged(int state); void handleSslError(QNetworkReply* reply, const QList& errors); private: void upload(bool anything); int accountNumber() { QString jid = activeTab->getYourJid(); QString jidToSend = activeTab->getJid(); int account = 0; QString tmpJid(""); while (jid != (tmpJid = accInfo->getJid(account))) { ++account; if (tmpJid == "-1") return -1; } return account; } void cancelTimeout() { slotTimeout.stop(); if (dataSource) { dataSource->deleteLater(); } if (imageBytes) { delete imageBytes; imageBytes = 0; } } void processServices(const QDomElement& query, int account); void processOneService(const QDomElement& query, const QString& service, int account); void processUploadSlot(const QDomElement& xml); IconFactoryAccessingHost* iconHost; StanzaSendingHost* stanzaSender; ActiveTabAccessingHost* activeTab; AccountInfoAccessingHost* accInfo; PsiAccountControllingHost *psiController; OptionAccessingHost *psiOptions; ApplicationInfoAccessingHost* appInfoHost; bool enabled; QHash accounts_; QNetworkAccessManager* manager; QMap serviceNames; QPointer dataSource; QByteArray* imageBytes; CurrentUpload currentUpload; QTimer slotTimeout; QSpinBox *sb_previewWidth; QCheckBox *cb_resize; QSpinBox *sb_size; QSpinBox *sb_quality; bool imageResize; int imageSize; int imageQuality; int previewWidth; }; #ifndef HAVE_QT5 Q_EXPORT_PLUGIN(HttpUploadPlugin) #endif HttpUploadPlugin::HttpUploadPlugin() : iconHost(0), stanzaSender(0), activeTab(0), accInfo(0), psiController(0), psiOptions(0), appInfoHost(0), enabled( false), manager(new QNetworkAccessManager(this)), imageBytes(0), sb_previewWidth(0), cb_resize(0), sb_size( 0), sb_quality(0), imageResize(false), imageSize(0), imageQuality(0), previewWidth(0) { connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(uploadComplete(QNetworkReply*))); connect(&slotTimeout, SIGNAL(timeout()), this, SLOT(timeout())); connect(manager, SIGNAL(sslErrors(QNetworkReply*, const QList&)), this, SLOT(handleSslError(QNetworkReply*, const QList&))); slotTimeout.setSingleShot(true); } QString HttpUploadPlugin::name() const { return "HTTP Upload Plugin"; } QString HttpUploadPlugin::shortName() const { return "httpupload"; } QString HttpUploadPlugin::version() const { return constVersion; } bool HttpUploadPlugin::enable() { QFile image_icon(":/httpuploadplugin/upload_image.png"); QByteArray image; enabled = true; if (image_icon.open(QIODevice::ReadOnly)) { image = image_icon.readAll(); iconHost->addIcon("httpuploadplugin/upload_image", image); image_icon.close(); } else { enabled = false; } QFile file_icon(":/httpuploadplugin/upload_file.png"); if (file_icon.open(QIODevice::ReadOnly)) { image = file_icon.readAll(); iconHost->addIcon("httpuploadplugin/upload_file", image); file_icon.close(); } else { enabled = false; } imageResize = psiOptions->getPluginOption(OPTION_RESIZE, false).toBool(); imageSize = psiOptions->getPluginOption(OPTION_SIZE, 1024).toInt(); imageQuality = psiOptions->getPluginOption(OPTION_QUALITY, 75).toInt(); previewWidth = psiOptions->getPluginOption(OPTION_PREVIEW_WIDTH, 150).toInt(); updateProxy(); return enabled; } bool HttpUploadPlugin::disable() { enabled = false; return true; } QWidget* HttpUploadPlugin::options() { if (!enabled) { return 0; } QWidget *optionsWid = new QWidget(); QVBoxLayout *vbox = new QVBoxLayout(optionsWid); vbox->addWidget(new QLabel(tr("Image preview width"))); sb_previewWidth = new QSpinBox(); sb_previewWidth->setMinimum(1); sb_previewWidth->setMaximum(65535); vbox->addWidget(sb_previewWidth); cb_resize = new QCheckBox(tr("Resize images")); vbox->addWidget(cb_resize); vbox->addWidget(new QLabel(tr("If width or height is bigger than"))); sb_size = new QSpinBox(); sb_size->setMinimum(1); sb_size->setMaximum(65535); sb_size->setEnabled(false); vbox->addWidget(sb_size); vbox->addWidget(new QLabel(tr("JPEG quality"))); sb_quality = new QSpinBox(); sb_quality->setMinimum(1); sb_quality->setMaximum(100); sb_quality->setEnabled(false); vbox->addWidget(sb_quality); vbox->addStretch(); connect(cb_resize, SIGNAL(stateChanged(int)), this, SLOT(resizeStateChanged(int))); updateProxy(); return optionsWid; } QList HttpUploadPlugin::getButtonParam() { QList l; QVariantHash uploadImg; uploadImg["tooltip"] = tr("Upload Image"); uploadImg["icon"] = QString("httpuploadplugin/upload_image"); uploadImg["reciver"] = qVariantFromValue(qobject_cast(this)); uploadImg["slot"] = QVariant(SLOT(uploadImage())); l.push_back(uploadImg); QVariantHash uploadFile; uploadFile["tooltip"] = tr("Upload File"); uploadFile["icon"] = QString("httpuploadplugin/upload_file"); uploadFile["reciver"] = qVariantFromValue(qobject_cast(this)); uploadFile["slot"] = QVariant(SLOT(uploadFile())); l.push_back(uploadFile); return l; } QList HttpUploadPlugin::getGCButtonParam() { return getButtonParam(); } void HttpUploadPlugin::setAccountInfoAccessingHost(AccountInfoAccessingHost* host) { accInfo = host; } void HttpUploadPlugin::setIconFactoryAccessingHost(IconFactoryAccessingHost* host) { iconHost = host; } void HttpUploadPlugin::setPsiAccountControllingHost(PsiAccountControllingHost *host) { psiController = host; } void HttpUploadPlugin::setOptionAccessingHost(OptionAccessingHost *host) { psiOptions = host; } void HttpUploadPlugin::setStanzaSendingHost(StanzaSendingHost *host) { stanzaSender = host; } void HttpUploadPlugin::setActiveTabAccessingHost(ActiveTabAccessingHost* host) { activeTab = host; } void HttpUploadPlugin::uploadFile() { upload(true); } void HttpUploadPlugin::uploadImage() { upload(false); } void HttpUploadPlugin::upload(bool anything) { if (!enabled) return; if (dataSource) { QMessageBox::warning(0, tr("Please wait"), tr( "Another upload operation is already in progress. Please wait up to %1 sec for it to complete or fail.").arg( SLOT_TIMEOUT / 1000)); return; } if (imageBytes) { delete imageBytes; imageBytes = 0; } QString serviceName; int sizeLimit = -1; int account = accountNumber(); QString curJid = accInfo->getJid(account); QMap::iterator iter = serviceNames.find(curJid); if (iter == serviceNames.end()) { QMessageBox::critical(0, tr("Not supported"), tr("Server for account %1 does not support HTTP Upload (XEP-363)").arg(curJid)); return; } serviceName = iter->serviceName(); sizeLimit = iter->sizeLimit(); QString fileName; QString jid = activeTab->getYourJid(); QString jidToSend = activeTab->getJid(); if ("offline" == accInfo->getStatus(account)) { return; } QString imageName; const QString lastPath = psiOptions->getPluginOption(CONST_LAST_FOLDER, QDir::homePath()).toString(); PreviewFileDialog dlg(0, anything ? tr("Upload file") : tr("Upload image"), lastPath, anything ? "" : tr("Images (*.png *.gif *.jpg *.jpeg)"), previewWidth); dlg.setAcceptMode(QFileDialog::AcceptOpen); if (!dlg.exec()) { return; } fileName = dlg.selectedFiles()[0]; QFile file(fileName); QFileInfo fileInfo(file); QPixmap pix(fileName); imageName = fileInfo.fileName(); psiOptions->setPluginOption(CONST_LAST_FOLDER, fileInfo.path()); #ifndef HAVE_QT5 QString mimeType("application/octet-stream"); #else // prosody requires a proper type now QMimeDatabase db; QString mimeType(db.mimeTypeForFile(imageName).name()); #ifdef DEBUG_UPLOAD qDebug() << "MIME type:" << mimeType; #endif #endif int length; QString lowerImagename = imageName.toLower(); // only resize jpg and png if (!anything && imageResize && (lowerImagename.endsWith(".jpg") || lowerImagename.endsWith(".jpeg") || lowerImagename.endsWith(".png")) && (pix.width() > imageSize || pix.height() > imageSize)) { imageBytes = new QByteArray(); dataSource = new QBuffer(imageBytes); QString type = "jpg"; if (lowerImagename.endsWith(".png")) { type = "png"; } pix.scaled(imageSize, imageSize, Qt::KeepAspectRatio, Qt::SmoothTransformation).save(dataSource, type.toLatin1().constData(), imageQuality); length = imageBytes->length(); #ifdef DEBUG_UPLOAD qDebug() << "Resized length:" << length; #endif dataSource->open(QIODevice::ReadOnly); } else { length = fileInfo.size(); dataSource = new QFile(fileName, this); if (!dataSource->open(QIODevice::ReadOnly)) { dataSource->deleteLater(); QMessageBox::critical(0, tr("Error"), tr("Error opening file %1").arg(fileName)); return; } } if (length > sizeLimit) { QMessageBox::critical(0, tr("The file size is too large."), tr("File size must be less than %1 bytes").arg(sizeLimit)); if (dataSource) { dataSource->deleteLater(); } return; } currentUpload.account = account; currentUpload.from = jid; currentUpload.to = jidToSend; currentUpload.type = QLatin1String(sender()->parent()->metaObject()->className()) == "PsiChatDlg" ? "chat" : "groupchat"; QString slotRequestStanza = QString("" "" "%4" "%5" "%6" "" "").arg(jid).arg(getId(account)).arg(serviceName).arg(escape(imageName)).arg(length).arg(mimeType); #ifdef DEBUG_UPLOAD qDebug() << "Requesting slot:" << slotRequestStanza; #endif slotTimeout.start(SLOT_TIMEOUT); stanzaSender->sendStanza(account, slotRequestStanza); } QString HttpUploadPlugin::pluginInfo() { return tr("Authors: ") + "rkfg\n\n" + trUtf8("This plugin allows uploading images and other files via XEP-0363."); } QPixmap HttpUploadPlugin::icon() const { return QPixmap(":/httpuploadplugin/upload_image.png"); } void HttpUploadPlugin::checkUploadAvailability(int account) { QString curJid = accInfo->getJid(account); if (serviceNames.find(curJid) != serviceNames.end()) { return; } QRegExp jidRE("^([^@]*)@([^/]*)$"); if (jidRE.indexIn(curJid) == 0) { QString domain = jidRE.cap(2); QString id = getId(account); // send discovery request to the main domain for Prosody to work QString discoMain = QString("" "" "").arg(curJid).arg(id).arg(domain); stanzaSender->sendStanza(account, discoMain); QString disco = QString("" "" "").arg(curJid).arg(id).arg(domain); stanzaSender->sendStanza(account, disco); } } void HttpUploadPlugin::processServices(const QDomElement& query, int account) { QString curJid = accInfo->getJid(account); QDomNodeList nodes = query.childNodes(); for (int i = 0; i < nodes.count(); i++) { QDomElement elem = nodes.item(i).toElement(); if (elem.tagName() == "item") { QString serviceJid = elem.attribute("jid"); QString serviceDiscoStanza = QString("" "" "").arg(curJid).arg(getId(account)).arg(serviceJid); #ifdef DEBUG_UPLOAD qDebug() << "Discovering service" << serviceJid; #endif stanzaSender->sendStanza(account, serviceDiscoStanza); } } } void HttpUploadPlugin::processOneService(const QDomElement& query, const QString& service, int account) { QString curJid = accInfo->getJid(account); int sizeLimit = -1; QDomElement feature = query.firstChildElement("feature"); bool ok = false; while (!feature.isNull()) { if (feature.attribute("var") == "urn:xmpp:http:upload") { #ifdef DEBUG_UPLOAD qDebug() << "Service" << service << "looks like http upload"; #endif QDomElement x = query.firstChildElement("x"); while (!x.isNull()) { QDomElement field = x.firstChildElement("field"); while (!field.isNull()) { if (field.attribute("var") == "max-file-size") { QDomElement sizeNode = field.firstChildElement("value"); int foundSizeLimit = sizeNode.text().toInt(&ok); if (ok) { #ifdef DEBUG_UPLOAD qDebug() << "Discovered size limit:" << foundSizeLimit; #endif sizeLimit = foundSizeLimit; break; } } field = field.nextSiblingElement("field"); } x = x.nextSiblingElement("x"); } } feature = feature.nextSiblingElement("feature"); } if (sizeLimit > 0) { serviceNames.insert(curJid, UploadService(service, sizeLimit)); } } void HttpUploadPlugin::processUploadSlot(const QDomElement& xml) { if (xml.firstChildElement("request").attribute("xmlns") == "urn:xmpp:http:upload") { QDomElement error = xml.firstChildElement("error"); if (!error.isNull()) { QString errorText = error.firstChildElement("text").text(); if (!errorText.isNull()) { QMessageBox::critical(0, tr("Error requesting slot"), errorText); cancelTimeout(); return; } } } QDomElement slot = xml.firstChildElement("slot"); if (slot.attribute("xmlns") == "urn:xmpp:http:upload") { slotTimeout.stop(); QString put = slot.firstChildElement("put").text(); QString get = slot.firstChildElement("get").text(); #ifdef DEBUG_UPLOAD qDebug() << "PUT:" << put; qDebug() << "GET:" << get; #endif if (get.isEmpty() || put.isEmpty()) { QMessageBox::critical(0, tr("Error requesting slot"), tr("Either put or get URL is missing in the server's reply.")); cancelTimeout(); return; } currentUpload.getUrl = get; QNetworkRequest req; req.setUrl(QUrl(put)); if (!dataSource) { QMessageBox::critical(0, tr("Error uploading"), tr("No data to upload, this maybe a result of timeout or other error.")); cancelTimeout(); return; } qint64 size = dataSource->size(); req.setHeader(QNetworkRequest::ContentLengthHeader, size); manager->put(req, dataSource); } } bool HttpUploadPlugin::incomingStanza(int account, const QDomElement& xml) { if (xml.nodeName() == "iq" && xml.attribute("type") == "result") { QDomElement query = xml.firstChildElement("query"); if (!query.isNull()) { if (query.attribute("xmlns") == "http://jabber.org/protocol/disco#items") { processServices(query, account); } if (query.attribute("xmlns") == "http://jabber.org/protocol/disco#info") { processOneService(query, xml.attribute("from"), account); } } else { processUploadSlot(xml); } } return false; } void HttpUploadPlugin::uploadComplete(QNetworkReply* reply) { bool ok; int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(&ok); if (ok && (statusCode == 201 || statusCode == 200)) { QString id = getId(currentUpload.account); QString receipt( currentUpload.type == "chat" && psiOptions->getGlobalOption("options.ui.notifications.request-receipts").toBool() ? "" : ""); QString message = QString("" "" "%4" "" "%4" "%5" "").arg(currentUpload.type).arg(currentUpload.to).arg(id).arg(currentUpload.getUrl).arg( receipt); stanzaSender->sendStanza(currentUpload.account, message); if (currentUpload.type == "chat") { // manually add outgoing message to the regular chats, in MUC this isn't needed psiController->appendMsg(currentUpload.account, currentUpload.to, currentUpload.getUrl, id); } cancelTimeout(); } else { cancelTimeout(); QMessageBox::critical(0, tr("Error uploading"), tr("Upload error %1; HTTP code %2, message: %3").arg(reply->errorString()).arg( reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toString()).arg( reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString())); } } void HttpUploadPlugin::timeout() { cancelTimeout(); QMessageBox::critical(0, tr("Error requesting slot"), tr("Timeout waiting for an upload slot")); } void HttpUploadPlugin::applyOptions() { psiOptions->setPluginOption(OPTION_PREVIEW_WIDTH, previewWidth = sb_previewWidth->value()); psiOptions->setPluginOption(OPTION_RESIZE, imageResize = cb_resize->checkState() == Qt::Checked); psiOptions->setPluginOption(OPTION_SIZE, imageSize = sb_size->value()); psiOptions->setPluginOption(OPTION_QUALITY, imageQuality = sb_quality->value()); } void HttpUploadPlugin::restoreOptions() { sb_previewWidth->setValue(previewWidth); sb_size->setValue(imageSize); sb_quality->setValue(imageQuality); cb_resize->setCheckState(imageResize ? Qt::Checked : Qt::Unchecked); } void HttpUploadPlugin::resizeStateChanged(int state) { bool enabled = state == Qt::Checked; sb_size->setEnabled(enabled); sb_quality->setEnabled(enabled); } void HttpUploadPlugin::setApplicationInfoAccessingHost(ApplicationInfoAccessingHost* host) { appInfoHost = host; } void HttpUploadPlugin::updateProxy() { Proxy proxy = appInfoHost->getProxyFor(name()); #ifdef DEBUG_UPLOAD qDebug() << "Proxy:" << "T:" << proxy.type << "H:" << proxy.host << "Pt:" << proxy.port << "U:" << proxy.user << "Ps:" << proxy.pass; #endif if (proxy.type.isEmpty()) { manager->setProxy(QNetworkProxy()); return; } QNetworkProxy netProxy(proxy.type == "socks" ? QNetworkProxy::Socks5Proxy : QNetworkProxy::HttpProxy, proxy.host, proxy.port, proxy.user, proxy.pass); manager->setProxy(netProxy); } void HttpUploadPlugin::handleSslError(QNetworkReply* reply, const QList&) { reply->ignoreSslErrors(); } #include "httpuploadplugin.moc" plugins-1.5/generic/httpuploadplugin/httpuploadplugin.pro000066400000000000000000000005151336777360500242260ustar00rootroot00000000000000isEmpty(PSISDK) { include(../../psiplugin.pri) } else { include($$PSISDK/plugins/psiplugin.pri) } QT += network greaterThan(QT_MAJOR_VERSION, 4) { CONFIG += c++11 } RESOURCES = httpuploadplugin.qrc SOURCES += httpuploadplugin.cpp \ uploadservice.cpp \ previewfiledialog.cpp \ HEADERS += previewfiledialog.h plugins-1.5/generic/httpuploadplugin/httpuploadplugin.qrc000066400000000000000000000002361336777360500242130ustar00rootroot00000000000000 upload_file.png upload_image.png plugins-1.5/generic/httpuploadplugin/previewfiledialog.cpp000066400000000000000000000024231336777360500243060ustar00rootroot00000000000000#include "previewfiledialog.h" #include PreviewFileDialog::PreviewFileDialog(QWidget* parent, const QString & caption, const QString & directory, const QString & filter, int previewWidth) : QFileDialog(parent, caption, directory, filter) { QGridLayout *layout = (QGridLayout*) this->layout(); if (!layout) { // this QFileDialog is a native one (Windows/KDE/...) and doesn't need to be extended with preview return; } setObjectName("PreviewFileDialog"); QVBoxLayout* box = new QVBoxLayout(); mpPreview = new QLabel(tr("Preview"), this); mpPreview->setAlignment(Qt::AlignCenter); mpPreview->setObjectName("labelPreview"); mpPreview->setMinimumWidth(previewWidth); mpPreview->setMinimumHeight(height()); setMinimumWidth(width() + previewWidth); box->addWidget(mpPreview); box->addStretch(); // add to QFileDialog layout layout->addLayout(box, 1, 3, 3, 1); connect(this, SIGNAL(currentChanged(const QString&)), this, SLOT(onCurrentChanged(const QString&))); } void PreviewFileDialog::onCurrentChanged(const QString & path) { QPixmap pixmap = QPixmap(path); if (pixmap.isNull()) { mpPreview->setText(tr("Not an image")); } else { mpPreview->setPixmap( pixmap.scaled(mpPreview->width(), height(), Qt::KeepAspectRatio, Qt::SmoothTransformation)); } } plugins-1.5/generic/httpuploadplugin/previewfiledialog.h000066400000000000000000000011221336777360500237460ustar00rootroot00000000000000#ifndef PREVIEW_FILE_DIALOG_H #define PREVIEW_FILE_DIALOG_H #include #include // based on http://www.qtcentre.org/threads/33593-How-can-i-have-a-QFileDialog-with-a-preview-of-the-picture class PreviewFileDialog: public QFileDialog { Q_OBJECT public: explicit PreviewFileDialog(QWidget* parent = 0, const QString & caption = QString(), const QString & directory = QString(), const QString & filter = QString(), int previewWidth = 150); private slots: void onCurrentChanged(const QString & path); protected: QLabel* mpPreview; }; #endif // PREVIEW_FILE_DIALOG_H plugins-1.5/generic/httpuploadplugin/upload_file.png000066400000000000000000000224301336777360500230720ustar00rootroot00000000000000PNG  IHDRa" iCCPiccxڭgPͷ{f 7M9% 3(*9(IDQ@̈Ꜻu[ut?L5]6DDLDF%9=hE@x@T#@32oAdatw@L\žܻ 1{W{Z:n@|5VG9;ish@yoȿ5'x6AqQ O 5x̀! w1 PkA a t #Oo@SWPMsJb$ MZHBB\Th#`3"e#hHM?D8,9$4fadD [f1"4%F2h~48_BhfO3HH OLq cD3hJ}Q1q {BJ+KIdkx9Tx?r`@] %XQ0elӴ}zyF{~)4@`{U\:糀ĸ=`(;GD̀68<@@Q $H=dߣJ (ԁZ@=ǟ0&{$ ` vaN' W܁=2@ c4d=v#A{QA Hi dL r@. 8 A(GQP P @5u4Fp 4ӠVA8:AA} K2U0 F(M0&-p}0 )̀ sxK^ x ށ` ~ ~-l A !!"@$ Q f Bl qC<$ !H IA2,$)@J2 C Bd@9d YA6d9B>r< /A B0(X(JeBYP@"0t*CP9T UA5P5BMjBN< B}4]B(4݄&]>4 MAc)4=5U#}~@/h a$q0& 0'  , $, Ú6 F l[ְ;.{þp8 qp" p&B> K F n[9< _Axc8| ?x~7[xuxނ]@!<`B ?F!i,BPCh"tzC aE8 .w` B(D,"8@d#rBD1qQF!N"͈6D э@\F\E ;ibXC|G#~! v0" H dCr"yH!(F!H Ri4CZ"mHg+G2!d42LEf Cbd YA#O! ېd?ry9@EN"! W%2r FEP ōG DQt JRGiQF(3rAy|P T(*JD2P9|T!8UGB5Q K!!j5zZD-QQ_P?QPDcD4͉E Et Z@ ѦhK- D!t :@ Ї%Rt݈nF;=~e0z =~~Cϣ_ߡ?ћ?Abpa`0" Fa0`B0XL& abJ1U:)L ,<"*:fs YlavH,KRX^ V +*c5X#9uzaApl 6{aKejl4 ۉ`q]Cc3"-v!pX GqpB8q4NLq8  …bqI4\ wW5Zqp=Uu>n7{[}}ma<O³x</Wk&xK=#qd|>_/k|?o_?! T' B$TZDp' aB!K($ SVB'0H&$%L o/u"DID"F#JD] ъ@t%zab1G,"#V뉧 ~qx8I|B|A|M\!׉H K"H<$AIB"Iv}$/?)MJ"HEJRA!]" IHӤgE{'"cd2,DȪd1ْ@v#xr\B דϐ;=A0y|de}ź7Ćg I)鰙ٲŰf+cckfdgf`{6m;;..ǮƮnȞ~{5{{E!؟/c@p9X98889 8,988QE-9.qrx3&'qR9y8E8e989-898Qɜ9989[9/prq|̹s Ebs)riqprqqs%per:Uuk. K\_$nvn$)=ww$w2warm=Cܓso?qsxXxxyy4yylyxy"xyxxxxxzxxy~{O A0H(XDi'2+$&%EUD DmDE1颅墧D;EEoN΋.#q ɉi9%k/6'Vض8NM\P\F\CTQG}#ITԕt ̐<,Y%,#yM[o;Rx))))])+)7)TT^RϤK<*҆v^ҡIyǥOJ^,%aіq ɔ)i(s]fR̪̆,RY_VZVCLYO6Z6]lll+r9f9~9i9M93}rr1rrr5rmr}rcrSr/>G˳ [ɻ'?))Y%o $n UcG Q Z>)l)bEmS)V(QQQ|8AZUIXIAIOFK)L)ERQIyJ1"Jv>iEʭ7_)QV!pUTLUUTTU4t QSYVYWE ʫڪzP-RRmUW:ZYOMZMKBM-X-I@\Zu)E5mu:zzzziSkD  ) M 7`d}745^k|MMYMMM/p4Úg55okj.knhشDrNh5iukjMi-j}&kkhhh{iGhkkiӾ}W:8.NNNNN%[:::]]q]5]3]W`dCUmto.na8\R n=[җԷO/֯Կ@g~ z n5i2d33T543t5 1L1,2502g8opۈl$`$go`gggTnlo4a4klgm,eelmmee|ܸɸxx ڄDD$$äĤѤɴɒOS)ii1S=c3oM70fft3-3k3o(lf͞6Ǜ˘ۛǛW_6k>o|ׂBB"EEyQi%uK%eeee%;/,?[Z1Y Y)[ZYZYj걺aj5ޚZZ::ɺкֺzzO MMMY66l"m9lZ6qgml.~CڱlUu]{mmi/ecooohȾ־~~΁A!!CCMYUG!GeG3GHlRA{ ߜNNt'm';'DB:Nם;-;m9iJΦYΥ-΃C'Ow>ƾ}N7on};.TQu+_8N.[$WkkkY׫SKnx7~7777l26+nnoq|nYemW'߸ox<<]}{OOOOψόϲ__&_Q_ _[_dbS}w|_~ߏϳ_n~sW?d~~Z~~ ~%~g'U-} {o  0p   J  |`a 'F#Qhg\cL3VA ǠࠌҠkAA+A```WwCXC$CBdT 4S(*jZz!tz;%F2F?5&2&?6'VBXBPz]lPlzlYlGhlZ2'N1<7.)h\sܕGq+qFo%0'H$%$D&'%&IxHNKItN OMINDJIJrL KINt+i!i=,\ܝ|+y!y#"Rғr'UʯTJxnKjTjAjCj_ԥ?XH0}&{(qd_JmNPNVNUNw9sF Gr[rs~4ȗ7?_ߙ3eF@ Zӂ/jt:qɃN\=9|PC5z;v!G|EaZaE[ XL|RN+YPyaއ;|ŔbbbGG$q\qO_9=zD'.9V-*.u---.m--}^RF/3.)K)++*]o9GBuyPyNy]@T TBb_ELኖъ땔JJJݕw+U***UMUCUOUū KoW/Up(ՄԜyZX+^kXSZ[^{n:P[VXYWX\7Rn^ެ>>~cAA!xù7 'N*?~'O>?(hИX88ݸv wJ)S)Ouwj $ФT4i4i#On9}ӿϰQ8cs&L3<;,lhi>|irdYK@KVK]`㖯VzI_kfkm@L6BDq/vvv/gggM<[wv:f W:f;~c:'s\s];f'k|MgX 8TtZ:| _ |Aυ /\M6ftv7v_~޽֣csggj&>tQEO^Fkb]_d_q_{D~__߳?y@zb x`ŁK<4.^JTvK AA``?._vpr˟Я] +Wx4܆*.=z|UհW[_]_]ӻ}-Zݵm + ;>?`~>b64R0<26z z֎^ݼv]'w_x}m4&=f56V4>vk F7o8uc⍝|7ozLY{͹/O`86q~[[ҷn:|֝[%n}v1x'Ι;7 kpnݦw_h˺xoϼ;>y v&&&}'&'G&'w?0ᩇ rNOݘZzx$QGOcŧͦC Nߙ09:539Xǥ{<'O >yd)S^O3|:tq ϶N.asssG&sO>yB Ƌ/_ya0/3o;=bwK/_9rqZZ0^`,Zh_i(hXؿ8+W>^5kkז#^}}?ްQ{7o^-K"KK!K:&U~6m۫oAߙ ~WܻᄒW~>}kee++j++i+'WFWVQV{Wn~C·V?>~tw> ~2S秇fsSo|~]Z]]+_|m ї/E_:<+W_36}M÷o߆-||7{'G?O?~NX[w\OZYj!aQ1lc{Spx3df/_k׷l5~{O[L[[n[[nn!'O?obJﵿQm+ ;NN.ݵ؍-}%{93 s:@,cۖC pHYs B(xzTXtTitlex H,H-RHM-)lGtT zTXtAuthorxI,WpNIMK)J0{Ɍ_IDAT8mS=lPf7Qh*"baDB001!1P$ $ APUBF !u(jc?iҳ޻wߝ;XL$$ L&S:@)5gOV2z-ERڦRnLe&+EUO*%|1iqK*2N;oFj5or켄E)’ TlV 8zw[GHj|#0 V:] 8:=^D~Usż ]8 Cع]%:TgîFƷORJASFvY{`gUJe~U"s0_EM.`JB8m]&=wsXoGkg;)‰[3<8>Q ;r5l@̡0tcS_6:{[HMvkȏ{݈b$=euij#x5Mkd=؋}g]A]}>n ͳ7+0 "\Z`])-][l o>::JR~^Ӵ:vj1uNyIENDB`plugins-1.5/generic/httpuploadplugin/upload_image.png000066400000000000000000000222251336777360500232370ustar00rootroot00000000000000PNG  IHDRa" iCCPiccxڭgPͷ{f 7M9% 3(*9(IDQ@̈Ꜻu[ut?L5]6DDLDF%9=hE@x@T#@32oAdatw@L\žܻ 1{W{Z:n@|5VG9;ish@yoȿ5'x6AqQ O 5x̀! w1 PkA a t #Oo@SWPMsJb$ MZHBB\Th#`3"e#hHM?D8,9$4fadD [f1"4%F2h~48_BhfO3HH OLq cD3hJ}Q1q {BJ+KIdkx9Tx?r`@] %XQ0elӴ}zyF{~)4@`{U\:糀ĸ=`(;GD̀68<@@Q $H=dߣJ (ԁZ@=ǟ0&{$ ` vaN' W܁=2@ c4d=v#A{QA Hi dL r@. 8 A(GQP P @5u4Fp 4ӠVA8:AA} K2U0 F(M0&-p}0 )̀ sxK^ x ށ` ~ ~-l A !!"@$ Q f Bl qC<$ !H IA2,$)@J2 C Bd@9d YA6d9B>r< /A B0(X(JeBYP@"0t*CP9T UA5P5BMjBN< B}4]B(4݄&]>4 MAc)4=5U#}~@/h a$q0& 0'  , $, Ú6 F l[ְ;.{þp8 qp" p&B> K F n[9< _Axc8| ?x~7[xuxނ]@!<`B ?F!i,BPCh"tzC aE8 .w` B(D,"8@d#rBD1qQF!N"͈6D э@\F\E ;ibXC|G#~! v0" H dCr"yH!(F!H Ri4CZ"mHg+G2!d42LEf Cbd YA#O! ېd?ry9@EN"! W%2r FEP ōG DQt JRGiQF(3rAy|P T(*JD2P9|T!8UGB5Q K!!j5zZD-QQ_P?QPDcD4͉E Et Z@ ѦhK- D!t :@ Ї%Rt݈nF;=~e0z =~~Cϣ_ߡ?ћ?Abpa`0" Fa0`B0XL& abJ1U:)L ,<"*:fs YlavH,KRX^ V +*c5X#9uzaApl 6{aKejl4 ۉ`q]Cc3"-v!pX GqpB8q4NLq8  …bqI4\ wW5Zqp=Uu>n7{[}}ma<O³x</Wk&xK=#qd|>_/k|?o_?! T' B$TZDp' aB!K($ SVB'0H&$%L o/u"DID"F#JD] ъ@t%zab1G,"#V뉧 ~qx8I|B|A|M\!׉H K"H<$AIB"Iv}$/?)MJ"HEJRA!]" IHӤgE{'"cd2,DȪd1ْ@v#xr\B דϐ;=A0y|de}ź7Ćg I)鰙ٲŰf+cckfdgf`{6m;;..ǮƮnȞ~{5{{E!؟/c@p9X98889 8,988QE-9.qrx3&'qR9y8E8e989-898Qɜ9989[9/prq|̹s Ebs)riqprqqs%per:Uuk. K\_$nvn$)=ww$w2warm=Cܓso?qsxXxxyy4yylyxy"xyxxxxxzxxy~{O A0H(XDi'2+$&%EUD DmDE1颅墧D;EEoN΋.#q ɉi9%k/6'Vض8NM\P\F\CTQG}#ITԕt ̐<,Y%,#yM[o;Rx))))])+)7)TT^RϤK<*҆v^ҡIyǥOJ^,%aіq ɔ)i(s]fR̪̆,RY_VZVCLYO6Z6]lll+r9f9~9i9M93}rr1rrr5rmr}rcrSr/>G˳ [ɻ'?))Y%o $n UcG Q Z>)l)bEmS)V(QQQ|8AZUIXIAIOFK)L)ERQIyJ1"Jv>iEʭ7_)QV!pUTLUUTTU4t QSYVYWE ʫڪzP-RRmUW:ZYOMZMKBM-X-I@\Zu)E5mu:zzzziSkD  ) M 7`d}745^k|MMYMMM/p4Úg55okj.knhشDrNh5iukjMi-j}&kkhhh{iGhkkiӾ}W:8.NNNNN%[:::]]q]5]3]W`dCUmto.na8\R n=[җԷO/֯Կ@g~ z n5i2d33T543t5 1L1,2502g8opۈl$`$go`gggTnlo4a4klgm,eelmmee|ܸɸxx ڄDD$$äĤѤɴɒOS)ii1S=c3oM70fft3-3k3o(lf͞6Ǜ˘ۛǛW_6k>o|ׂBB"EEyQi%uK%eeee%;/,?[Z1Y Y)[ZYZYj걺aj5ޚZZ::ɺкֺzzO MMMY66l"m9lZ6qgml.~CڱlUu]{mmi/ecooohȾ־~~΁A!!CCMYUG!GeG3GHlRA{ ߜNNt'm';'DB:Nם;-;m9iJΦYΥ-΃C'Ow>ƾ}N7on};.TQu+_8N.[$WkkkY׫SKnx7~7777l26+nnoq|nYemW'߸ox<<]}{OOOOψόϲ__&_Q_ _[_dbS}w|_~ߏϳ_n~sW?d~~Z~~ ~%~g'U-} {o  0p   J  |`a 'F#Qhg\cL3VA ǠࠌҠkAA+A```WwCXC$CBdT 4S(*jZz!tz;%F2F?5&2&?6'VBXBPz]lPlzlYlGhlZ2'N1<7.)h\sܕGq+qFo%0'H$%$D&'%&IxHNKItN OMINDJIJrL KINt+i!i=,\ܝ|+y!y#"Rғr'UʯTJxnKjTjAjCj_ԥ?XH0}&{(qd_JmNPNVNUNw9sF Gr[rs~4ȗ7?_ߙ3eF@ Zӂ/jt:qɃN\=9|PC5z;v!G|EaZaE[ XL|RN+YPyaއ;|ŔbbbGG$q\qO_9=zD'.9V-*.u---.m--}^RF/3.)K)++*]o9GBuyPyNy]@T TBb_ELኖъ땔JJJݕw+U***UMUCUOUū KoW/Up(ՄԜyZX+^kXSZ[^{n:P[VXYWX\7Rn^ެ>>~cAA!xù7 'N*?~'O>?(hИX88ݸv wJ)S)Ouwj $ФT4i4i#On9}ӿϰQ8cs&L3<;,lhi>|irdYK@KVK]`㖯VzI_kfkm@L6BDq/vvv/gggM<[wv:f W:f;~c:'s\s];f'k|MgX 8TtZ:| _ |Aυ /\M6ftv7v_~޽֣csggj&>tQEO^Fkb]_d_q_{D~__߳?y@zb x`ŁK<4.^JTvK AA``?._vpr˟Я] +Wx4܆*.=z|UհW[_]_]ӻ}-Zݵm + ;>?`~>b64R0<26z z֎^ݼv]'w_x}m4&=f56V4>vk F7o8uc⍝|7ozLY{͹/O`86q~[[ҷn:|֝[%n}v1x'Ι;7 kpnݦw_h˺xoϼ;>y v&&&}'&'G&'w?0ᩇ rNOݘZzx$QGOcŧͦC Nߙ09:539Xǥ{<'O >yd)S^O3|:tq ϶N.asssG&sO>yB Ƌ/_ya0/3o;=bwK/_9rqZZ0^`,Zh_i(hXؿ8+W>^5kkז#^}}?ްQ{7o^-K"KK!K:&U~6m۫oAߙ ~WܻᄒW~>}kee++j++i+'WFWVQV{Wn~C·V?>~tw> ~2S秇fsSo|~]Z]]+_|m ї/E_:<+W_36}M÷o߆-||7{'G?O?~NX[w\OZYj!aQ1lc{Spx3df/_k׷l5~{O[L[[n[[nn!'O?obJﵿQm+ ;NN.ݵ؍-}%{93 s:@,cۖC pHYs^/IDAT8˥KTQ?wޛ_40L1ed^PH w,v&Z_Dr!@A.CNX3yR s;D fYMƆMĦhtބthR6A8-rghuζ焃ě(B2Vj/ u |%T}nn֞:XEʨF!!Re.Չ_w{Ovbo} Wazg/ofBx]nZ}c_6lo7.~\<Ýň%z;gs`Q.#8{h'b`O\"6m>#'EW+Go9Dh[9ZR\T*^jgiit MQ~؀u->/%su7XIYyzɵp|~k=kIENDB`plugins-1.5/generic/httpuploadplugin/uploadservice.cpp000066400000000000000000000003561336777360500234550ustar00rootroot00000000000000/* * uploadservice.cpp * * Created on: 24 Sep 2016 * Author: rkfg */ #include "uploadservice.h" UploadService::UploadService(const QString& serviceName, int sizeLimit) : serviceName_(serviceName), sizeLimit_(sizeLimit) { } plugins-1.5/generic/httpuploadplugin/uploadservice.h000066400000000000000000000010451336777360500231160ustar00rootroot00000000000000/* * uploadservice.h * * Created on: 24 Sep 2016 * Author: rkfg */ #ifndef SRC_PLUGINS_GENERIC_HTTPUPLOADPLUGIN_UPLOADSERVICE_H_ #define SRC_PLUGINS_GENERIC_HTTPUPLOADPLUGIN_UPLOADSERVICE_H_ #include class UploadService { public: UploadService(const QString& serviceName, int sizeLimit); const QString& serviceName() const { return serviceName_; } int sizeLimit() const { return sizeLimit_; } private: QString serviceName_; int sizeLimit_; }; #endif /* SRC_PLUGINS_GENERIC_HTTPUPLOADPLUGIN_UPLOADSERVICE_H_ */ plugins-1.5/generic/icqdieplugin/000077500000000000000000000000001336777360500171525ustar00rootroot00000000000000plugins-1.5/generic/icqdieplugin/CMakeLists.txt000066400000000000000000000025011336777360500217100ustar00rootroot00000000000000unset(_HDRS) unset(_UIS) unset(_SRCS) unset(_RSCS) unset(PLUGIN) set( PLUGIN icqdieplugin ) project(${PLUGIN}) cmake_minimum_required(VERSION 3.1.0) set( CMAKE_AUTOMOC TRUE ) IF( NOT WIN32 ) set( LIB_SUFFIX "" CACHE STRING "Define suffix of directory name (32/64)" ) set( PLUGINS_PATH "lib${LIB_SUFFIX}/psi-plus/plugins" CACHE STRING "Install suffix for plugins" ) ELSE() set( PLUGINS_PATH "psi-plus/plugins" CACHE STRING "Install suffix for plugins" ) ENDIF() add_definitions( -DQT_PLUGIN -DHAVE_QT5 ) include_directories( ${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ../../include . ) set( _SRCS ${PLUGIN}.cpp ) set( _UIS icqdieoptions.ui ) set( _RSCS resources.qrc ) find_package( Qt5 COMPONENTS Widgets Xml REQUIRED ) set(QT_DEPLIBS Qt5::Widgets Qt5::Xml ) qt5_wrap_ui(UIS ${_UIS}) qt5_add_resources(RSCS ${_RSCS}) add_library( ${PLUGIN} MODULE ${_SRCS} ${UIS} ${RSCS} ) target_link_libraries( ${PLUGIN} ${QT_DEPLIBS} ) if( UNIX AND NOT( APPLE OR CYGWIN ) ) install( TARGETS ${PLUGIN} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} ) endif() if( WIN32 ) install( TARGETS ${PLUGIN} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} ) endif() plugins-1.5/generic/icqdieplugin/changelog.txt000066400000000000000000000025441336777360500216470ustar00rootroot000000000000002013-08-13 v0.1.6 - taurus + Иконка плагина 2010-10-10 v0.1.5 * Добавлено максимальное количество сообщений контакту 2010-09-11 v0.1.4 * обновлена ссылка на wiki ( http://psi-plus.com/wiki/plugins#icq_must_die_plugin ) 2010-05-26 v0.1.3 * Исправлена ошибка разбора поля from - падал при получения сообщения от транспорта 2010-05-24 v0.1.2 * Исправлено значение по умолчанию для списка 2010-05-23 v0.1.1 * поправлены опечатки в текстах автоответчика 2010-05-22 v0.1.0 + добавлено два сообщения - если принимаем и если посылаем + добавлен выбор транспортов * теперь для каждого контакта можно задать своё действие 2010-05-17 v0.0.5 + добавлена информация о плагине [i] 2010-05-04 v0.0.4 * исправлена ссылка на wiki 2010-01-04 v0.0.3 + в настройки плагина добавлена ссылка на wiki 2009-12-26 v0.0.2 + добавлена опция игнорирования сообщений из ICQ 2009-12-25 v0.0.1 ! initial версия plugins-1.5/generic/icqdieplugin/icqdie.png000066400000000000000000000017721336777360500211250ustar00rootroot00000000000000PNG  IHDRasRGBbKGD pHYs  tIME &؋݃zIDAT85Ouǟ}.8INO.K[~ sk.SVinrXX?$5\+MjeF&`"qwpy?/$@D k <Fw Aoh/&DP$qb?vղ $<1^ry+ã(%ϨVQTNe@T?+2*,k7XP >5/zzP/S~9pSOYp_e(Pַ֖[BG]FpRqTԬk6[RR8\ɽ ?Cxlu9/OKhz>ǬdgةYDl8U헧ŏr4gRpU;Xl˳ +ęR`b(M'1RoWEqfb( m1VwTXTꀍ3瓲X9_(v7B,\e۱ziga{ 8suOܥ_;)&rX;pri65Eaa63j]Ov\41[w73;.iLZMMJm&h{*d>[s]G4IimӦ (eQGrSO&¥ )A-?toIENDB`plugins-1.5/generic/icqdieplugin/icqdieoptions.ui000066400000000000000000000142761336777360500223750ustar00rootroot00000000000000 options 0 0 575 489 Form Auto Reply Message If Recv: Qt::PlainText 0 0 Auto Reply Message If No Recv: Qt::PlainText 0 0 Custom options: -uin - do nothing +uin - send replay !uin - block message [-+!]other - default [-+!]nil - not in list # - comment to end line 0 0 Pause for next Recv message: Qt::PlainText Qt::Horizontal 40 20 1 2000 min. Max messages to contact: Qt::Horizontal 40 20 182 16777215 Disable if chat window is active Qt::Vertical 20 40 Transports: true 0 1 <a href="http://code.google.com/p/psi-dev/wiki/plugins#ICQ_Must_Die_Plugin">Wiki (Online)</a> plugins-1.5/generic/icqdieplugin/icqdieplugin.cpp000066400000000000000000000316521336777360500223420ustar00rootroot00000000000000/* * icqdieplugin.cpp - plugin * Copyright (C) 2009 Ivan Borzenkov * * THE BEER-WARE LICENSE (Revision 42): * I wrote this file. As long as you retain this notice you * can do whatever you want with this stuff. If we meet some day, * and you think this stuff is worth it, you can buy a beer in return. * * Alternatively, this file may be used under the terms of the GNU * General Public License version 2 or (at your option) any later version * or GNU Lesser General Public License version 2 or (at your option) any * later version as published by the Free Software Foundation and * appearing in the file copying.txt included in the packaging of this file. * Please review the following information to ensure the GNU General * Public License version 2.0 requirements will be met: * . */ #include #include #include #include #include "psiplugin.h" #include "optionaccessor.h" #include "optionaccessinghost.h" #include "stanzafilter.h" #include "stanzasender.h" #include "stanzasendinghost.h" #include "activetabaccessor.h" #include "activetabaccessinghost.h" #include "accountinfoaccessor.h" #include "accountinfoaccessinghost.h" #include "plugininfoprovider.h" #include "ui_icqdieoptions.h" #define cVer "0.1.6" #define constMessageRecv "msgr" #define constMessageNoRecv "msgnr" #define constCustom "custom" #define constActiveTab "actvtb" #define constPauseTime "whttm" #define constMessageCount "msgcnt" #define constTransports "transp" class IcqDie: public QObject, public PsiPlugin, public OptionAccessor, public StanzaSender, public StanzaFilter, public ActiveTabAccessor, public AccountInfoAccessor, public PluginInfoProvider { Q_OBJECT #ifdef HAVE_QT5 Q_PLUGIN_METADATA(IID "com.psi-plus.IcqDie") #endif Q_INTERFACES(PsiPlugin OptionAccessor StanzaSender StanzaFilter ActiveTabAccessor AccountInfoAccessor PluginInfoProvider) public: IcqDie(); virtual QString name() const; virtual QString shortName() const; virtual QString version() const; virtual QWidget* options(); virtual bool enable(); virtual bool disable(); virtual void applyOptions(); virtual void restoreOptions(); virtual void setOptionAccessingHost(OptionAccessingHost* host); virtual void optionChanged(const QString& option); virtual void setStanzaSendingHost(StanzaSendingHost *host); virtual bool incomingStanza(int account, const QDomElement& stanza); virtual bool outgoingStanza(int account, QDomElement& stanza); virtual void setActiveTabAccessingHost(ActiveTabAccessingHost* host); virtual void setAccountInfoAccessingHost(AccountInfoAccessingHost* host); virtual QString pluginInfo(); virtual QPixmap icon() const; private: bool enabled; AccountInfoAccessingHost* AccInfoHost; ActiveTabAccessingHost* ActiveTabHost; OptionAccessingHost* psiOptions; StanzaSendingHost* StanzaHost; QString MessageRecv; QString MessageNoRecv; typedef QPair CounterInfo; QMap Counter; enum stat { ignore = '-', send = '+', block = '!', }; typedef QMap CustomList; CustomList Custom; QVector Transports; CustomList ParseCustomText(QString sCustom); int PauseTime; int MessageCount; bool ActiveTabIsEnable; Ui::options ui; }; #ifndef HAVE_QT5 Q_EXPORT_PLUGIN(IcqDie); #endif IcqDie::IcqDie() { ActiveTabIsEnable = true; Custom.clear(); Custom["other"] = send; Custom["nil"] = ignore; Counter.clear(); Transports.clear(); Transports << "icq" << "jit"; PauseTime = 120; MessageCount = 0; enabled = false; MessageRecv = trUtf8("I can tell you as a Linux, but do not be mad at me. " "Certainly this human will receive this message. But it's much better to chat to him by Jabber. " "You are risking, one never knows when ICQ can die, granny already outlived its. His JID: %1.\n\n" "Sincerely yours, Debian Sid."); MessageNoRecv = trUtf8("I can tell you as a Linux, but do not be mad at me. " "This human do not use ICQ anymore, so if you are still use that network he will not receive your message and you have to chat to him by Jabber. His JID: %1.\n\n" "If you don't know what Jabber is - use Google. It knows everything and ready to help everyone who ask it.\n" "Sincerely yours, Debian Sid."); ActiveTabHost = 0; AccInfoHost = 0; psiOptions = 0; StanzaHost = 0; } QString IcqDie::name() const { return "Icq Must Die Plugin"; } QString IcqDie::shortName() const { return "icqdie"; } QString IcqDie::version() const { return cVer; } IcqDie::CustomList IcqDie::ParseCustomText(QString sCustom) { IcqDie::CustomList Custom; Custom.clear(); QStringList Clist; Clist = sCustom.split(QRegExp("\n"), QString::SkipEmptyParts); while(!Clist.isEmpty()) { //удаляем пробелы и комментарии QString C = Clist.takeFirst().remove(QRegExp("\\s+")).remove(QRegExp("\\#.*$")); stat s; QString id = C; id.remove(0,1); if (C[0] == '-') s = ignore; else if (C[0] == '!') s = block; else if (C[0] == '+') s = send; else { s = send; //прилепляем назад id = C[0] + id; } Custom[id] = s; } //если удалили дефолтовые, то восстанавливаем if (Custom.find("nil") == Custom.end()) Custom["nil"] = ignore; if (Custom.find("other") == Custom.end()) Custom["other"] = send; //qDebug() << "ParseCustomText" << Custom; return Custom; } bool IcqDie::enable() { if (!psiOptions) return enabled; enabled = true; MessageRecv = psiOptions->getPluginOption(constMessageRecv, QVariant(MessageRecv)).toString(); MessageNoRecv = psiOptions->getPluginOption(constMessageNoRecv, QVariant(MessageNoRecv)).toString(); PauseTime = psiOptions->getPluginOption(constPauseTime, QVariant(PauseTime)).toInt(); MessageCount = psiOptions->getPluginOption(constMessageCount, QVariant(MessageCount)).toInt(); ActiveTabIsEnable = psiOptions->getPluginOption(constActiveTab, QVariant(ActiveTabIsEnable)).toBool(); QVariant vCustom; vCustom = psiOptions->getPluginOption(constCustom); if (!vCustom.isNull()) Custom = ParseCustomText(vCustom.toString()); QVariant vTransports; vTransports = psiOptions->getPluginOption(constTransports); if (!vTransports.isNull()) { QString sTransports = vTransports.toString(); Transports.clear(); QStringList Tlist; Tlist = sTransports.split(QRegExp("\n"), QString::SkipEmptyParts); while(!Tlist.isEmpty()) Transports << Tlist.takeFirst().remove(QRegExp("\\s+")); } return enabled; } bool IcqDie::disable() { enabled = false; return true; } void IcqDie::applyOptions() { psiOptions->setPluginOption(constMessageRecv, QVariant(MessageRecv = ui.messageRecv->toPlainText())); psiOptions->setPluginOption(constMessageNoRecv, QVariant(MessageNoRecv = ui.messageNoRecv->toPlainText())); QString sCustom; psiOptions->setPluginOption(constCustom, QVariant(sCustom = ui.custom->toPlainText())); Custom = ParseCustomText(sCustom); psiOptions->setPluginOption(constActiveTab, QVariant(ActiveTabIsEnable = ui.activetabWidget->isChecked())); psiOptions->setPluginOption(constMessageCount, QVariant(MessageCount = ui.messageCount->value())); psiOptions->setPluginOption(constPauseTime, QVariant(PauseTime = ui.pauseWidget->value())); //сохранили и разобрали парсеры QString sTransports; psiOptions->setPluginOption(constTransports, QVariant(sTransports = ui.transportsWidget->toPlainText())); Transports.clear(); QStringList Tlist; Tlist = sTransports.split(QRegExp("\n"), QString::SkipEmptyParts); while(!Tlist.isEmpty()) Transports << Tlist.takeFirst().remove(QRegExp("\\s+")); } void IcqDie::restoreOptions() { ui.messageRecv->setText(MessageRecv); ui.messageNoRecv->setText(MessageNoRecv); ui.messageCount->setValue(MessageCount); ui.pauseWidget->setValue(PauseTime); ui.activetabWidget->setChecked(ActiveTabIsEnable); ui.custom->setText(psiOptions->getPluginOption(constCustom, QVariant("+other\n-nil")).toString()); QString text; foreach(QString t,Transports) { if (!text.isEmpty()) text += "\n"; text += t; } ui.transportsWidget->setText(text); } QWidget* IcqDie::options() { if (!enabled) return 0; QWidget *options = new QWidget; ui.setupUi(options); ui.wiki->setText(tr("Wiki (Online)")); ui.wiki->setOpenExternalLinks(true); restoreOptions(); return options; } void IcqDie::setOptionAccessingHost(OptionAccessingHost* host) { psiOptions = host; } void IcqDie::optionChanged(const QString& option) { Q_UNUSED(option); } void IcqDie::setStanzaSendingHost(StanzaSendingHost *host) { StanzaHost = host; } bool IcqDie::incomingStanza(int account, const QDomElement& stanza) { if (!enabled) return false; if (stanza.tagName() != "message") return false; //реагируем только на чат и на сообщение QString type = stanza.attribute("type"); if(type != "chat" && type != "") return false; QDomElement Body = stanza.firstChildElement("body"); //если пустое сообщение, то ничего не делаем if(Body.isNull()) return false; QDomElement rec = stanza.firstChildElement("received"); if(!rec.isNull()) return false; QString from = stanza.attribute("from"); QStringList f = from.split("/"); QString valF = f.takeFirst(); QStringList fid = valF.split("@"); if (fid.count() < 2) return false; QString idF = fid.takeFirst(); QString server = fid.takeFirst(); QString to = stanza.attribute("to"); QStringList t = to.split("/"); QString valT = t.takeFirst(); //игнорируем сообщения от всех, кромя транспортов bool fromTransport = false; foreach(QString Transport, Transports) if (server.indexOf(Transport, Qt::CaseInsensitive) == 0) fromTransport = true; if(!fromTransport) return false; //разбираемся от кого оно stat todo = Custom["nil"]; if (Custom.find(idF) != Custom.end()) //нашли в списке - делаем что указано todo = Custom[idF]; else //проверяем, есть ли он в ростере { QStringList Roster = AccInfoHost->getRoster(account); while(!Roster.isEmpty()) { QString jid = Roster.takeFirst(); if(valF.toLower() == jid.toLower()) todo = Custom["other"]; } } //если игнорировать - пропускаем и ничего if (todo == ignore) return false; //если блокировать - отправляем сообщение и давим его if (todo == block) { if(!Counter.contains(from)) Counter[from].second = 0; Counter[from].second++; //не посылать больше N раз if (MessageCount > 0 && Counter[from].second > MessageCount) return true; QString mes = ""; StanzaHost->sendStanza(account, mes); return true; } //если уже посылали, то таймаут if(!Counter.contains(from)) Counter[from].first = QDateTime::currentDateTime(); else { QDateTime old = Counter[from].first; Counter[from].first = QDateTime::currentDateTime(); if(QDateTime::currentDateTime().secsTo(old) >= -PauseTime*60) return false; } //если пришло сообщение в активный чат, то не посылать if(ActiveTabIsEnable) { QString getJid = ActiveTabHost->getJid(); if(getJid.toLower() == from.toLower()) return false; } if(!Counter.contains(from)) Counter[from].second = 0; Counter[from].second++; //не посылать больше N раз if (MessageCount > 0 && Counter[from].second > MessageCount) return false; //отправляем сообщение QString mes = ""; StanzaHost->sendStanza(account, mes); return false; } bool IcqDie::outgoingStanza(int /*account*/, QDomElement& /*stanza*/) { return false; } void IcqDie::setActiveTabAccessingHost(ActiveTabAccessingHost* host) { ActiveTabHost = host; } void IcqDie::setAccountInfoAccessingHost(AccountInfoAccessingHost* host) { AccInfoHost = host; } QString IcqDie::pluginInfo() { return tr("Author: ") + "ivan1986\n\n" + trUtf8("This plugin is designed to help you transfer as many contacts as possible from ICQ to Jabber.\n" "The plugin has a number of simple settings that can help you:\n" "* set a special message text\n" "* exclude specific ICQ numbers\n" "* set the time interval after which the message will be repeated\n" "* set the max count of messages by contact\n" "* disable the message for the active window/tab\n" "* disable messages for contacts that are not in your roster"); } QPixmap IcqDie::icon() const { return QPixmap(":/icons/icqdie.png"); } #include "icqdieplugin.moc" plugins-1.5/generic/icqdieplugin/icqdieplugin.pro000066400000000000000000000002731336777360500223530ustar00rootroot00000000000000isEmpty(PSISDK) { include(../../psiplugin.pri) } else { include($$PSISDK/plugins/psiplugin.pri) } SOURCES += icqdieplugin.cpp FORMS += icqdieoptions.ui RESOURCES += resources.qrc plugins-1.5/generic/icqdieplugin/resources.qrc000066400000000000000000000001361336777360500216730ustar00rootroot00000000000000 icqdie.png plugins-1.5/generic/imageplugin/000077500000000000000000000000001336777360500167765ustar00rootroot00000000000000plugins-1.5/generic/imageplugin/CMakeLists.txt000066400000000000000000000024111336777360500215340ustar00rootroot00000000000000unset(_HDRS) unset(_UIS) unset(_SRCS) unset(_RSCS) unset(PLUGIN) set( PLUGIN imageplugin ) project(${PLUGIN}) cmake_minimum_required(VERSION 3.1.0) set( CMAKE_AUTOMOC TRUE ) IF( NOT WIN32 ) set( LIB_SUFFIX "" CACHE STRING "Define suffix of directory name (32/64)" ) set( PLUGINS_PATH "lib${LIB_SUFFIX}/psi-plus/plugins" CACHE STRING "Install suffix for plugins" ) ELSE() set( PLUGINS_PATH "psi-plus/plugins" CACHE STRING "Install suffix for plugins" ) ENDIF() add_definitions( -DQT_PLUGIN -DHAVE_QT5 ) include_directories( ${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ../../include . ) set( _SRCS ${PLUGIN}.cpp ) set( _RSCS ${PLUGIN}.qrc ) find_package( Qt5 COMPONENTS Widgets Xml REQUIRED ) set(QT_DEPLIBS Qt5::Widgets Qt5::Xml ) qt5_add_resources(RSCS ${_RSCS}) add_library( ${PLUGIN} MODULE ${_SRCS} ${UIS} ${RSCS} ) target_link_libraries( ${PLUGIN} ${QT_DEPLIBS} ) if( UNIX AND NOT( APPLE OR CYGWIN ) ) install( TARGETS ${PLUGIN} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} ) endif() if( WIN32 ) install( TARGETS ${PLUGIN} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} ) endif() plugins-1.5/generic/imageplugin/changelog.txt000066400000000000000000000036071336777360500214740ustar00rootroot000000000000002013-08-13 v0.1.3 - taurus + Иконка плагина 2012-03-29 v0.1.2 + запоминается последний открытый каталог + перед отправкой производится ресайз картинки, максимальный размер - 400х400 * исправлен текст, который получит пользователь с отключенным html-рендерингом + добавлен показ отправленной картинки в собственном чатлоге + добавлена возможность вставки изображения из буфера обмена * некоторые исправления кода 2011-06-20 v0.1.1 * кнопка в групчатах 2010-12-17 v0.1.0 * некоторые исправления 2010-09-11 v0.0.9 * обновлена ссылка на wiki ( http://psi-plus.com/wiki/plugins#image_plugin ) 2010-08-25 v0.0.8 * совместимость с последней версией Psi+ 2010-05-17 v0.0.7 + добавлена информация о плагине 2010-05-04 v0.0.6 * исправлена ссылка на wiki 2010-01-12 v0.0.5 * исправлена совместимость с новыми ревизиями Psi+ 2009-12-15 v0.0.4 * поддержка расширения *.ico * введено ограничение на размер изображения < 60кб * добавлена ссылка на wiki 2009-12-23 v0.0.3 * обновлён диалог открытия файла * поддержа расширения *.jpeg 2009-12-22 v0.0.2 * обновлена иконка * иконка теперь в ресурсах плагина 2009-12-22 v0.0.1 Базовый функционал: * отправка изображений собеседнику в сообщении plugins-1.5/generic/imageplugin/imageplugin.cpp000066400000000000000000000213731336777360500220110ustar00rootroot00000000000000/* * imageplugin.cpp - plugin * Copyright (C) 2009-2010 VampiRus * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "psiplugin.h" #include "activetabaccessinghost.h" #include "activetabaccessor.h" #include "toolbariconaccessor.h" #include "iconfactoryaccessor.h" #include "iconfactoryaccessinghost.h" #include "gctoolbariconaccessor.h" #include "stanzasender.h" #include "stanzasendinghost.h" #include "accountinfoaccessinghost.h" #include "accountinfoaccessor.h" #include "plugininfoprovider.h" #include "psiaccountcontroller.h" #include "psiaccountcontrollinghost.h" #include "optionaccessinghost.h" #include "optionaccessor.h" #include #include #include #include #include #include #include #include #include #define constVersion "0.1.2" #define CONST_LAST_FOLDER "lastfolder" const int MAX_SIZE = 400; class ImagePlugin : public QObject, public PsiPlugin, public ToolbarIconAccessor , public GCToolbarIconAccessor, public StanzaSender, public IconFactoryAccessor , public ActiveTabAccessor, public PluginInfoProvider, public AccountInfoAccessor , public PsiAccountController, public OptionAccessor { Q_OBJECT #ifdef HAVE_QT5 Q_PLUGIN_METADATA(IID "com.psi-plus.ImagePlugin") #endif Q_INTERFACES(PsiPlugin ToolbarIconAccessor GCToolbarIconAccessor StanzaSender ActiveTabAccessor PsiAccountController OptionAccessor IconFactoryAccessor AccountInfoAccessor PluginInfoProvider) public: ImagePlugin(); virtual QString name() const; virtual QString shortName() const; virtual QString version() const; virtual QWidget* options(); virtual bool enable(); virtual bool disable(); virtual void applyOptions() {} virtual void restoreOptions() {} virtual QList < QVariantHash > getButtonParam(); virtual QAction* getAction(QObject* , int , const QString& ) { return 0; } virtual QList < QVariantHash > getGCButtonParam(); virtual QAction* getGCAction(QObject* , int , const QString& ) { return 0; } virtual void setIconFactoryAccessingHost(IconFactoryAccessingHost* host); virtual void setStanzaSendingHost(StanzaSendingHost *host); virtual void setActiveTabAccessingHost(ActiveTabAccessingHost* host); virtual void setAccountInfoAccessingHost(AccountInfoAccessingHost* host); virtual void setPsiAccountControllingHost(PsiAccountControllingHost *host); virtual void setOptionAccessingHost(OptionAccessingHost *host); virtual void optionChanged(const QString &) {} virtual QString pluginInfo(); virtual QPixmap icon() const; private slots: void actionActivated(); private: IconFactoryAccessingHost* iconHost; StanzaSendingHost* stanzaSender; ActiveTabAccessingHost* activeTab; AccountInfoAccessingHost* accInfo; PsiAccountControllingHost *psiController; OptionAccessingHost *psiOptions; bool enabled; QHash accounts_; }; #ifndef HAVE_QT5 Q_EXPORT_PLUGIN(ImagePlugin) #endif ImagePlugin::ImagePlugin() : iconHost(0) , stanzaSender(0) , activeTab(0) , accInfo(0) , psiController(0) , psiOptions(0) , enabled(false) { } QString ImagePlugin::name() const { return "Image Plugin"; } QString ImagePlugin::shortName() const { return "image"; } QString ImagePlugin::version() const { return constVersion; } bool ImagePlugin::enable() { QFile file(":/imageplugin/imageplugin.gif"); if ( file.open(QIODevice::ReadOnly) ) { QByteArray image = file.readAll(); iconHost->addIcon("imageplugin/icon",image); file.close(); enabled = true; } else { enabled = false; } return enabled; } bool ImagePlugin::disable() { enabled = false; return true; } QWidget* ImagePlugin::options() { if (!enabled) { return 0; } QWidget *optionsWid = new QWidget(); QVBoxLayout *vbox= new QVBoxLayout(optionsWid); QLabel *wikiLink = new QLabel(tr("Wiki (Online)"),optionsWid); wikiLink->setOpenExternalLinks(true); vbox->addWidget(wikiLink); vbox->addStretch(); return optionsWid; } QList< QVariantHash > ImagePlugin::getButtonParam() { QVariantHash hash; hash["tooltip"] = QVariant(tr("Send Image")); hash["icon"] = QVariant(QString("imageplugin/icon")); hash["reciver"] = qVariantFromValue(qobject_cast(this)); hash["slot"] = QVariant(SLOT(actionActivated())); QList< QVariantHash > l; l.push_back(hash); return l; } QList< QVariantHash > ImagePlugin::getGCButtonParam() { return getButtonParam(); } void ImagePlugin::setAccountInfoAccessingHost(AccountInfoAccessingHost* host) { accInfo = host; } void ImagePlugin::setIconFactoryAccessingHost(IconFactoryAccessingHost* host) { iconHost = host; } void ImagePlugin::setPsiAccountControllingHost(PsiAccountControllingHost *host) { psiController = host; } void ImagePlugin::setOptionAccessingHost(OptionAccessingHost *host) { psiOptions = host; } void ImagePlugin::setStanzaSendingHost(StanzaSendingHost *host) { stanzaSender = host; } void ImagePlugin::setActiveTabAccessingHost(ActiveTabAccessingHost* host) { activeTab = host; } void ImagePlugin::actionActivated() { if (!enabled) return; QString fileName(""); QString jid = activeTab->getYourJid(); QString jidToSend = activeTab->getJid(); int account = 0; QString tmpJid(""); while (jid != (tmpJid = accInfo->getJid(account))) { ++account; if (tmpJid == "-1") return; } QMenu m; QList list; list << new QAction(tr("Open file"), &m) << new QAction(tr("From clipboard"), &m); QAction *act = m.exec(list, QCursor::pos()); if(!act) return; if ("offline" == accInfo->getStatus(account)) { return; } QPixmap pix; QString imageName; if(list.indexOf(act) == 1) { if(!QApplication::clipboard()->mimeData()->hasImage()) return; pix = QPixmap::fromImage(QApplication::clipboard()->image()); imageName = QApplication::clipboard()->text(); } else { const QString lastPath = psiOptions->getPluginOption(CONST_LAST_FOLDER, QDir::homePath()).toString(); fileName = QFileDialog::getOpenFileName(0, tr("Open Image"), lastPath, tr("Images (*.png *.gif *.jpg *.jpeg *.ico)")); if (fileName.isEmpty()) return; QFile file(fileName); if ( file.open(QIODevice::ReadOnly) ) { pix = QPixmap::fromImage(QImage::fromData(file.readAll())); imageName = QFileInfo(file).fileName(); } else { return; } psiOptions->setPluginOption(CONST_LAST_FOLDER, QFileInfo(file).path()); } QByteArray image; QString mimeType("jpeg"); if(pix.height() > MAX_SIZE || pix.width() > MAX_SIZE) { pix = pix.scaled(MAX_SIZE, MAX_SIZE, Qt::KeepAspectRatio, Qt::SmoothTransformation); } QBuffer b(&image); pix.save(&b, mimeType.toLatin1().constData()); QString imageBase64(image.toBase64()); int length = image.length(); if(length > 61440) { QMessageBox::information(0, tr("The image size is too large."), tr("Image size must be less than 60 kb")); } QString mType = QLatin1String(sender()->parent()->metaObject()->className()) == "PsiChatDlg"? "chat" : "groupchat"; QString body = tr("Image %1 bytes received.").arg(QString::number(length)); QString msgHtml = QString("" "%4" "" "" "
\"img\"/ " "
") .arg(mType) .arg(jidToSend) .arg(stanzaSender->uniqueId(account)) .arg(body) .arg(mimeType) .arg(imageBase64); stanzaSender->sendStanza(account, msgHtml); psiController->appendSysMsg(account, jidToSend, tr("Image %1 sent
\"img\"/ ") .arg(imageName) .arg(mimeType) .arg(imageBase64)); } QString ImagePlugin::pluginInfo() { return tr("Authors: ") + "VampiRUS, Dealer_WeARE\n\n" + trUtf8("This plugin is designed to send images to roster contacts.\n" "Your contact's client must be support XEP-0071: XHTML-IM and support the data:URI scheme.\n" "Note: To work correctly, the option options.ui.chat.central-toolbar must be set to true."); } QPixmap ImagePlugin::icon() const { return QPixmap(":/imageplugin/imageplugin.gif"); } #include "imageplugin.moc" plugins-1.5/generic/imageplugin/imageplugin.gif000066400000000000000000000004121336777360500217630ustar00rootroot00000000000000GIF89ad=ܾ^چUӮyMӞSڠ̒ӥ:|fzju]diCsѮm!,'dih] ps@Wgr(J0Wdb&,b~R` 1X&hz{V#  |W"7;=&4+!;plugins-1.5/generic/imageplugin/imageplugin.pro000066400000000000000000000002601336777360500220170ustar00rootroot00000000000000isEmpty(PSISDK) { include(../../psiplugin.pri) } else { include($$PSISDK/plugins/psiplugin.pri) } RESOURCES = imageplugin.qrc SOURCES += imageplugin.cpp \ plugins-1.5/generic/imageplugin/imageplugin.qrc000066400000000000000000000001721336777360500220060ustar00rootroot00000000000000 imageplugin.gif plugins-1.5/generic/imagepreviewplugin/000077500000000000000000000000001336777360500204005ustar00rootroot00000000000000plugins-1.5/generic/imagepreviewplugin/CMakeLists.txt000066400000000000000000000041011336777360500231340ustar00rootroot00000000000000unset(_HDRS) unset(_UIS) unset(_SRCS) unset(_RSCS) unset(PLUGIN) set( PLUGIN imagepreviewplugin ) project(${PLUGIN}) cmake_minimum_required(VERSION 3.1.0) set( CMAKE_AUTOMOC TRUE ) IF( NOT WIN32 ) set( LIB_SUFFIX "" CACHE STRING "Define suffix of directory name (32/64)" ) set( PLUGINS_PATH "lib${LIB_SUFFIX}/psi-plus/plugins" CACHE STRING "Install suffix for plugins" ) ELSE() set( PLUGINS_PATH "psi-plus/plugins" CACHE STRING "Install suffix for plugins" ) ENDIF() option( USE_WEBENGINE "Use WebEngine support instead of Webkit" OFF ) find_package( Qt5 COMPONENTS Core REQUIRED ) if(${Qt5Core_VERSION} VERSION_GREATER 5.6.0) find_package( Qt5 COMPONENTS WebEngine QUIET ) if( Qt5WebEngine_FOUND ) set(USE_WEBENGINE ON) add_definitions( -DWEBENGINE=1 -DHAVE_WEBENGINE ) else() set(USE_WEBENGINE OFF) add_definitions( -DHAVE_WEBKIT ) endif() endif() add_definitions( -DQT_PLUGIN -DHAVE_QT5 ) include_directories( ${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ../../include . ) set( _SRCS ${PLUGIN}.cpp ScrollKeeper.cpp ) set( _HDRS ScrollKeeper.h ) set( _RSCS ${PLUGIN}.qrc ) add_definitions(-DHAVE_QT5) find_package(Qt5 COMPONENTS Widgets Xml Network REQUIRED) set(QT_DEPLIBS Qt5::Widgets Qt5::Xml Qt5::Network ) if( USE_WEBENGINE ) find_package(Qt5 COMPONENTS WebEngine WebEngineWidgets REQUIRED) list(APPEND QT_DEPLIBS Qt5::WebEngine Qt5::WebEngineWidgets ) else() find_package(Qt5 COMPONENTS WebKit WebKitWidgets REQUIRED) list(APPEND QT_DEPLIBS Qt5::WebKit Qt5::WebKitWidgets ) endif() qt5_wrap_ui(UIS ${_UIS}) qt5_add_resources(RSCS ${_RSCS}) add_library( ${PLUGIN} MODULE ${_SRCS} ${RSCS} ) target_link_libraries( ${PLUGIN} ${QT_DEPLIBS} ) if( UNIX AND NOT( APPLE OR CYGWIN ) ) install( TARGETS ${PLUGIN} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} ) endif() if( WIN32 ) install( TARGETS ${PLUGIN} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} ) endif() plugins-1.5/generic/imagepreviewplugin/ScrollKeeper.cpp000066400000000000000000000041271336777360500235020ustar00rootroot00000000000000/* * ScrollKeeper.cpp * * Created on: 30 Oct 2016 * Author: rkfg */ #include "ScrollKeeper.h" #ifdef HAVE_WEBKIT #include #include #endif #ifdef HAVE_WEBENGINE #include #endif #include //#define SCROLL_DEBUG ScrollKeeper::ScrollKeeper(QWidget* chatView) : chatView_(chatView), scrollPos_(0), scrollToEnd_(false), ted_(0) #ifdef HAVE_WEBKIT ,mainFrame_(0) #endif { Q_UNUSED(chatView_) ted_ = qobject_cast(chatView); if (ted_) { scrollPos_ = ted_->verticalScrollBar()->value(); if (scrollPos_ == ted_->verticalScrollBar()->maximum()) { scrollToEnd_ = true; } #ifdef SCROLL_DEBUG qDebug() << "QTED Scroll pos:" << scrollPos_ << "to end:" << scrollToEnd_ << "max:" << ted_->verticalScrollBar()->maximum(); #endif } else { #ifdef HAVE_WEBKIT QWebView* wv = qobject_cast(chatView); if (!wv) { return; } mainFrame_ = wv->page()->mainFrame(); scrollPos_ = mainFrame_->scrollBarValue(Qt::Vertical); if (scrollPos_ == mainFrame_->scrollBarMaximum(Qt::Vertical)) { scrollToEnd_ = true; } #ifdef SCROLL_DEBUG qDebug() << "QWV Scroll pos:" << scrollPos_ << "to end:" << scrollToEnd_ << "max:" << mainFrame_->scrollBarMaximum(Qt::Vertical) << "min:" << mainFrame_->scrollBarMinimum(Qt::Vertical); #endif #endif #ifdef HAVE_WEBENGINE #ifdef __GNUC__ #warning "ImagePreviewPlugin TODO: add support for webengine" #endif #endif } } ScrollKeeper::~ScrollKeeper() { if (ted_) { #ifdef SCROLL_DEBUG qDebug() << "QTED restoring scroll pos:" << scrollPos_ << "to end:" << scrollToEnd_ << "max:" << ted_->verticalScrollBar()->maximum(); #endif ted_->verticalScrollBar()->setValue(scrollToEnd_ ? ted_->verticalScrollBar()->maximum() : scrollPos_); } #ifdef HAVE_WEBKIT if (mainFrame_) { #ifdef SCROLL_DEBUG qDebug() << "QWV restoring scroll pos:" << scrollPos_ << "to end:" << scrollToEnd_ << "max:" << mainFrame_->scrollBarMaximum(Qt::Vertical); #endif mainFrame_->setScrollBarValue(Qt::Vertical, scrollToEnd_ ? mainFrame_->scrollBarMaximum(Qt::Vertical) : scrollPos_); } #endif } plugins-1.5/generic/imagepreviewplugin/ScrollKeeper.h000066400000000000000000000010601336777360500231400ustar00rootroot00000000000000/* * ScrollKeeper.h * * Created on: 30 Oct 2016 * Author: rkfg */ #ifndef SRC_PLUGINS_GENERIC_IMAGEPREVIEWPLUGIN_SCROLLKEEPER_H_ #define SRC_PLUGINS_GENERIC_IMAGEPREVIEWPLUGIN_SCROLLKEEPER_H_ #include #include class QWebFrame; class ScrollKeeper { private: QWidget* chatView_; int scrollPos_; bool scrollToEnd_; QTextEdit* ted_; #ifdef HAVE_WEBKIT QWebFrame* mainFrame_; #endif public: ScrollKeeper(QWidget* chatView); virtual ~ScrollKeeper(); }; #endif /* SRC_PLUGINS_GENERIC_IMAGEPREVIEWPLUGIN_SCROLLKEEPER_H_ */ plugins-1.5/generic/imagepreviewplugin/imagepreviewplugin.cpp000066400000000000000000000336131336777360500250150ustar00rootroot00000000000000/* * imageplugin.cpp - plugin * Copyright (C) 2016 rkfg * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "psiplugin.h" #include "plugininfoprovider.h" #include "optionaccessinghost.h" #include "optionaccessor.h" #include "chattabaccessor.h" #include "applicationinfoaccessor.h" #include "applicationinfoaccessinghost.h" #include "ScrollKeeper.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_WEBKIT #include #include #include #endif #ifdef HAVE_WEBENGINE #include #include #endif #include #undef AUTOREDIRECTS #if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)) #define AUTOREDIRECTS #endif //#define IMGPREVIEW_DEBUG #define constVersion "0.1.1" #define sizeLimitName "imgpreview-size-limit" #define previewSizeName "imgpreview-preview-size" #define allowUpscaleName "imgpreview-allow-upscale" #define MAX_REDIRECTS 2 class Origin: public QObject { Q_OBJECT public: Origin(QWidget* chat) : QObject(chat), originalUrl_(""), chat_(chat) #ifndef AUTOREDIRECTS , redirectsLeft_(0) #endif {} QString originalUrl_; QWidget* chat_; #ifndef AUTOREDIRECTS int redirectsLeft_; #endif }; class ImagePreviewPlugin: public QObject, public PsiPlugin, public PluginInfoProvider, public OptionAccessor, public ChatTabAccessor, public ApplicationInfoAccessor { Q_OBJECT #ifdef HAVE_QT5 Q_PLUGIN_METADATA(IID "com.psi-plus.ImagePreviewPlugin") #endif Q_INTERFACES(PsiPlugin PluginInfoProvider OptionAccessor ChatTabAccessor ApplicationInfoAccessor) public: ImagePreviewPlugin(); virtual QString name() const; virtual QString shortName() const; virtual QString version() const; virtual QWidget* options(); virtual bool enable(); virtual bool disable(); virtual void applyOptions(); virtual void restoreOptions(); virtual void setOptionAccessingHost(OptionAccessingHost *host); virtual void optionChanged(const QString &) { } virtual QString pluginInfo(); virtual QPixmap icon() const; virtual void setupChatTab(QWidget* widget, int, const QString&) { connect(widget, SIGNAL(messageAppended(const QString &, QWidget*)), SLOT(messageAppended(const QString &, QWidget*))); } virtual void setupGCTab(QWidget* widget, int, const QString&) { connect(widget, SIGNAL(messageAppended(const QString &, QWidget*)), SLOT(messageAppended(const QString &, QWidget*))); } virtual bool appendingChatMessage(int, const QString&, QString&, QDomElement&, bool) { return false; } virtual void setApplicationInfoAccessingHost(ApplicationInfoAccessingHost* host); void updateProxy(); ~ImagePreviewPlugin() { manager->deleteLater(); } private slots: void messageAppended(const QString &, QWidget*); void imageReply(QNetworkReply* reply); private: OptionAccessingHost *psiOptions; bool enabled; QNetworkAccessManager* manager; QSet pending, failed; int previewSize; QPointer sb_previewSize; int sizeLimit; QPointer cb_sizeLimit; bool allowUpscale; QPointer cb_allowUpscale; ApplicationInfoAccessingHost* appInfoHost; void queueUrl(const QString& url, Origin* origin); }; #ifndef HAVE_QT5 Q_EXPORT_PLUGIN(ImagePreviewPlugin) #endif ImagePreviewPlugin::ImagePreviewPlugin() : psiOptions(0), enabled(false), manager(new QNetworkAccessManager(this)), previewSize(0), sizeLimit(0), allowUpscale( false), appInfoHost(0) { connect(manager, SIGNAL(finished(QNetworkReply *)), SLOT(imageReply(QNetworkReply *))); } QString ImagePreviewPlugin::name() const { return "Image Preview Plugin"; } QString ImagePreviewPlugin::shortName() const { return "imgpreview"; } QString ImagePreviewPlugin::version() const { return constVersion; } bool ImagePreviewPlugin::enable() { enabled = true; sizeLimit = psiOptions->getPluginOption(sizeLimitName, 1024 * 1024).toInt(); previewSize = psiOptions->getPluginOption(previewSizeName, 150).toInt(); allowUpscale = psiOptions->getPluginOption(allowUpscaleName, true).toBool(); updateProxy(); return enabled; } bool ImagePreviewPlugin::disable() { enabled = false; return true; } QWidget* ImagePreviewPlugin::options() { if (!enabled) { return 0; } QWidget *optionsWid = new QWidget(); QVBoxLayout *vbox = new QVBoxLayout(optionsWid); cb_sizeLimit = new QComboBox(optionsWid); cb_sizeLimit->addItem(tr("512 Kb"), 512 * 1024); cb_sizeLimit->addItem(tr("1 Mb"), 1024 * 1024); cb_sizeLimit->addItem(tr("2 Mb"), 2 * 1024 * 1024); cb_sizeLimit->addItem(tr("5 Mb"), 5 * 1024 * 1024); cb_sizeLimit->addItem(tr("10 Mb"), 10 * 1024 * 1024); vbox->addWidget(new QLabel(tr("Maximum image size"))); vbox->addWidget(cb_sizeLimit); sb_previewSize = new QSpinBox(optionsWid); sb_previewSize->setMinimum(1); sb_previewSize->setMaximum(65535); vbox->addWidget(new QLabel(tr("Image preview size in pixels"))); vbox->addWidget(sb_previewSize); cb_allowUpscale = new QCheckBox(tr("Allow upscale")); vbox->addWidget(cb_allowUpscale); vbox->addStretch(); updateProxy(); return optionsWid; } void ImagePreviewPlugin::setOptionAccessingHost(OptionAccessingHost *host) { psiOptions = host; } QString ImagePreviewPlugin::pluginInfo() { return tr("Author: ") + "rkfg\n\n" + trUtf8("This plugin shows the preview image for an image URL.\n"); } QPixmap ImagePreviewPlugin::icon() const { return QPixmap(":/imagepreviewplugin/imagepreviewplugin.png"); } void ImagePreviewPlugin::queueUrl(const QString& url, Origin* origin) { if (!pending.contains(url) && !failed.contains(url)) { pending.insert(url); QNetworkRequest req; origin->originalUrl_ = url; #ifndef AUTOREDIRECTS origin->redirectsLeft_ = MAX_REDIRECTS; #endif req.setUrl(QUrl::fromUserInput(url)); req.setOriginatingObject(origin); req.setRawHeader("User-Agent", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36"); #ifdef AUTOREDIRECTS req.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true); req.setMaximumRedirectsAllowed(MAX_REDIRECTS); #endif manager->head(req); } } void ImagePreviewPlugin::messageAppended(const QString &, QWidget* logWidget) { if (!enabled) { return; } ScrollKeeper sk(logWidget); QTextEdit* te_log = qobject_cast(logWidget); if (te_log) { QTextCursor cur = te_log->textCursor(); te_log->moveCursor(QTextCursor::End, QTextCursor::MoveAnchor); te_log->moveCursor(QTextCursor::StartOfBlock, QTextCursor::MoveAnchor); QTextCursor found = te_log->textCursor(); while (!(found = te_log->document()->find(QRegExp("https?://\\S*"), found)).isNull()) { QString url = found.selectedText(); #ifdef IMGPREVIEW_DEBUG qDebug() << "URL FOUND:" << url; #endif queueUrl(url, new Origin(te_log)); }; te_log->setTextCursor(cur); } else { #ifdef HAVE_WEBKIT QWebView* wv_log = qobject_cast(logWidget); QWebFrame* mainFrame = wv_log->page()->mainFrame(); QWebElementCollection elems = mainFrame->findAllElements("a[href]"); for (QWebElementCollection::const_iterator i = elems.constEnd() - 1;; i--) { if ((*i).isNull()) { break; } // skip nick links and already processed anchors if (!(*i).classes().contains("nicklink", Qt::CaseInsensitive) && (*i).firstChild().tagName().toLower() != "img") { QString url = (*i).attribute("href", ""); if (url.startsWith("http://") || url.startsWith("https://")) { queueUrl(url, new Origin(wv_log)); } } } #endif #ifdef HAVE_WEBENGINE #ifdef __GNUC__ #warning "ImagePreviewPlugin TODO: add support for webengine" #endif #endif } } void ImagePreviewPlugin::imageReply(QNetworkReply* reply) { bool ok; int size = 0; QStringList contentTypes; QStringList allowedTypes; allowedTypes.append("image/jpeg"); allowedTypes.append("image/png"); allowedTypes.append("image/gif"); Origin* origin = qobject_cast(reply->request().originatingObject()); QString urlStr = origin->originalUrl_; QString urlStrEscaped = reply->url().toString(); #ifdef IMGPREVIEW_DEBUG qDebug() << "Original URL " << urlStr << " / Escaped: " << urlStrEscaped; #endif switch (reply->operation()) { case QNetworkAccessManager::HeadOperation: { #ifndef AUTOREDIRECTS int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(&ok); if (ok && (status == 301 || status == 302 || status == 303)) { if (origin->redirectsLeft_ == 0) { qWarning() << "Redirect count exceeded for" << urlStr; origin->deleteLater(); pending.remove(urlStr); break; } origin->redirectsLeft_--; QUrl location = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl(); if (location.isRelative()) { location = location.resolved(reply->request().url()); } #ifdef IMGPREVIEW_DEBUG qDebug() << "Redirected to" << location; #endif QNetworkRequest req = reply->request(); req.setUrl(location); manager->head(req); } else #endif { size = reply->header(QNetworkRequest::ContentLengthHeader).toInt(&ok); if (reply->error() == QNetworkReply::NoError) { ok = true; } contentTypes = reply->header(QNetworkRequest::ContentTypeHeader).toString().split(","); QString lastType = contentTypes.last().trimmed(); #ifdef IMGPREVIEW_DEBUG qDebug() << "URL:" << urlStr << "RESULT:" << reply->error() << "SIZE:" << size << "Content-type:" << contentTypes << " Last type: " << lastType; #endif if (ok && allowedTypes.contains(lastType, Qt::CaseInsensitive) && size < sizeLimit) { manager->get(reply->request()); } else { #ifdef IMGPREVIEW_DEBUG qDebug() << "Failed url " << origin->originalUrl_; #endif failed.insert(origin->originalUrl_); origin->deleteLater(); pending.remove(urlStr); } } break; } case QNetworkAccessManager::GetOperation: try { QImageReader imageReader(reply); QImage image = imageReader.read(); if (imageReader.error() != QImageReader::UnknownError) { throw std::runtime_error(imageReader.errorString().toStdString()); } if (image.width() > previewSize || image.height() > previewSize || allowUpscale) { image = image.scaled(previewSize, previewSize, Qt::KeepAspectRatio, Qt::SmoothTransformation); } #ifdef IMGPREVIEW_DEBUG qDebug() << "Image size:" << image.size(); #endif ScrollKeeper sk(origin->chat_); QTextEdit* te_log = qobject_cast(origin->chat_); if (te_log) { te_log->document()->addResource(QTextDocument::ImageResource, urlStrEscaped, image); QTextCursor saved = te_log->textCursor(); te_log->moveCursor(QTextCursor::End); QRegExp rawUrlRE = QRegExp("()(.*)()"); while (te_log->find(urlStr, QTextDocument::FindBackward)) { QTextCursor cur = te_log->textCursor(); QString html = cur.selection().toHtml(); if (html.contains(rawUrlRE)) { html.replace(rawUrlRE, QString("\\1\\3").arg(urlStrEscaped)); cur.insertHtml(html); } } te_log->setTextCursor(saved); } else { #ifdef HAVE_WEBKIT QByteArray imageBytes; QBuffer imageBuf(&imageBytes); image.save(&imageBuf, "jpg", 60); QWebView* wv_log = qobject_cast(origin->chat_); QWebFrame* mainFrame = wv_log->page()->mainFrame(); mainFrame->evaluateJavaScript(QString("var links = document.body.querySelectorAll('a[href=\"%1\"]');" "for (var i = 0; i < links.length; i++) {" " var elem = links[i];" " elem.innerHTML = \"\";" "}").arg(urlStr).arg(QString(imageBytes.toBase64()))); #endif #ifdef HAVE_WEBENGINE #ifdef __GNUC__ #warning "ImagePreviewPlugin TODO: add support for webengine" #endif #endif } } catch (std::exception& e) { failed.insert(origin->originalUrl_); qWarning() << "ERROR: " << e.what(); } origin->deleteLater(); pending.remove(urlStr); break; default: break; } reply->deleteLater(); } void ImagePreviewPlugin::applyOptions() { psiOptions->setPluginOption(previewSizeName, previewSize = sb_previewSize->value()); psiOptions->setPluginOption(sizeLimitName, sizeLimit = cb_sizeLimit->itemData(cb_sizeLimit->currentIndex()).toInt()); psiOptions->setPluginOption(allowUpscaleName, allowUpscale = cb_allowUpscale->checkState() == Qt::Checked); } void ImagePreviewPlugin::restoreOptions() { sb_previewSize->setValue(previewSize); cb_sizeLimit->setCurrentIndex(cb_sizeLimit->findData(sizeLimit)); cb_allowUpscale->setCheckState(allowUpscale ? Qt::Checked : Qt::Unchecked); } void ImagePreviewPlugin::setApplicationInfoAccessingHost(ApplicationInfoAccessingHost* host) { appInfoHost = host; } void ImagePreviewPlugin::updateProxy() { Proxy proxy = appInfoHost->getProxyFor(name()); #ifdef IMGPREVIEW_DEBUG qDebug() << "Proxy:" << "T:" << proxy.type << "H:" << proxy.host << "Pt:" << proxy.port << "U:" << proxy.user << "Ps:" << proxy.pass; #endif if (proxy.type.isEmpty()) { manager->setProxy(QNetworkProxy()); return; } QNetworkProxy netProxy(proxy.type == "socks" ? QNetworkProxy::Socks5Proxy : QNetworkProxy::HttpProxy, proxy.host, proxy.port, proxy.user, proxy.pass); manager->setProxy(netProxy); } #include "imagepreviewplugin.moc" plugins-1.5/generic/imagepreviewplugin/imagepreviewplugin.png000066400000000000000000000011111336777360500250030ustar00rootroot00000000000000PNG  IHDRasRGBbKGD pHYs B(xtIME *"I!IDATxڥMkQ;νL$iN?TREQ B Xt!EV]hd@cHM&2P@k8xy@  &|݁DU`| !ĘٙL jwTk|Ez3WWD7A'asEIA'!H*1m újX@Q X3I8Be/F-n+͕K 7y50eQ?5dgbi\͏m i6'&|O%xh/b-+m OGI#WI_šxp5|ɓ~nqE9D-rUNLPfn5v=eEj50q2omv[M terP+!sa@z7ϴw|[{CtIENDB`plugins-1.5/generic/imagepreviewplugin/imagepreviewplugin.pro000066400000000000000000000010121336777360500250170ustar00rootroot00000000000000isEmpty(PSISDK) { include(../../psiplugin.pri) } else { include($$PSISDK/plugins/psiplugin.pri) } QT += network greaterThan(QT_MAJOR_VERSION, 4) { qtHaveModule(webengine) { QT += webengine webenginewidgets DEFINES += HAVE_WEBENGINE } qtHaveModule(webkit) { QT += webkit webkitwidgets DEFINES += HAVE_WEBKIT } } else { QT += webkit DEFINES += HAVE_WEBKIT } RESOURCES = imagepreviewplugin.qrc SOURCES += imagepreviewplugin.cpp \ ScrollKeeper.cpp plugins-1.5/generic/imagepreviewplugin/imagepreviewplugin.qrc000066400000000000000000000002101336777360500250030ustar00rootroot00000000000000 imagepreviewplugin.png plugins-1.5/generic/jabberdiskplugin/000077500000000000000000000000001336777360500200145ustar00rootroot00000000000000plugins-1.5/generic/jabberdiskplugin/CMakeLists.txt000066400000000000000000000030351336777360500225550ustar00rootroot00000000000000unset(_HDRS) unset(_UIS) unset(_SRCS) unset(_RSCS) unset(PLUGIN) set( PLUGIN jabberdiskplugin ) project(${PLUGIN}) cmake_minimum_required(VERSION 3.1.0) set( CMAKE_AUTOMOC TRUE ) IF( NOT WIN32 ) set( LIB_SUFFIX "" CACHE STRING "Define suffix of directory name (32/64)" ) set( PLUGINS_PATH "lib${LIB_SUFFIX}/psi-plus/plugins" CACHE STRING "Install suffix for plugins" ) ELSE() set( PLUGINS_PATH "psi-plus/plugins" CACHE STRING "Install suffix for plugins" ) ENDIF() add_definitions( -DQT_PLUGIN -DHAVE_QT5 ) include_directories ( ${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ../../include . ) set( _HDRS ${PLUGIN}.h model.h jabberdiskcontroller.h jd_commands.h jd_item.h jd_mainwin.h jd_view.h ) set( _SRCS ${PLUGIN}.cpp model.cpp jabberdiskcontroller.cpp jd_commands.cpp jd_item.cpp jd_mainwin.cpp jd_view.cpp ) set( _UIS options.ui jd_mainwin.ui ) set( _RSCS resources.qrc ) find_package( Qt5 COMPONENTS Widgets Xml REQUIRED ) set(QT_DEPLIBS Qt5::Widgets Qt5::Xml ) qt5_wrap_ui(UIS ${_UIS}) qt5_add_resources(RSCS ${_RSCS}) add_library( ${PLUGIN} MODULE ${_SRCS} ${UIS} ${RSCS} ) target_link_libraries( ${PLUGIN} ${QT_DEPLIBS} ) if( UNIX AND NOT( APPLE OR CYGWIN ) ) install( TARGETS ${PLUGIN} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} ) endif() if( WIN32 ) install( TARGETS ${PLUGIN} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} ) endif() plugins-1.5/generic/jabberdiskplugin/changelog.txt000066400000000000000000000020721336777360500225050ustar00rootroot000000000000002013-08-13 v0.0.4 - taurus + Иконка плагина 2011-03-02 v0.0.3 + добавлена возможность переименовывать файлы + добавлена возможность перемещать файлы с одного диска на другой * различные исправления 2011-03-01 v0.0.2 + добавлена кнопка очистки лога + добавлена возможность перемещать файлы по каталогам с помощию драг-н-дропа * различные исправления и улучшения 2011-02-28 v0.0.1 ! Initial version Данный плагин предназначен для комфортной работы с файловыми хранилищами Jabber Disk Просто выберете соответствующий пунк в контекстном меню контакта В данный момент реализован самый базовый функционал и самые изощренные баги ;) plugins-1.5/generic/jabberdiskplugin/jabberdisk.png000066400000000000000000000020201336777360500226140ustar00rootroot00000000000000PNG  IHDRa pHYs B(xtEXtSoftwarewww.inkscape.org<IDATxEkL[e51Bhe2tрk/& 1KѮ79 -=t-Dh:b Lm^)Pz;=-ib\Ny==(""D/`dc0jidcZ0E@k eD|/*#VOWK$T /ꠗ޽Skm]_-YTi"]|5~j@~Hyked- n7'?EY @$ɻ k>KW.6t-vwphs~ޙ>[;CPe4W/  𥩟W|_:;|KZǘ|rv ~g N)d50"a+k !?3~?@yDי_Q :n=`2D`FnxRL&U^Ÿn.?ycc.Bǹt. =nk][,^zP70(NLK)kW#o ˍ_ ^sB?]<r\ɔ<ǃ<ʮ+\. P(pl׸KjYF>ţJ4Ex% L&M'yh"0W"r*}Ѫ^t5t_-` Bا`R)t:;fSP B Hx'0UDBx"}}45I`>W^j5K[TIa$HZ`RLůuwj`tt:::#m @.L&?bfr38IENDB`plugins-1.5/generic/jabberdiskplugin/jabberdiskcontroller.cpp000066400000000000000000000066101336777360500247270ustar00rootroot00000000000000/* * jabberdiskcontroller.cpp - plugin * Copyright (C) 2011 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include #include #include "jabberdiskcontroller.h" #include "jd_mainwin.h" struct Session { Session(int a, const QString& j, JDMainWin* w = 0) : account(a) , jid(j) , window(w) { } int account; QString jid; JDMainWin* window; bool operator==(const Session& s) { return account == s.account && jid == s.jid; } }; JabberDiskController::JabberDiskController() : QObject(0) , stanzaSender(0) // , iconHost(0) , accInfo(0) { } JabberDiskController::~JabberDiskController() { while(!sessions_.isEmpty()) { delete sessions_.takeFirst().window; } } JabberDiskController* JabberDiskController::instance() { if(instance_) return instance_; return instance_ = new JabberDiskController(); } void JabberDiskController::reset() { delete instance_; instance_ = 0; } void JabberDiskController::viewerDestroyed() { JDMainWin *w = static_cast(sender()); for(int i = 0; i < sessions_.size(); i++) { Session s = sessions_.at(i); if(s.window == w) { sessions_.removeAt(i); break; } } } void JabberDiskController::initSession() { QAction* act = dynamic_cast(sender()); if(act) { int account = act->property("account").toInt(); const QString jid = act->property("jid").toString(); Session s(account, jid); if(sessions_.contains(s)) { sessions_.at(sessions_.indexOf(s)).window->raise(); } else { s.window = new JDMainWin(accInfo->getJid(account), jid, account); connect(s.window, SIGNAL(destroyed()), SLOT(viewerDestroyed())); sessions_.append(s); } } } void JabberDiskController::sendStanza(int account, const QString &to, const QString &message, QString* id) { *id = stanzaSender->uniqueId(account); QString txt = QString("" "%4") .arg(accInfo->getJid(account)) .arg(to) .arg(*id) #ifdef HAVE_QT5 .arg(message.toHtmlEscaped()); #else .arg(Qt::escape(message)); #endif stanzaSender->sendStanza(account, txt); } //void JabberDiskController::setIconFactoryAccessingHost(IconFactoryAccessingHost* host) //{ // iconHost = host; //} void JabberDiskController::setStanzaSendingHost(StanzaSendingHost *host) { stanzaSender = host; } void JabberDiskController::setAccountInfoAccessingHost(AccountInfoAccessingHost* host) { accInfo = host; } bool JabberDiskController::incomingStanza(int account, const QDomElement& xml) { Session s(account, xml.attribute("from").split("/").at(0).toLower()); if(sessions_.contains(s)) { emit stanza(account, xml); return true; } return false; } JabberDiskController* JabberDiskController::instance_ = 0; plugins-1.5/generic/jabberdiskplugin/jabberdiskcontroller.h000066400000000000000000000036561336777360500244030ustar00rootroot00000000000000/* * jabberdiskcontroller.h - plugin * Copyright (C) 2011 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef JABBERDISKCONTROLLER_H #define JABBERDISKCONTROLLER_H //class QIcon; class JDMainWin; struct Session; class QDomElement; #include //#include "iconfactoryaccessinghost.h" #include "stanzasendinghost.h" #include "accountinfoaccessinghost.h" class JabberDiskController : public QObject { Q_OBJECT public: static JabberDiskController* instance(); static void reset(); virtual ~JabberDiskController(); //void setIconFactoryAccessingHost(IconFactoryAccessingHost* host); void setStanzaSendingHost(StanzaSendingHost *host); void setAccountInfoAccessingHost(AccountInfoAccessingHost* host); bool incomingStanza(int account, const QDomElement& xml); void sendStanza(int account, const QString& to, const QString& message, QString* id); signals: void stanza(int account, const QDomElement& xml); public slots: void initSession(); private slots: void viewerDestroyed(); private: JabberDiskController(); static JabberDiskController* instance_; private: StanzaSendingHost* stanzaSender; //IconFactoryAccessingHost* iconHost; AccountInfoAccessingHost* accInfo; QList sessions_; }; #endif // JABBERDISKCONTROLLER_H plugins-1.5/generic/jabberdiskplugin/jabberdiskplugin.cpp000066400000000000000000000114561336777360500240460ustar00rootroot00000000000000/* * jabberdiskplugin.cpp - plugin * Copyright (C) 2011 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include #include #include "jabberdiskplugin.h" #include "jabberdiskcontroller.h" static const QString constJids_ = "jids"; JabberDiskPlugin::JabberDiskPlugin() : enabled(false) , psiOptions(0) { jids_ = QStringList() << "disk.jabbim.cz"; } QString JabberDiskPlugin::name() const { return "Jabber Disk Plugin"; } QString JabberDiskPlugin::shortName() const { return "jabberdisk"; } QString JabberDiskPlugin::version() const { return constVersion; } bool JabberDiskPlugin::enable() { enabled = true; jids_ = psiOptions->getPluginOption(constJids_, jids_).toStringList(); return enabled; } bool JabberDiskPlugin::disable() { JabberDiskController::instance()->reset(); enabled = false; return true; } void JabberDiskPlugin::applyOptions() { if(!options_) return; jids_.clear(); for(int i = 0; i < ui_.lw_jids->count(); i++) { jids_.append(ui_.lw_jids->item(i)->text()); } psiOptions->setPluginOption(constJids_, jids_); } void JabberDiskPlugin::restoreOptions() { if(!options_) return; ui_.lw_jids->addItems(jids_); } QWidget* JabberDiskPlugin::options() { if (!enabled) { return 0; } options_ = new QWidget(); ui_.setupUi(options_); ui_.cb_hack->setVisible(false); restoreOptions(); connect(ui_.pb_add, SIGNAL(clicked()), SLOT(addJid())); connect(ui_.pb_delete, SIGNAL(clicked()), SLOT(removeJid())); return options_; } //этот слот нужен для активации кнопки "Применить" void JabberDiskPlugin::hack() { ui_.cb_hack->toggle(); } bool JabberDiskPlugin::incomingStanza(int account, const QDomElement& xml) { if(!enabled) return false; if(xml.tagName() == "message" && !xml.firstChildElement("body").isNull()) { const QString from = xml.attribute("from"); bool find = false; foreach(const QString& jid, jids_) { if(from.contains(jid, Qt::CaseInsensitive)) { find = true; break; } } if(find) { return JabberDiskController::instance()->incomingStanza(account, xml); } } return false; } void JabberDiskPlugin::addJid() { if(!options_) return; const QString& txt = ui_.le_addJid->text(); if(!txt.isEmpty()) { ui_.lw_jids->addItem(txt); hack(); } } void JabberDiskPlugin::removeJid() { if(!options_) return; QListWidgetItem *i = ui_.lw_jids->currentItem(); ui_.lw_jids->removeItemWidget(i); delete i; hack(); } bool JabberDiskPlugin::outgoingStanza(int/* account*/, QDomElement&/* xml*/) { return false; } void JabberDiskPlugin::setAccountInfoAccessingHost(AccountInfoAccessingHost* host) { JabberDiskController::instance()->setAccountInfoAccessingHost(host); } void JabberDiskPlugin::setIconFactoryAccessingHost(IconFactoryAccessingHost* host) { iconHost = host; //JabberDiskController::instance()->setIconFactoryAccessingHost(host); } void JabberDiskPlugin::setStanzaSendingHost(StanzaSendingHost *host) { JabberDiskController::instance()->setStanzaSendingHost(host); } void JabberDiskPlugin::setOptionAccessingHost(OptionAccessingHost *host) { psiOptions = host; } //void JabberDiskPlugin::setPopupAccessingHost(PopupAccessingHost* host) //{ // popup = host; //} QList < QVariantHash > JabberDiskPlugin::getAccountMenuParam() { return QList < QVariantHash >(); } QList < QVariantHash > JabberDiskPlugin::getContactMenuParam() { return QList < QVariantHash >(); } QAction* JabberDiskPlugin::getContactAction(QObject *p, int acc, const QString &jid) { foreach(const QString& j, jids_) { if(jid.contains(j)) { QAction* act = new QAction(iconHost->getIcon("psi/save"), tr("Jabber Disk"), p); act->setProperty("account", acc); act->setProperty("jid", jid.toLower().split("/").at(0)); connect(act, SIGNAL(triggered()), JabberDiskController::instance(), SLOT(initSession())); return act; } } return 0; } QString JabberDiskPlugin::pluginInfo() { return tr("Author: ") + "Dealer_WeARE\n" + tr("Email: ") + "wadealer@gmail.com\n\n"; } QPixmap JabberDiskPlugin::icon() const { return QPixmap(":/icons/jabberdisk.png"); } #ifndef HAVE_QT5 Q_EXPORT_PLUGIN(JabberDiskPlugin); #endif plugins-1.5/generic/jabberdiskplugin/jabberdiskplugin.h000066400000000000000000000065151336777360500235130ustar00rootroot00000000000000/* * jabberdiskplugin.h - plugin * Copyright (C) 2011 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef JABBERDISKPLUGIN_H #define JABBERDISKPLUGIN_H class QAction; class QDomElement; #include "psiplugin.h" #include "iconfactoryaccessor.h" #include "iconfactoryaccessinghost.h" #include "stanzasender.h" #include "stanzasendinghost.h" #include "accountinfoaccessinghost.h" #include "accountinfoaccessor.h" #include "stanzafilter.h" //#include "popupaccessor.h" //#include "popupaccessinghost.h" #include "menuaccessor.h" #include "plugininfoprovider.h" #include "optionaccessinghost.h" #include "optionaccessor.h" #include "ui_options.h" #define constVersion "0.0.4" class JabberDiskPlugin : public QObject, public PsiPlugin, public StanzaSender, public IconFactoryAccessor, public PluginInfoProvider, public StanzaFilter, public MenuAccessor, public AccountInfoAccessor, public OptionAccessor /*, public PopupAccessor,*/ { Q_OBJECT #ifdef HAVE_QT5 Q_PLUGIN_METADATA(IID "com.psi-plus.JabberDiskPlugin") #endif Q_INTERFACES(PsiPlugin StanzaFilter StanzaSender IconFactoryAccessor AccountInfoAccessor// PopupAccessor MenuAccessor PluginInfoProvider OptionAccessor) public: JabberDiskPlugin(); virtual QString name() const; virtual QString shortName() const; virtual QString version() const; virtual QWidget* options(); virtual bool enable(); virtual bool disable(); virtual Priority priority() { return PsiPlugin::PriorityHigh; } virtual void applyOptions(); virtual void restoreOptions(); virtual void setOptionAccessingHost(OptionAccessingHost* host); virtual void optionChanged(const QString& ) {}; virtual void setIconFactoryAccessingHost(IconFactoryAccessingHost* host); virtual void setStanzaSendingHost(StanzaSendingHost *host); virtual void setAccountInfoAccessingHost(AccountInfoAccessingHost* host); virtual bool incomingStanza(int account, const QDomElement& xml); virtual bool outgoingStanza(int account, QDomElement& xml); //virtual void setPopupAccessingHost(PopupAccessingHost* host); virtual QList < QVariantHash > getAccountMenuParam(); virtual QList < QVariantHash > getContactMenuParam(); virtual QAction* getContactAction(QObject* , int , const QString& ); virtual QAction* getAccountAction(QObject* , int ) { return 0; }; virtual QString pluginInfo(); virtual QPixmap icon() const; //signals: private slots: void addJid(); void removeJid(); private: void hack(); private: bool enabled; QPointer options_; Ui::Options ui_; OptionAccessingHost* psiOptions; QStringList jids_; IconFactoryAccessingHost* iconHost; // // PopupAccessingHost* popup; }; #endif plugins-1.5/generic/jabberdiskplugin/jabberdiskplugin.pro000066400000000000000000000010041336777360500240500ustar00rootroot00000000000000isEmpty(PSISDK) { include(../../psiplugin.pri) } else { include($$PSISDK/plugins/psiplugin.pri) } INCLUDEPATH += $$PWD DEPENDPATH += $$PWD SOURCES += jabberdiskplugin.cpp \ model.cpp \ jabberdiskcontroller.cpp \ jd_commands.cpp \ jd_item.cpp \ jd_mainwin.cpp \ jd_view.cpp FORMS += options.ui \ jd_mainwin.ui HEADERS += jabberdiskplugin.h \ model.h \ jabberdiskcontroller.h \ jd_commands.h \ jd_item.h \ jd_mainwin.h \ jd_view.h RESOURCES += resources.qrc plugins-1.5/generic/jabberdiskplugin/jd_commands.cpp000066400000000000000000000067141336777360500230060ustar00rootroot00000000000000/* * jd_commands.h - plugin * Copyright (C) 2011 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include #include #include #include #include "jd_commands.h" #include "jabberdiskcontroller.h" #define TIMER_INTERVAL 5000 JDCommands::JDCommands(int account, const QString &jid, QObject *p) : QObject(p) , account_(account) , jid_(jid) , jdc(JabberDiskController::instance()) , timer_(new QTimer(this)) , eventLoop_(new QEventLoop(this)) , lastCommand_(CommandNoCommand) { timer_->setInterval(TIMER_INTERVAL); connect(jdc, SIGNAL(stanza(int,QDomElement)), this, SLOT(incomingStanza(int,QDomElement))); connect(timer_, SIGNAL(timeout()), this, SLOT(timeOut())); } JDCommands::~JDCommands() { timeOut(); } void JDCommands::incomingStanza(int account, const QDomElement &xml) { if(account != account_ || xml.attribute("from").split("/").at(0).toLower() != jid_) return; emit incomingMessage(xml.firstChildElement("body").text(), lastCommand_); lastCommand_ = CommandNoCommand; timeOut(); } void JDCommands::get(const QString& file) { sendStanza("get "+file, CommandGet); } void JDCommands::cd(const QString& dir) { sendStanza("cd "+dir, CommandCd); } void JDCommands::help() { sendStanza("help", CommandHelp); } void JDCommands::intro() { sendStanza("intro", CommandIntro); } void JDCommands::hash(const QString& file) { sendStanza("hash "+file, CommandHash); } void JDCommands::rm(const QString& path) { sendStanza("rm "+path, CommandRm); } void JDCommands::du() { sendStanza("du", CommandDu); } void JDCommands::mkDir(const QString& dir) { sendStanza("mkdir "+dir, CommandMkDir); } void JDCommands::lang(const QString& l) { sendStanza("lang "+l, CommandLang); } void JDCommands::pwd() { sendStanza("pwd", CommandPwd); } void JDCommands::ls(const QString& dir) { QString txt = "ls"; if(!dir.isEmpty()) txt += " "+dir; sendStanza(txt, CommandLs); } void JDCommands::send(const QString &toJid, const QString &file) { sendStanza("send "+toJid+" "+file, CommandSend); } void JDCommands::mv(const QString& oldFile, const QString& newFile) { sendStanza("mv "+oldFile+" "+newFile, CommandMv); } void JDCommands::link(const QString &file) { sendStanza("link "+file, CommandLink); } void JDCommands::sendStanzaDirect(const QString &text) { emit outgoingMessage(text); QString id; jdc->sendStanza(account_, jid_, text, &id); } void JDCommands::sendStanza(const QString &text, Command c) { emit outgoingMessage(text); lastCommand_ = c; QString id; jdc->sendStanza(account_, jid_, text, &id); timer_->start(); eventLoop_->exec(); } void JDCommands::timeOut() { if(timer_->isActive()) timer_->stop(); if(eventLoop_->isRunning()) eventLoop_->quit(); } bool JDCommands::isReady() const { return !eventLoop_->isRunning(); } plugins-1.5/generic/jabberdiskplugin/jd_commands.h000066400000000000000000000043271336777360500224510ustar00rootroot00000000000000/* * jd_commands.h - plugin * Copyright (C) 2011 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef JD_COMMANDS_H #define JD_COMMANDS_H #include class QEventLoop; class QTimer; class QDomElement; class JabberDiskController; class JDCommands : public QObject { Q_OBJECT public: JDCommands(int account = -1, const QString& jid = QString(), QObject* p = 0); virtual ~JDCommands(); enum Command { CommandNoCommand, CommandGet, CommandCd, CommandHelp, CommandIntro, CommandHash, CommandRm, CommandDu, CommandMkDir, CommandLang, CommandPwd, CommandLs, CommandSend, CommandMv, CommandLink }; void get(const QString& file); void cd(const QString& dir); void help(); void intro(); void hash(const QString& file); void rm(const QString& path); void du(); void mkDir(const QString& dir); void lang(const QString& l); void pwd(); void ls(const QString& dir = QString()); void send(const QString& toJid, const QString& file); void mv(const QString& oldFile, const QString& newFile); void link(const QString& file); void sendStanzaDirect(const QString& text); bool isReady() const; signals: void incomingMessage(const QString&, JDCommands::Command); void outgoingMessage(const QString&); private slots: void incomingStanza(int account, const QDomElement& xml); void timeOut(); private: void sendStanza(const QString& text, Command c); private: int account_; QString jid_; JabberDiskController* jdc; QTimer* timer_; QEventLoop* eventLoop_; Command lastCommand_; }; #endif // JD_COMMANDS_H plugins-1.5/generic/jabberdiskplugin/jd_item.cpp000066400000000000000000000064351336777360500221430ustar00rootroot00000000000000/* * jd_item.cpp - plugin * Copyright (C) 2011 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include #include #include #include "jd_item.h" //#include JDItem::JDItem(Type t, const QString& name, const QString& size, const QString& descr, int number, JDItem* parent) : parent_(parent) , name_(name) , size_(size) , descr_(descr) , number_(number) , type_(t) { } JDItem::JDItem(Type t, JDItem* parent) : parent_(parent) , type_(t) { } JDItem::~JDItem() { } void JDItem::setData(const QString& name, const QString& size, const QString& descr, int number) { name_ = name; size_ = size; descr_ = descr; number_ = number; } JDItem* JDItem::parent() const { return parent_; } JDItem::Type JDItem::type() const { return type_; } QString JDItem::name() const { return name_; } QString JDItem::size() const { return size_; } QString JDItem::description() const { return descr_; } QString JDItem::fullPath() const { QString path; if(type_ == File) { path = QString("#%1").arg(QString::number(number_)); } if(type_ == Dir) { path = name_; } path = parentPath() + path; return path; } QString JDItem::parentPath() const { QString path; JDItem* it = parent_; while(it) { path = it->name() + path; it = it->parent(); } return path; } int JDItem::number() const { return number_; } const QString JDItem::mimeType() { return "jditem/file"; } bool JDItem::operator==(const JDItem& i) { return name_ == i.name() && parent_ == i.parent() && number_ == i.number() && size_ == i.size() && descr_ == i.description(); } QMimeData* JDItem::mimeData() const { QMimeData* data = new QMimeData(); QByteArray ba; QDataStream out(&ba, QIODevice::WriteOnly); out << name_ << size_ << descr_ << number_ << type_; out << fullPath(); //Эта информация нам потребуется в моделе data->setData(mimeType(), ba); return data; } void JDItem::fromDataStream(QDataStream *const in) { int t; *in >> name_ >> size_ >> descr_ >> number_ >> t; type_ = (Type)t; } //----------------------------------- //------ItemsList-------------------- //----------------------------------- ItemsList::ItemsList() : QList() { } //ВНИМАНИЕ! Перед удалением листа желательно явно вызвать метод clear(); ItemsList::~ItemsList() { } bool ItemsList::contains(const JDItem *const item) const { for(int i = 0; i < size(); i++) { if(*at(i).item == *item) return true; } return false; } void ItemsList::clear() { while(!isEmpty()) delete this->takeFirst().item; QList::clear(); } plugins-1.5/generic/jabberdiskplugin/jd_item.h000066400000000000000000000043441336777360500216050ustar00rootroot00000000000000/* * jd_item.h - plugin * Copyright (C) 2011 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef JD_ITEM_H #define JD_ITEM_H #include class JDItem { public: enum Type { None, Dir, File }; JDItem(Type t, const QString& name, const QString& size = QString(), const QString& descr = QString(), int number = -1, JDItem* parent = 0); JDItem(Type t, JDItem* parent = 0); virtual ~JDItem(); void setData(const QString& name, const QString& size = QString(), const QString& descr = QString(), int number = -1); JDItem* parent() const; Type type() const; QString name() const; QString size() const; QString description() const; int number() const; QString fullPath() const; QString parentPath() const; QMimeData* mimeData() const; void fromDataStream(QDataStream *const in); static const QString mimeType(); // bool operator<(const JDItem& i); // bool operator>(const JDItem& i); bool operator==(const JDItem& i); private: JDItem* parent_; QString name_; QString size_; QString descr_; int number_; Type type_; }; struct ProxyItem { ProxyItem() : item(0) , index(QModelIndex()) , parent(QModelIndex()) { } JDItem* item; QModelIndex index; QModelIndex parent; bool isNull() { return !index.isValid() && !parent.isValid() && !item; } bool operator==(const ProxyItem& i) { return item == i.item && index == i.index && parent == i.parent; } }; class ItemsList : public QList { public: ItemsList(); ~ItemsList(); bool contains(const JDItem *const item) const; void clear(); }; #endif // JD_ITEM_H plugins-1.5/generic/jabberdiskplugin/jd_mainwin.cpp000066400000000000000000000205731336777360500226460ustar00rootroot00000000000000/* * jd_mainwin.cpp - plugin * Copyright (C) 2011 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "jd_mainwin.h" #include "model.h" #include #include #include #include #include //#include JDMainWin::JDMainWin(const QString &name, const QString &jid, int acc, QWidget *p) : QDialog(p, Qt::Window) , model_(0) , commands_(0) , refreshInProgres_(false) , yourJid_(name) { setAttribute(Qt::WA_DeleteOnClose); ui_.setupUi(this); setWindowTitle(tr("Jabber Disk - %1").arg(name)); model_ = new JDModel(jid, this); ui_.lv_disk->setModel(model_); commands_ = new JDCommands(acc, jid, this); ui_.pb_send->setShortcut(QKeySequence("Ctrl+Return")); connect(commands_, SIGNAL(incomingMessage(QString,JDCommands::Command)), SLOT(incomingMessage(QString,JDCommands::Command))); connect(commands_, SIGNAL(outgoingMessage(QString)), SLOT(outgoingMessage(QString))); connect(ui_.pb_refresh, SIGNAL(clicked()), SLOT(refresh())); connect(ui_.pb_send, SIGNAL(clicked()), SLOT(doSend())); connect(ui_.pb_clear, SIGNAL(clicked()), SLOT(clearLog())); connect(ui_.lv_disk, SIGNAL(newIndex(QModelIndex)), SLOT(indexChanged(QModelIndex))); connect(ui_.lv_disk, SIGNAL(contextMenu(QModelIndex)), SLOT(indexContextMenu(QModelIndex))); connect(model_, SIGNAL(moveItem(QString,QString)), SLOT(moveItem(QString,QString))); show(); QTimer::singleShot(0, this, SLOT(refresh())); } JDMainWin::~JDMainWin() { } void JDMainWin::incomingMessage(const QString &message, JDCommands::Command command) { switch(command) { case JDCommands::CommandLs: parse(message); break; case JDCommands::CommandRm: case JDCommands::CommandMkDir: case JDCommands::CommandMv: QTimer::singleShot(100, this, SLOT(refresh())); break; case JDCommands::CommandGet: case JDCommands::CommandCd: case JDCommands::CommandSend: case JDCommands::CommandHash: case JDCommands::CommandLang: case JDCommands::CommandPwd: case JDCommands::CommandHelp: case JDCommands::CommandIntro: case JDCommands::CommandDu: case JDCommands::CommandLink: case JDCommands::CommandNoCommand: break; } appendMessage(message, false); } void JDMainWin::refresh() { refreshInProgres_ = true; ui_.pb_refresh->setEnabled(false); ui_.pb_send->setEnabled(false); model_->clear(); commands_->cd(JDModel::rootPath()); currentDir_.clear(); recursiveFind(currentDir_); ui_.lv_disk->expand(model_->rootIndex()); ui_.lv_disk->setCurrentIndex(model_->rootIndex()); ui_.pb_refresh->setEnabled(true); ui_.pb_send->setEnabled(true); refreshInProgres_ = false; } void JDMainWin::recursiveFind(const QString& dir) { QString tmp = currentDir_; commands_->ls(dir); QStringList dirs = model_->dirs(dir); foreach(const QString& d, dirs) { currentDir_ += d; recursiveFind(currentDir_); currentDir_ = tmp; } } void JDMainWin::doSend() { const QString mes = ui_.te_message->toPlainText(); if(!mes.isEmpty()) { commands_->sendStanzaDirect(mes); ui_.te_message->clear(); } } void JDMainWin::outgoingMessage(const QString &message) { appendMessage(message); } void JDMainWin::appendMessage(const QString& message, bool outgoing) { #ifdef HAVE_QT5 QString msg = message.toHtmlEscaped().replace("\n", "
"); #else QString msg = Qt::escape(message).replace("\n", "
"); #endif if (outgoing) msg = "" + tr("You: ") + msg+ ""; else msg = "" + tr("Disk: ") + msg + ""; ui_.te_log->append(msg); } void JDMainWin::clearLog() { ui_.te_log->clear(); } void JDMainWin::parse(QString message) { static const QRegExp dirRE("
(\\S+/)"); static const QRegExp fileRE("([0-9]+) - (.*) \\[(\\S+)\\] - (.*)"); QTextStream str(&message, QIODevice::ReadOnly); while(!str.atEnd()) { QString line = str.readLine(); if(dirRE.indexIn(line) != -1) { model_->addDir(currentDir_, dirRE.cap(1)); } else if(fileRE.indexIn(line) != -1) { model_->addFile(currentDir_,fileRE.cap(2), fileRE.cap(3), fileRE.cap(4), fileRE.cap(1).toInt()); } } } void JDMainWin::indexChanged(const QModelIndex& index) { if(refreshInProgres_) return; const QString tmp = currentDir_; if(model_->data(index, JDModel::RoleType).toInt() != JDItem::File) { currentDir_ = model_->data(index, JDModel::RoleFullPath).toString(); } else { currentDir_ = model_->data(index, JDModel::RoleParentPath).toString(); } if(currentDir_ == JDModel::rootPath()) currentDir_.clear(); if(tmp != currentDir_) { if(!tmp.isEmpty()) commands_->cd(JDModel::rootPath()); if(!currentDir_.isEmpty()) commands_->cd(currentDir_); } } void JDMainWin::indexContextMenu(const QModelIndex& index) { QMenu m; JDItem::Type type = (JDItem::Type)index.data(JDModel::RoleType).toInt(); QList aList; QAction* actRemove = new QAction(tr("Remove"), &m); QAction* actMake = new QAction(tr("Make dir"), &m); QAction* actGet = new QAction(tr("Get File"), &m); QAction* actSend = new QAction(tr("Send File"), &m); QAction* actHash = new QAction(tr("Hash"), &m); QAction* actLink = new QAction(tr("Link"), &m); QAction* actHelp = new QAction(tr("Help"), &m); QAction* actIntro = new QAction(tr("Intro"), &m); QAction* actDu = new QAction(tr("Statistics"), &m); QAction* actRename = new QAction(tr("Rename"), &m); QMenu move; move.setTitle(tr("Move to...")); QAction *actPublic = new QAction("public", &move); QAction *actAlbum = new QAction("album", &move); QAction *actPrivate = new QAction("private", &move); move.addActions(QList() << actPublic << actAlbum << actPrivate); if(type == JDItem::File) { aList << actRename << actGet << actSend << actLink << actHash << actRemove << move.menuAction(); } else { aList << actMake; } if(type == JDItem::Dir) { aList << actRemove; } if(type == JDItem::None) { aList << actDu << actHelp << actIntro; } m.addActions(aList); QAction* result = m.exec(QCursor::pos()); if(result == actRemove) { int rez = QMessageBox::question(this, tr("Remove Item"), tr("Are you sure?"), QMessageBox::Yes | QMessageBox::No); if(rez == QMessageBox::No) return; commands_->cd(JDModel::rootPath()); commands_->rm(model_->data(index, JDModel::RoleFullPath).toString()); } else if(result == actMake) { const QString name = QInputDialog::getText(this, tr("Input Dir Name"), QString()); if(!name.isEmpty()) commands_->mkDir(name); } else if(result == actGet) commands_->get(QString("#%1").arg(index.data(JDModel::RoleNumber).toInt())); else if(result == actHash) commands_->hash(QString("#%1").arg(index.data(JDModel::RoleNumber).toInt())); else if(result == actSend) { const QString name = QInputDialog::getText(this, tr("Input Full JID"), QString()); if(!name.isEmpty()) { commands_->send(name, QString("#%1").arg(index.data(JDModel::RoleNumber).toInt())); } } else if(result == actDu) commands_->du(); else if(result == actHelp) commands_->help(); else if(result == actIntro) commands_->intro(); else if(result == actLink) commands_->link(QString("#%1").arg(index.data(JDModel::RoleNumber).toInt())); else if(result == actRename) { const QString name = QInputDialog::getText(this, tr("Input New Name"), QString()); if(!name.isEmpty()) { commands_->mv(QString("#%1").arg(index.data(JDModel::RoleNumber).toInt()), name); } } else if(result == actPublic || result == actAlbum || result == actPrivate) { const QString path = result->text(); commands_->mv(QString("'//%1%%2/%3'").arg(yourJid_, model_->disk() ,index.data(JDModel::RoleFullPath).toString()), QString("'//%1%%2/%3'").arg(yourJid_, path ,index.data(JDModel::RoleName).toString())); } } void JDMainWin::moveItem(const QString &oldPath, const QString &newPath) { commands_->cd(JDModel::rootPath()); commands_->mv(oldPath, newPath); } plugins-1.5/generic/jabberdiskplugin/jd_mainwin.h000066400000000000000000000033011336777360500223010ustar00rootroot00000000000000/* * jd_mainwin.h - plugin * Copyright (C) 2011 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef JD_MAINWIN_H #define JD_MAINWIN_H class JDModel; #include "jd_commands.h" #include "ui_jd_mainwin.h" class JDMainWin : public QDialog { Q_OBJECT public: JDMainWin(const QString& name,const QString& jid, int acc, QWidget* p = 0); ~JDMainWin(); private slots: void incomingMessage(const QString& message, JDCommands::Command command); void refresh(); void doSend(); void outgoingMessage(const QString& message); void indexChanged(const QModelIndex& index); void indexContextMenu(const QModelIndex& index); void moveItem(const QString& oldPath, const QString& newPath); void clearLog(); private: void parse(QString message); void appendMessage(const QString& message, bool outgoing = true); void recursiveFind(const QString& dir); protected: private: Ui::JDMainWin ui_; JDModel* model_; JDCommands* commands_; QString currentDir_; bool refreshInProgres_; QString yourJid_; }; #endif // JD_MAINWIN_H plugins-1.5/generic/jabberdiskplugin/jd_mainwin.ui000066400000000000000000000115401336777360500224730ustar00rootroot00000000000000 JDMainWin 0 0 800 600 0 0 Qt::Horizontal 6 0 0 0 Qt::CustomContextMenu QAbstractItemView::DragDrop Qt::MoveAction true false false 0 0 Qt::ClickFocus Refresh Qt::Horizontal 40 20 Clear log 6 0 true 0 0 16777215 16777215 0 0 Send JDView QTreeView
jd_view.h
plugins-1.5/generic/jabberdiskplugin/jd_view.cpp000066400000000000000000000027001336777360500221460ustar00rootroot00000000000000/* * jd_view.cpp - plugin * Copyright (C) 2011 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "jd_view.h" #include JDView::JDView(QWidget* p) : QTreeView(p) { } JDView::~JDView() { } void JDView::currentChanged(const QModelIndex ¤t, const QModelIndex &previous) { QTreeView::currentChanged(current, previous); emit newIndex(current); } void JDView::mousePressEvent(QMouseEvent *e) { QTreeView::mousePressEvent(e); if(e->button() == Qt::RightButton) { emit contextMenu(currentIndex()); } } //void JDView::dragEnterEvent(QDragEnterEvent *event) //{ // if(event->mimeData()->hasFormat(JDItem::mimeType())) // event->acceptProposedAction(); //} // //void JDView::dropEvent(QDropEvent *event) //{ // QTreeView::dropEvent(event); //} plugins-1.5/generic/jabberdiskplugin/jd_view.h000066400000000000000000000023631336777360500216200ustar00rootroot00000000000000/* * jd_view.h - plugin * Copyright (C) 2011 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef JD_VIEW_H #define JD_VIEW_H #include class JDView : public QTreeView { Q_OBJECT public: JDView(QWidget *p = 0); ~JDView(); signals: void contextMenu(const QModelIndex&); void newIndex(const QModelIndex&); protected: void currentChanged(const QModelIndex ¤t, const QModelIndex &previous); void mousePressEvent(QMouseEvent *e); //void dragEnterEvent(QDragEnterEvent *event); //void dropEvent(QDropEvent *event); }; #endif // JD_VIEW_H plugins-1.5/generic/jabberdiskplugin/model.cpp000066400000000000000000000172171336777360500216300ustar00rootroot00000000000000/* * model.cpp - plugin * Copyright (C) 2011 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "model.h" #include #include #include //#include JDModel::JDModel(const QString &diskName, QObject *parent) : QAbstractItemModel(parent) , diskName_(diskName) #ifdef HAVE_QT5 , rootIndex_(createIndex(0, 0, static_cast(0))) #else , rootIndex_(createIndex(0, 0, 0)) #endif { } JDModel::~JDModel() { removeAll(); } Qt::ItemFlags JDModel::flags(const QModelIndex& index) const { Qt::ItemFlags f = QAbstractItemModel::flags(index); if (!index.isValid()) return f; f |= Qt::ItemIsSelectable | Qt::ItemIsEnabled; if(index.data(RoleType) == JDItem::File) f |= Qt::ItemIsDragEnabled; else f |= Qt::ItemIsDropEnabled; return f; } int JDModel::rowCount(const QModelIndex &parent) const { if(parent == QModelIndex()) { return 1; } int count = 0; foreach(const ProxyItem& i, items_) { if(i.parent == parent) ++count; } return count; } bool JDModel::hasChildren(const QModelIndex &parent) const { JDItem *i = (JDItem*)parent.internalPointer(); if(i) { if(i->type() == JDItem::File) return false; foreach(const ProxyItem& item, items_) { if(item.item->parent() == i) return true; } } return true; } QVariant JDModel::headerData(int /*section*/, Qt::Orientation /*orientation*/, int /*role*/) const { return QVariant(); } QModelIndex JDModel::index(int row, int column, const QModelIndex& parent) const { if(column != 0) return QModelIndex(); if(parent == QModelIndex()) { if(row == 0) return rootIndex(); else return QModelIndex(); } int c = 0; foreach(const ProxyItem& i, items_) { if(i.parent == parent) { if(row == c) return i.index; ++c; } } return QModelIndex(); } QModelIndex JDModel::parent(const QModelIndex& index) const { if(!index.isValid()) return QModelIndex(); else if(!index.internalPointer()) return QModelIndex(); foreach(const ProxyItem& i, items_) if(i.index == index) return i.parent; return QModelIndex(); } QModelIndex JDModel::indexForItem(JDItem *item) const { foreach(const ProxyItem& i, items_) if(i.item == item) return i.index; return QModelIndex(); } const QModelIndex JDModel::rootIndex() const { return rootIndex_; } const QString JDModel::disk() const { return diskName_.split("@").first(); } bool JDModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int /*row*/, int /*column*/, const QModelIndex &parent) { if(!parent.isValid()) return false; if(action != Qt::CopyAction && action != Qt::MoveAction) return false; if(!data->hasFormat(JDItem::mimeType())) return false; JDItem *p = 0; if(parent != rootIndex()) { foreach(const ProxyItem& i, items_) { if(i.index == parent) { p = i.item; break; } } } if(p && p->type() == JDItem::File) return false; JDItem* newItem = new JDItem(JDItem::File, p); QByteArray ba = data->data(JDItem::mimeType()); QDataStream in(&ba, QIODevice::ReadOnly); newItem->fromDataStream(&in); if(addItem(newItem)) { //В DataStream осталась только информация о полном пути //к старому элементу, и ее можно получить QString path; in >> path; emit moveItem(path, p ? p->fullPath() : rootPath()); } return true; } QMimeData* JDModel::mimeData(const QModelIndexList &indexes) const { if(indexes.isEmpty()) return 0; QMimeData *data = 0; QModelIndex i = indexes.first(); foreach(const ProxyItem& item, items_) { if(item.index == i) { data = item.item->mimeData(); break; } } return data; } Qt::DropActions JDModel::supportedDropActions() const { return Qt::MoveAction; } QStringList JDModel::mimeTypes() const { return QStringList(JDItem::mimeType()); } //bool JDModel::removeRow(int row, const QModelIndex &parent) //{ // if(!parent.isValid()) // return false; // // ProxyItem pi; // foreach(const ProxyItem& item, items_) { // if(item.parent == parent && item.index.row() == row) { // pi = item; // break; // } // } // if(pi.isNull()) // return false; // // emit layoutAboutToBeChanged(); // items_.removeAll(pi); // delete pi.item; // emit layoutChanged(); // // return true; //} QVariant JDModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); if(!index.internalPointer()) { if(role == Qt::DisplayRole) { return diskName_; } else if(role == RoleFullPath) return rootPath(); } else { JDItem* i = (JDItem*)index.internalPointer(); if(i) { if(role == Qt::DisplayRole) { QString text; if(i->type() == JDItem::Dir) text = i->name(); else text = QString("%1 - %2 [%3] - %4").arg(QString::number(i->number()), i->name(), i->size(), i->description()); return text; } else if(role == RoleName) return i->name(); else if(role == RoleSize) return i->size(); else if(role == RoleNumber) return i->number(); else if(role == RoleType) return i->type(); else if(role == Qt::DecorationRole) { if(i->type() == JDItem::Dir) return qApp->style()->standardIcon(QStyle::SP_DirIcon); else return qApp->style()->standardIcon(QStyle::SP_FileIcon); } else if(role == RoleFullPath) return i->fullPath(); else if(role == RoleParentPath) return i->parentPath(); } } return QVariant(); } bool JDModel::addItem(JDItem *i) { if(items_.contains(i)) return false; ProxyItem pi; pi.item = i; if(i->parent()) { foreach(const ProxyItem& item, items_) { if(item.item == i->parent()) { pi.parent = item.index; break; } } } else { pi.parent = rootIndex(); } int count = 0; foreach(const ProxyItem& item, items_) { if(item.item->parent() == i->parent()) ++count; } pi.index = createIndex(count, 0, i); items_.append(pi); emit layoutChanged(); return true; } void JDModel::clear() { beginResetModel(); removeAll(); endResetModel(); } void JDModel::removeAll() { // while(!items_.isEmpty()) // delete items_.takeFirst().item; items_.clear(); } JDItem* JDModel::findDirItem(const QString &path) const { if(!path.isEmpty()) { foreach(const ProxyItem i, items_) { if(i.item->type() != JDItem::Dir) continue; if(i.item->fullPath() == path) return i.item; } } return 0; } QStringList JDModel::dirs(const QString &path) const { QStringList dirs_; foreach(const ProxyItem& i, items_) { if(i.item->type() != JDItem::Dir) continue; if(i.item->parent()) { if(i.item->parent()->fullPath() == path) dirs_.append(i.item->name()); } else if(path.isEmpty()) { dirs_.append(i.item->name()); } } return dirs_; } void JDModel::addDir(const QString &curPath, const QString &name) { JDItem *i = new JDItem(JDItem::Dir, findDirItem(curPath)); i->setData(name); addItem(i); } void JDModel::addFile(const QString &curPath, const QString &name, const QString &size, const QString &descr, int number) { JDItem *i = new JDItem(JDItem::File, name, size, descr, number, findDirItem(curPath)); addItem(i); } plugins-1.5/generic/jabberdiskplugin/model.h000066400000000000000000000052561336777360500212750ustar00rootroot00000000000000/* * model.h - plugin * Copyright (C) 2011 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef MODEL_H #define MODEL_H #include "jd_item.h" class JDModel : public QAbstractItemModel { Q_OBJECT public: enum { RoleType = Qt::UserRole + 1, RoleName = Qt::UserRole + 2, RoleSize = Qt::UserRole + 3, RoleNumber = Qt::UserRole + 4, RoleFullPath = Qt::UserRole + 5, RoleParentPath = Qt::UserRole + 6 }; JDModel(const QString& diskName, QObject *parent = 0); ~JDModel(); int rowCount(const QModelIndex &parent = QModelIndex()) const; int columnCount(const QModelIndex &) const { return 1; }; bool hasChildren(const QModelIndex &parent = QModelIndex()) const; Qt::ItemFlags flags(const QModelIndex& index) const; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; QModelIndex index(int row, int column = 0, const QModelIndex& parent = QModelIndex()) const; QModelIndex parent(const QModelIndex& index) const; QModelIndex indexForItem(JDItem* item) const; QVariant data(const QModelIndex &index, int role) const; bool dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent); QMimeData *mimeData(const QModelIndexList &indexes) const; Qt::DropActions supportedDropActions() const; QStringList mimeTypes() const; //bool removeRow(int row, const QModelIndex &parent = QModelIndex()); QStringList dirs(const QString& path) const; void addFile(const QString& curPath, const QString& name, const QString& size, const QString& descr, int number); void addDir(const QString& curPath, const QString& name); const QModelIndex rootIndex() const; const QString disk() const; static const QString rootPath() { return "/"; }; void clear(); signals: void moveItem(const QString& oldPat, const QString& newPath); private: JDItem* findDirItem(const QString& name) const; bool addItem(JDItem *i); void removeAll(); private: ItemsList items_; QString diskName_; const QModelIndex rootIndex_; }; #endif plugins-1.5/generic/jabberdiskplugin/options.ui000066400000000000000000000045451336777360500220560ustar00rootroot00000000000000 Options 0 0 319 311 Form Add Delete Qt::Horizontal 0 20 Qt::Vertical 20 0 <a href="http://psi-plus.com/wiki/plugins#jabber_disk_plugin">Wiki (Online)</a> true plugins-1.5/generic/jabberdiskplugin/resources.qrc000066400000000000000000000001421336777360500225320ustar00rootroot00000000000000 jabberdisk.png plugins-1.5/generic/juickplugin/000077500000000000000000000000001336777360500170215ustar00rootroot00000000000000plugins-1.5/generic/juickplugin/CMakeLists.txt000066400000000000000000000042611336777360500215640ustar00rootroot00000000000000unset(_HDRS) unset(_UIS) unset(_SRCS) unset(_RSCS) unset(PLUGIN) set( PLUGIN juickplugin ) project(${PLUGIN}) cmake_minimum_required(VERSION 3.1.0) set( CMAKE_AUTOMOC TRUE ) IF( NOT WIN32 ) set( LIB_SUFFIX "" CACHE STRING "Define suffix of directory name (32/64)" ) set( PLUGINS_PATH "lib${LIB_SUFFIX}/psi-plus/plugins" CACHE STRING "Install suffix for plugins" ) ELSE() set( PLUGINS_PATH "psi-plus/plugins" CACHE STRING "Install suffix for plugins" ) ENDIF() option( USE_WEBENGINE "Use WebEngine support instead of Webkit" OFF ) find_package( Qt5 COMPONENTS Core REQUIRED ) if(${Qt5Core_VERSION} VERSION_GREATER 5.6.0) find_package( Qt5 COMPONENTS WebEngine QUIET ) if( Qt5WebEngine_FOUND ) set(USE_WEBENGINE ON) add_definitions( -DWEBENGINE=1 -DHAVE_WEBENGINE ) else() set(USE_WEBENGINE OFF) add_definitions( -DHAVE_WEBKIT ) endif() endif() add_definitions( -DQT_PLUGIN -DHAVE_QT5 ) include_directories( ${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} #$ ../../include . ) set( _HDRS ${PLUGIN}.h juickjidlist.h juickparser.h juickdownloader.h defines.h ) set( _SRCS ${PLUGIN}.cpp juickjidlist.cpp juickparser.cpp juickdownloader.cpp ) set( _UIS juickjidlist.ui settings.ui ) set( _RSCS resources.qrc ) find_package(Qt5 COMPONENTS Widgets Xml Network REQUIRED) set(QT_DEPLIBS Qt5::Widgets Qt5::Xml Qt5::Network ) if( USE_WEBENGINE ) find_package(Qt5 COMPONENTS WebEngine WebEngineWidgets REQUIRED) list(APPEND QT_DEPLIBS Qt5::WebEngine Qt5::WebEngineWidgets ) else() find_package(Qt5 COMPONENTS WebKit WebKitWidgets REQUIRED) list(APPEND QT_DEPLIBS Qt5::WebKit Qt5::WebKitWidgets ) endif() qt5_wrap_ui(UIS ${_UIS}) qt5_add_resources(RSCS ${_RSCS}) add_library( ${PLUGIN} MODULE ${_SRCS} ${UIS} ${RSCS} ) target_link_libraries( ${PLUGIN} ${QT_DEPLIBS} ) if( UNIX AND NOT( APPLE OR CYGWIN ) ) install( TARGETS ${PLUGIN} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} ) endif() if( WIN32 ) install( TARGETS ${PLUGIN} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} ) endif() plugins-1.5/generic/juickplugin/changelog.txt000066400000000000000000000261601336777360500215160ustar00rootroot000000000000002016-02-16 v0.11.7 * адаптация к изменениям в плагинных интерфейсах 2014-06-20 v0.11.6 * исправлен парсинг сущностей, с присоединенным одним символом по бокам 2014-05-21 v0.11.5 * исправлена загрузка аватаров + добавлена поддержка жуйковской разметки ссылок вида [текст][ссылка] 2013-08-21 v0.11.4 - taurus * изменение в интерфейсе плагинов 2013-08-13 v0.11.3 - taurus + иконка плагина 2012.05.23 v0.11.2 * исправлено деление на 0 2012.05.22 v0.11.1 * небольшие исправления 2012-05-14 v0.11.0 * большое количество исправлений кода, багфиксов и улучшений + при обновлении на новую версию, старый кэш аватаров очищается + добавлены таймстампы сообщений + улучшения для режима подмены ресурса на номер сообщения + улучшения алгоритма загрузки аватаров и фоток 2011-05-27 v0.10.6 * пересобрано с новым appHomeDir 2010-12-17 v0.10.5 * исправлены возможные утечки памяти 2010-12-05 v0.10.4 + добавлена возможность указать список джидов, для которых будет происходить обработка сообщений (экспериментально) 2010-11-10 v0.10.3 Dealer_WeARE * некоторые исправления 2010-11-08 ivan101 v0.10.2 * исправлена обработка превью 2010-11-08 v0.10.1 + теперь плагин умеет использовать настройки прокси для приложения - убраны настройки прокси из окна настроек плагина 2010-09-11 zet v0.9.17 * обновлена ссылка на wiki ( http://psi-plus.com/wiki/plugins#juick_plugin ) 2010-08-30 Dealer_WeARE v0.9.16 * переписан класс загрузки контента, что должно иправить работу серез прокси с аторизацией + добавлена возможность использовать прокси из настроек аккаунта 2010-08-25 Dealer_WeARE v0.9.15 * совместимость с последней версией Psi+ 2010-05-17 Dealer_WeARE v0.9.14 + добавлена информация о плагине 2010-05-04 zet v0.9.13 * исправлена ссылка на wiki 2010-03-02 Dealer_WeARE v0.9.12 + добавлена возможность в настройках плагина указать прокси-сервер, через который будет производиться загрузка аватар и изображений + добавлены настройки авторизации на прокси-сервере 2010-02-04 v0.9.10 * обновлена обработка рекомендаций 2009-12-06 v0.9.9 * опция замены id сообщений на ссылки в конференции juick@conference.jabber.ru вынесена в настройки * добавлена ссылка на wiki 2009-10-31 v0.9.8 * поддержка нового API juick 2009-10-28 v0.9.7 * исправлена обработка # в конференции juick@conference.jabber.ru 2009-10-27 rion v0.9.6 * proper link encoding 2009-10-25 rion v0.9.5 * and again avatars with wk * juick: ecncode : 2009-10-24 v0.9.4 * превью фотографий не сохраняются на жёсткий диск * исправлена проблема с отображением аватары при обновлении кеша, необходимо произвести очистку кэша * выравнивание аватары по высоте, в сборке с webkit * исправлено отображение постов с медиа 2009-10-23 rion v0.9.3 * try to fix show avatars in webkit 2009-10-17 v0.9.2 * исправлена xmpp-ссылка 'U' в ответах * добавлена xmpp-ссылка '+' в ответы * исправлена обработка последних 10 сообщений с тегом * кликабельное фото 2009-10-16 v0.9.1 * поддержка webkit * удалены xmpp-сылки '!' из ответов 2009-10-16 v0.9.0 * минимальная поддержка webkit — в juickplugin.pro расскоментировать DEFINES += WEBKIT 2009-10-14 v0.8.5 * исправлена ошибка открытия нового таба с неправильным ресурсом * исправлена обработка Last popular messages * добавлена xmpp-ссылка '+' в "Last popular messages" и в "Last messages" * замена в приходящих сообщениях, в конференции juick@conference.jabber.ru, id сообщений на http-ссылки на эти сообщения 2009-09-30 v0.8.4 * обработка *tune: выделение полужирным * поддержка рекомендаций 2009-09-22 v0.8.2 * обработка *geo: выделение полужирным * совместимость с qt 4.4 2009-09-22 v0.8.1 * добавлены xmpp-ссылки '!' для вставки сообщений вида ! #123456 * добавлена кнопка очистки кэша аватарок * обработка *mood: выделение полужирным и замена настроения на иконку 2009-09-21 v0.8.0 * добавлена поддержка транспорта j2j * аватары в сообщениях бота jubo * сообщения, не относящиеся к конкретному треду в режиме "use message is as resource", приходят в активный таб 2009-08-24 v0.7.1 * изменён шаблон определения ника * изменён шаблон определения номера сообщения 2009-08-21 v0.7.0 * добавлена поддержка аватар * добавлена xmpp-ссылка 'D' для удаления поста/комментария * в режиме "use message is as resource" ответ на команду "HELP", сообщение "Subscribed" и прочие ответы от бота приходят в активный таб 2009-08-06 v0.6.2 * добавлены xmpp-ссылки '+' для вставки сообщений вида #123456+ * исправлены мелкие недочёты 2009-08-04 v0.6.0 * добавлена поддержка показа превью фотографий 2009-08-02 v0.5.7 * добавлена поддержка глобального цвета ссылок 2009-08-02 v0.5.6 * добавлены xmpp-ссылки 'S' и возможность изменения оформления цвета http-ссылок на сообщения в сообщениях от бота jubo@nologin.ru 2009-07-21 v0.5.5 * добавлены дополнительные xmpp-ссылки рядом с номером сообщения/комментария 'S' и 'U' для подписки и отписки на сообщения соответственно 2009-07-31 v0.5.2 * исправлен баг открытия нового таба при клике на номер комментария в режиме "use message id as resource" 2009-07-30 v0.5.1 * добавлена поддержка изменения стиля оформления ссылок в "LAST" и при просмотре отдельного сообщения * исправлен баг с альтернативным текстом в сообщениях типа "Reply posted" 2009-07-29 v0.5.0 * добавлена возможность изменения стиля оформления http-ссылок на сообщение, в сообщениях и комментарях * добавлены всплывающие подсказки к xmpp-ссылкам * изменён стиль комментария * при включенной опции "use message id as resource" просмотр всего треда сообщений в отдельном табе * при клике на @username в информации о пользователе в поле ввода вставляется "S @username" 2009-07-27 v0.4.5 * добавлена опция "use message id as resource": сообщения и комментарии приходят в отдельный таб с соответствующим ресурсом 2009-07-26 v0.4.1 * пофикшен баг с определением ника 2009-07-25 v0.4.0 * при клике на @username для группы сообщений "Top 10 personal blogs" в поле ввода добавляется "S @username" * при клике на номер сообщения в тексте сообщения в поле ввода добавляется "#123456+" 2009-07-25 v0.3.3 * бот jubo переехал на jubo@nologin.ru 2009-07-23 v0.3.2 * добавлена поддержка бота jubo@jabber.ru * более правильное выделение жирным/курсивом/подчёркиванием словосочетаний 2009-07-20 v0.3.1 * команда 'HELP' не обрабатывается * уменьшен margin в оформлении цитат * удалён "лишний" перевод строки перед номером сообщения и ссылкой на него 2009-07-19 v0.3.0 * поддержка выделения жирным/курсивом/подчёркиванием словосочетаний * при клике @username в пришедшем от него PM в поле ввода добавляется "PM @username" 2009-07-18 v0.2.0 * добавлена возможность изменения стиля оформления цитат * более правильное определение ников * правильное оформление "Top 20 tags" 2009-07-10 v0.1.2 * замена ключевых слов на ссылки вне зависимости от типа сообщения 2009-07-08 v0.1.1 * добавлена поддержка ответов (reply) * исправлен баг с настройками 2009-07-07 v0.1.0 Базовый функционал: * замена ников, тегов и номеров сообщений на xmmp-ссылки в сообщениях, начинающихся с символа "@" * возможность изменения стиля оформления xmpp-ссылок plugins-1.5/generic/juickplugin/defines.h000066400000000000000000000034051336777360500206110ustar00rootroot00000000000000/* * defines.h - plugin * Copyright (C) 2012 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef DEFINES_H #define DEFINES_H #define constuserColor "usercolor" #define consttagColor "tagcolor" #define constmsgColor "idcolor" #define constQcolor "quotecolor" #define constLcolor "linkcolor" #define constUbold "userbold" #define constTbold "tagbold" #define constMbold "idbold" #define constQbold "quotebold" #define constLbold "linkbold" #define constUitalic "useritalic" #define constTitalic "tagitalic" #define constMitalic "iditalic" #define constQitalic "quoteitalic" #define constLitalic "linkitalic" #define constUunderline "userunderline" #define constTunderline "tagunderline" #define constMunderline "idunderline" #define constQunderline "quoteunderline" #define constLunderline "linkunderline" #define constIdAsResource "idAsResource" #define constShowPhoto "showphoto" #define constShowAvatars "showavatars" #define constWorkInGroupchat "workingroupchat" #define constVersionOpt "version" #define constVersion "0.11.7" #define constPluginName "Juick Plugin" #endif // DEFINES_H plugins-1.5/generic/juickplugin/juick.png000066400000000000000000000026441336777360500206420ustar00rootroot00000000000000PNG  IHDRaiCCPICC ProfilexTkA6n"Zkx"IYhE6bk Ed3In6&*Ezd/JZE(ޫ(b-nL~7}ov r4 Ril|Bj A4%UN$As{z[V{wwҶ@G*q Y<ߡ)t9Nyx+=Y"|@5-MS%@H8qR>׋infObN~N>! ?F?aĆ=5`5_M'Tq. VJp8dasZHOLn}&wVQygE0  HPEaP@<14r?#{2u$jtbDA{6=Q<("qCA*Oy\V;噹sM^|vWGyz?W15s-_̗)UKuZ17ߟl;=..s7VgjHUO^gc)1&v!.K `m)m$``/]?[xF QT*d4o(/lșmSqens}nk~8X<R5 vz)Ӗ9R,bRPCRR%eKUbvؙn9BħJeRR~NցoEx pHYs  \IDAT8MRMkAlr"<}mkIQވOXKh#Cky޸l֠3K1`G5 Kѡ{Y|mv@Bxnӝ i_y 9آ05` >`FJ11}RM,˲҆ E2@a>c*ز,Mgt q RRK@0u%7w'D!l"9ċ5ڛ^+d'hGl#&-]~LazBv*\X\0Yqp>r]s}>AZtZݤWL˝N?}Vr/5 jYbLE}<}ڤ5U #IENDB`plugins-1.5/generic/juickplugin/juickdownloader.cpp000066400000000000000000000071031336777360500227120ustar00rootroot00000000000000/* * juickdownloader.cpp - plugin * Copyright (C) 2012 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "juickdownloader.h" #include "applicationinfoaccessinghost.h" #include "defines.h" #include #include #include #include #include #include const int DOWNLOAD_TIMEOUT = 60000; static void save(const QString &path, const QByteArray &img) { QFile file(path); if(file.open(QIODevice::WriteOnly | QIODevice::Truncate)) { file.write(img); } else QMessageBox::warning(0, QObject::tr("Warning"), QObject::tr("Cannot write to file %1:\n%2.") .arg(file.fileName()) .arg(file.errorString())); } JuickDownloader::JuickDownloader(ApplicationInfoAccessingHost *host, QObject *p) : QObject(p) , inProgress_(false) , manager_(new QNetworkAccessManager(this)) , appInfo_(host) , waitTimer_(new QTimer(this)) { connect(manager_, SIGNAL(finished(QNetworkReply*)), SLOT(requestFinished(QNetworkReply*))); waitTimer_->setSingleShot(true); waitTimer_->setInterval(1000); connect(waitTimer_, SIGNAL(timeout()), SLOT(timeOut())); // qRegisterMetaType("JuickDownloadItem"); } void JuickDownloader::get(const JuickDownloadItem &item) { if(waitTimer_->isActive()) waitTimer_->stop(); items_.enqueue(item); Proxy prx = appInfo_->getProxyFor(constPluginName); setProxyHostPort(prx.host, prx.port, prx.user, prx.pass, prx.type); if(!inProgress_) { peekNext(); } } void JuickDownloader::setProxyHostPort(const QString& host, int port, const QString& username, const QString& pass, const QString& type) { QNetworkProxy prx; if(!host.isEmpty()) { prx.setType(QNetworkProxy::HttpCachingProxy); if(type == "socks") prx.setType(QNetworkProxy::Socks5Proxy); prx.setPort(port); prx.setHostName(host); if(!username.isEmpty()) { prx.setUser(username); prx.setPassword(pass); } } manager_->setProxy(prx); } void JuickDownloader::peekNext() { if(items_.isEmpty()) { inProgress_ = false; waitTimer_->start(); } else { inProgress_ = true; JuickDownloadItem it = items_.dequeue(); QNetworkRequest request; request.setUrl(QUrl(it.url)); request.setRawHeader("User-Agent", "Juick Plugin (Psi+)"); QNetworkReply *reply = manager_->get(request); QVariant v; v.setValue(it); reply->setProperty("jdi", v); } } void JuickDownloader::requestFinished(QNetworkReply *reply) { if (reply->error() == QNetworkReply::NoError ) { QByteArray ba = reply->readAll(); JuickDownloadItem it = reply->property("jdi").value(); dataReady(ba, it); } else { qDebug() << reply->errorString(); } reply->deleteLater(); peekNext(); } void JuickDownloader::timeOut() { emit finished(urls_); urls_.clear(); } void JuickDownloader::dataReady(const QByteArray &ba, const JuickDownloadItem& it) { urls_.append(QUrl::fromLocalFile(it.path).toEncoded()); save(it.path, ba); } plugins-1.5/generic/juickplugin/juickdownloader.h000066400000000000000000000037411336777360500223630ustar00rootroot00000000000000/* * juickdownloader.h - plugin * Copyright (C) 2012 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef JUICKDOWNLOADER_H #define JUICKDOWNLOADER_H #include #include class QNetworkAccessManager; class QNetworkReply; class ApplicationInfoAccessingHost; class QTimer; struct JuickDownloadItem { JuickDownloadItem() {} //need for Q_DECLARE_METATYPE JuickDownloadItem(const QString& _path, const QString& _url) : path(_path), url(_url) {} QString path; QString url; }; Q_DECLARE_METATYPE(JuickDownloadItem) class JuickDownloader : public QObject { Q_OBJECT public: JuickDownloader(ApplicationInfoAccessingHost * host, QObject *p = 0); ~JuickDownloader() {} void get(const JuickDownloadItem& item); private slots: void requestFinished(QNetworkReply *reply); void timeOut(); signals: void finished(const QList& urls); private: void dataReady(const QByteArray& ba, const JuickDownloadItem &it); void setProxyHostPort(const QString& host, int port, const QString& username = "", const QString& pass = "", const QString& type = "http"); void peekNext(); private: bool inProgress_; QNetworkAccessManager *manager_; ApplicationInfoAccessingHost *appInfo_; QQueue items_; QList urls_; QTimer *waitTimer_; }; #endif plugins-1.5/generic/juickplugin/juickjidlist.cpp000066400000000000000000000040631336777360500222200ustar00rootroot00000000000000/* * juickjidlist.cpp - plugin * Copyright (C) 2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "juickjidlist.h" #include "ui_juickjidlist.h" #include JuickJidList::JuickJidList(const QStringList &jids, QWidget *p) : QDialog(p) , ui_(new Ui::JuickJidDialog) , jidList_(jids) { ui_->setupUi(this); setAttribute(Qt::WA_DeleteOnClose); ui_->listWidget->addItems(jidList_); ui_->pb_del->setEnabled(false); connect(ui_->pb_add, SIGNAL(released()), SLOT(addPressed())); connect(ui_->pb_del, SIGNAL(released()), SLOT(delPressed())); connect(ui_->pb_ok, SIGNAL(released()), SLOT(okPressed())); connect(ui_->listWidget, SIGNAL(clicked(QModelIndex)), SLOT(enableButtons())); } JuickJidList::~JuickJidList() { delete ui_; } void JuickJidList::enableButtons() { ui_->pb_del->setEnabled(!ui_->listWidget->selectedItems().isEmpty()); } void JuickJidList::addPressed() { bool ok; QString jid = QInputDialog::getText(this, tr("Input JID"),"",QLineEdit::Normal,"", &ok); if(ok) { jidList_.append(jid); ui_->listWidget->addItem(jid); } } void JuickJidList::delPressed() { QList list = ui_->listWidget->selectedItems(); foreach(QListWidgetItem *i, list) { QString jid = i->text(); jidList_.removeAll(jid); ui_->listWidget->removeItemWidget(i); delete i; } } void JuickJidList::okPressed() { emit listUpdated(jidList_); close(); } plugins-1.5/generic/juickplugin/juickjidlist.h000066400000000000000000000023671336777360500216720ustar00rootroot00000000000000/* * juickjidlist.h - plugin * Copyright (C) 2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef JUICKJIDLIST_H #define JUICKJIDLIST_H #include namespace Ui { class JuickJidDialog; } class JuickJidList : public QDialog { Q_OBJECT public: JuickJidList(const QStringList& jids, QWidget *p = 0); ~JuickJidList(); signals: void listUpdated(const QStringList&); private slots: void addPressed(); void delPressed(); void okPressed(); void enableButtons(); private: Ui::JuickJidDialog *ui_; QStringList jidList_; }; #endif // JUICKJIDLIST_H plugins-1.5/generic/juickplugin/juickjidlist.ui000066400000000000000000000030111336777360500220430ustar00rootroot00000000000000 JuickJidDialog Qt::WindowModal 0 0 367 210 Set JIDs of Juick Bot Add Delete Qt::Vertical 20 40 OK plugins-1.5/generic/juickplugin/juickparser.cpp000066400000000000000000000240741336777360500220560ustar00rootroot00000000000000/* * JuickParser - plugin * Copyright (C) 2012 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include #include #include "juickparser.h" static const QString juickLink("http://juick.com/%1"); class JuickParser::Private { public: Private() : tagRx ("^\\s*(?!\\*\\S+\\*)(\\*\\S+)") , pmRx ("^\\nPrivate message from (@.+):(.*)$") , postRx ("\\n@(\\S*):( \\*[^\\n]*){0,1}\\n(.*)\\n\\n(#\\d+)\\s(http://\\S*)\\n$") , replyRx ("\\nReply by @(.*):\\n>(.{,50})\\n\\n(.*)\\n\\n(#\\d+/\\d+)\\s(http://\\S*)\\n$") // , regx ("(\\s+)(#\\d+(?:\\S+)|#\\d+/\\d+(?:\\S+)|@\\S+|_[^\\n]+_|\\*[^\\n]+\\*|/[^\\n]+/|http://\\S+|ftp://\\S+|https://\\S+){1}(\\s+)") , rpostRx ("\\nReply posted.\\n(#.*)\\s(http://\\S*)\\n$") , threadRx ("^\\n@(\\S*):( \\*[^\\n]*){0,1}\\n(.*)\\n(#\\d+)\\s(http://juick.com/\\S+)\\n(.*)") , userRx ("^\\nBlog: http://.*") , yourMesRecRx ("\\n@(\\S*)( recommended your post )(#\\d+)\\.\\s+(http://juick.com/\\S+).*") , singleMsgRx ("^\\n@(\\S+):( \\*[^\\n]*){0,1}\\n(.*)\\n(#\\d+) (\\(.*;{0,1}\\s*(?:\\d+ repl(?:ies|y)){0,1}\\) ){0,1}(http://juick.com/\\S+)\\n$") , lastMsgRx ("^\\n(Last (?:popular ){0,1}messages:)(.*)") , juboRx ("^\\n([^\\n]*)\\n@(\\S*):( [^\\n]*){0,1}\\n(.*)\\n(#\\d+)\\s(http://juick.com/\\S+)\\n$") , msgPostRx ("\\nNew message posted.\\n(#.*)\\s(http://\\S*)\\n$") // , delMsgRx ("^\\nMessage #\\d+ deleted.\\n$") // , delReplyRx ("^\\nReply #\\d+/\\d+ deleted.\\n$") // , idRx ("(#\\d+)(/\\d+){0,1}(\\S+){0,1}") // , nickRx ("(@[\\w\\-\\.@\\|]*)(\\b.*)") , recomendRx ("^\\nRecommended by @(\\S+):\\s+@(\\S+):( \\*[^\\n]+){0,1}\\n+(.*)\\s+(#\\d+) (\\(\\d+ repl(?:ies|y)\\) ){0,1}(http://\\S+)\\s+$") , topTag ("Top 20 tags:") { pmRx.setMinimal(true); replyRx.setMinimal(true); // regx.setMinimal(true); postRx.setMinimal(true); singleMsgRx.setMinimal(true); juboRx.setMinimal(true); } QRegExp tagRx, pmRx, postRx,replyRx,/*regx,*/rpostRx,threadRx, userRx, yourMesRecRx; QRegExp singleMsgRx,lastMsgRx,juboRx,msgPostRx,/*delMsgRx,delReplyRx,idRx,nickRx,*/recomendRx; const QString topTag; }; JuickParser::JuickParser(QDomElement *elem) : elem_(elem) { if(!d) d = new Private(); juickElement_ = findElement("juick", "http://juick.com/message"); userElement_ = juickElement_.firstChildElement("user"); QString msg = "\n" + originMessage() + "\n"; msg.replace(">",">"); msg.replace("<","<"); //Порядок обработки имеет значение if (d->recomendRx.indexIn(msg) != -1) { type_ = JM_Recomendation; infoText_ = QObject::tr("Recommended by @%1").arg(d->recomendRx.cap(1)); JuickMessage m(d->recomendRx.cap(2), d->recomendRx.cap(5), d->recomendRx.cap(3).trimmed().split(" ", QString::SkipEmptyParts), d->recomendRx.cap(4), d->recomendRx.cap(7), d->recomendRx.cap(6)); messages_.append(m); } else if (d->pmRx.indexIn(msg) != -1) { type_ = JM_Private; } else if (d->userRx.indexIn(msg) != -1) { type_ = JM_User_Info; } else if(d->lastMsgRx.indexIn(msg) != -1) { type_ = JM_10_Messages; infoText_ = d->lastMsgRx.cap(1); QString mes = d->lastMsgRx.cap(2); while(d->singleMsgRx.indexIn(mes) != -1) { JuickMessage m(d->singleMsgRx.cap(1), d->singleMsgRx.cap(4), d->singleMsgRx.cap(2).trimmed().split(" ", QString::SkipEmptyParts), d->singleMsgRx.cap(3), d->singleMsgRx.cap(6), d->singleMsgRx.cap(5)); messages_.append(m); mes = mes.right(mes.size() - d->singleMsgRx.matchedLength()); } } else if (msg.indexOf(d->topTag) != -1) { type_ = JM_Tags_Top; infoText_ = d->topTag; QStringList tags; msg = msg.right(msg.size() - d->topTag.size() - 1); while (d->tagRx.indexIn(msg, 0) != -1) { tags.append(d->tagRx.cap(1)); msg = msg.right(msg.size() - d->tagRx.matchedLength()); } JuickMessage m(QString(), QString(), tags, QString(), QString(), QString()); messages_.append(m); } else if (d->postRx.indexIn(msg) != -1) { type_ = JM_Message; infoText_ = QString(); JuickMessage m(d->postRx.cap(1), d->postRx.cap(4), d->postRx.cap(2).trimmed().split(" ", QString::SkipEmptyParts), d->postRx.cap(3), d->postRx.cap(5), QString()); messages_.append(m); } else if (d->replyRx.indexIn(msg) != -1) { type_ = JM_Reply; infoText_ = d->replyRx.cap(2); JuickMessage m(d->replyRx.cap(1), d->replyRx.cap(4), QStringList(), d->replyRx.cap(3), d->replyRx.cap(5), QString()); messages_.append(m); } else if (d->rpostRx.indexIn(msg) != -1) { type_ = JM_Reply_Posted; infoText_ = QObject::tr("Reply posted."); JuickMessage m(QString(), d->rpostRx.cap(1), QStringList(), QString(), d->rpostRx.cap(2), QString()); messages_.append(m); } else if (d->msgPostRx.indexIn(msg) != -1) { type_ = JM_Message_Posted; infoText_ = QObject::tr("New message posted."); JuickMessage m(QString(), d->msgPostRx.cap(1), QStringList(), QString(), d->msgPostRx.cap(2), QString()); messages_.append(m); } else if (d->threadRx.indexIn(msg) != -1) { type_ = JM_All_Messages; infoText_ = QString(); JuickMessage m(d->threadRx.cap(1), d->threadRx.cap(4), d->threadRx.cap(2).trimmed().split(" ", QString::SkipEmptyParts), d->threadRx.cap(3), d->threadRx.cap(5), msg.right(msg.size() - d->threadRx.matchedLength() + d->threadRx.cap(6).length())); messages_.append(m); } else if (d->singleMsgRx.indexIn(msg) != -1) { type_ = JM_Post_View; infoText_ = QString(); JuickMessage m(d->singleMsgRx.cap(1), d->singleMsgRx.cap(4), d->singleMsgRx.cap(2).trimmed().split(" ", QString::SkipEmptyParts), d->singleMsgRx.cap(3), d->singleMsgRx.cap(6), d->singleMsgRx.cap(5)); messages_.append(m); } else if (d->juboRx.indexIn(msg) != -1) { type_ = JM_Jubo; JuickMessage m(d->juboRx.cap(2), d->juboRx.cap(5), d->juboRx.cap(3).trimmed().split(" ", QString::SkipEmptyParts), d->juboRx.cap(4), d->juboRx.cap(6), QString()); messages_.append(m); infoText_ = d->juboRx.cap(1); } else if(d->yourMesRecRx.indexIn(msg) != -1) { type_ = JM_Your_Post_Recommended; JuickMessage m(d->yourMesRecRx.cap(1), d->yourMesRecRx.cap(3), QStringList(), d->yourMesRecRx.cap(2), d->yourMesRecRx.cap(4), QObject::tr(" recommended your post ")); messages_.append(m); } else { type_ = JM_Other; } // //mood // QRegExp moodRx("\\*mood:\\s(\\S*)\\s(.*)\\n(.*)"); // //geo // QRegExp geoRx("\\*geo:\\s(.*)\\n(.*)"); // //tune // QRegExp tuneRx("\\*tune:\\s(.*)\\n(.*)"); // if (moodRx.indexIn(recomendRx.cap(4)) != -1){ // body.appendChild(doc.createElement("br")); // QDomElement bold = doc.createElement("b"); // bold.appendChild(doc.createTextNode("mood: ")); // body.appendChild(bold); // QDomElement img = doc.createElement("icon"); // img.setAttribute("name","mood/"+moodRx.cap(1).left(moodRx.cap(1).size()-1).toLower()); // img.setAttribute("text",moodRx.cap(1)); // body.appendChild(img); // body.appendChild(doc.createTextNode(" "+moodRx.cap(2))); // msg = " " + moodRx.cap(3) + " "; // } else if(geoRx.indexIn(recomendRx.cap(4)) != -1) { // body.appendChild(doc.createElement("br")); // QDomElement bold = doc.createElement("b"); // bold.appendChild(doc.createTextNode("geo: "+ geoRx.cap(1) )); // body.appendChild(bold); // msg = " " + geoRx.cap(2) + " "; // } else if(tuneRx.indexIn(recomendRx.cap(4)) != -1) { // body.appendChild(doc.createElement("br")); // QDomElement bold = doc.createElement("b"); // bold.appendChild(doc.createTextNode("tune: "+ tuneRx.cap(1) )); // body.appendChild(bold); // msg = " " + tuneRx.cap(2) + " "; // } } void JuickParser::reset() { delete d; d = 0; } bool JuickParser::hasJuckNamespace() const { return !juickElement_.isNull(); } QString JuickParser::avatarLink() const { QString ava; if(!userElement_.isNull()) { ava = "/as/"+userElement_.attribute("uid")+".png"; } return ava; } QString JuickParser::photoLink() const { QString photo; QDomElement x = findElement("x", "jabber:x:oob"); if(!x.isNull()) { QDomElement url = x.firstChildElement("url"); if(!url.isNull()) { photo = url.text().trimmed(); if(!photo.endsWith(".jpg", Qt::CaseInsensitive) && !photo.endsWith(".png", Qt::CaseInsensitive)) photo.clear(); } } return photo; } QString JuickParser::nick() const { QString nick; if(!userElement_.isNull()) { nick = userElement_.attribute("uname"); } return nick; } QString JuickParser::originMessage() const { return elem_->firstChildElement("body").text(); } QString JuickParser::timeStamp() const { QString ts; if(hasJuckNamespace()) { ts = juickElement_.attribute("ts"); if(!ts.isEmpty()) { QDateTime dt = QDateTime::fromString(ts, "yyyy-MM-dd hh:mm:ss"); static qlonglong offset = -1; if(offset == -1) { QDateTime cur = QDateTime::currentDateTime(); QDateTime utc = cur.toUTC(); utc.setTimeSpec(Qt::LocalTime); offset = utc.secsTo(cur); } dt = dt.addSecs(offset); ts = dt.toString("yyyy-MM-dd hh:mm:ss"); } } return ts; } QDomElement JuickParser::findElement(const QString &tagName, const QString &xmlns) const { if(!elem_) return QDomElement(); QDomNode e = elem_->firstChild(); while(!e.isNull()) { if(e.isElement()) { QDomElement el = e.toElement(); if(el.tagName() == tagName && el.attribute("xmlns") == xmlns) return el; } e = e.nextSibling(); } return QDomElement(); } JuickParser::Private* JuickParser::d = 0; plugins-1.5/generic/juickplugin/juickparser.h000066400000000000000000000044761336777360500215270ustar00rootroot00000000000000/* * JuickParser - plugin * Copyright (C) 2012 Kravtsov Nikolai, Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef JUICKPARSER_H #define JUICKPARSER_H #include #include struct JuickMessage { JuickMessage(const QString& _unick, const QString& _mes, const QStringList& _tags, const QString& _body, const QString& _link, const QString& info) : unick(_unick), messageId(_mes), tags(_tags), body(_body), link(_link), infoText(info) { } QString unick; QString messageId; QStringList tags; QString body; QString link; QString infoText; }; typedef QList JuickMessages; class JuickParser { public: JuickParser(QDomElement* elem); virtual ~JuickParser() {} static void reset(); enum JMType { JM_Other = 0, JM_10_Messages, JM_Tags_Top, JM_Recomendation, JM_Message, JM_Message_Posted, JM_Reply, JM_Reply_Posted, JM_All_Messages, JM_Post_View, JM_Jubo, JM_Private, JM_User_Info, JM_Your_Post_Recommended }; bool hasJuckNamespace() const; QString avatarLink() const; QString photoLink() const; QString nick() const; QString infoText() const { return infoText_; } JMType type() const { return type_; } JuickMessages getMessages() const { return messages_; } QString originMessage() const; QString timeStamp() const; QDomElement findElement(const QString& tagName, const QString& xmlns) const; private: JuickParser() {} Q_DISABLE_COPY(JuickParser) private: QDomElement* elem_; QDomElement juickElement_; QDomElement userElement_; JMType type_; QString infoText_; JuickMessages messages_; class Private; static Private* d; }; #endif // JUICKPARSER_H plugins-1.5/generic/juickplugin/juickplugin.cpp000066400000000000000000001201141336777360500220500ustar00rootroot00000000000000/* * juickplugin.cpp - plugin * Copyright (C) 2009-2012 Kravtsov Nikolai, Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include #include #include #include #ifdef HAVE_WEBKIT #include #include #include #endif #ifdef HAVE_WEBENGINE #include #include #endif #include "optionaccessinghost.h" #include "activetabaccessinghost.h" #include "applicationinfoaccessinghost.h" #include "juickplugin.h" #include "juickdownloader.h" #include "juickjidlist.h" #include "juickparser.h" #include "defines.h" static const QString showAllmsgString(QObject::tr("Show all messages")); static const QString replyMsgString(QObject::tr("Reply")); static const QString userInfoString(QObject::tr("Show %1's info and last 10 messages")); static const QString subscribeString(QObject::tr("Subscribe")); static const QString showLastTenString(QObject::tr("Show last 10 messages with tag %1")); static const QString unsubscribeString(QObject::tr("Unsubscribe")); static const QString juick("juick@juick.com"); static const QString jubo("jubo@nologin.ru"); //static const QRegExp delMsgRx("^\\nMessage #\\d+ deleted.\\n$"); //static const QRegExp delReplyRx("^\\nReply #\\d+/\\d+ deleted.\\n$"); static const QString chatPlusAction = "xmpp:%1?message;type=chat;body=%2+"; static const QString chatAction = "xmpp:%1%3?message;type=chat;body=%2"; static const int avatarsUpdateInterval = 10; //static void debugElement(const QDomElement& e) //{ // QString out; // QTextStream str(&out); // e.save(str, 3); // qDebug() << out; //} static void nl2br(QDomElement *body,QDomDocument* e, const QString& msg) { foreach (const QString& str, msg.split("\n")) { body->appendChild(e->createTextNode(str)); body->appendChild(e->createElement("br")); } body->removeChild(body->lastChild()); } //----------------------------- //------JuickPlugin------------ //----------------------------- #ifndef HAVE_QT5 Q_EXPORT_PLUGIN(JuickPlugin) #endif JuickPlugin::JuickPlugin() : enabled(false) , psiOptions(0), activeTab(0), applicationInfo(0) , userColor(0, 85, 255), tagColor(131, 145, 145), msgColor(87, 165, 87), quoteColor(187, 187, 187), lineColor(0, 0, 255) , userBold(true), tagBold(false), msgBold(false), quoteBold(false), lineBold(false) , userItalic(false), tagItalic(true), msgItalic(false), quoteItalic(false), lineItalic(false) , userUnderline(false), tagUnderline(false), msgUnderline(true), quoteUnderline(false), lineUnderline(true) , tagRx ("^\\s*(?!\\*\\S+\\*)(\\*\\S+)") , regx ("(\\s+\\S?)(#\\d+/{0,1}\\d*(?:\\S+)|@\\S+|_[^\\n]+_|\\*[^\\n]+\\*|/[^\\n]+/|http://\\S+|ftp://\\S+|https://\\S+|\\[[^\\]]+\\]\\[[^\\]]+\\]){1}(\\S?\\s+)") , idRx ("(#\\d+)(/\\d+){0,1}(\\S+){0,1}") , nickRx("(@[\\w\\-\\.@\\|]*)(\\b.*)") , linkRx("\\[([^\\]]+)\\]\\[([^\\]]+)\\]") , idAsResource(false), showPhoto(false), showAvatars(true), workInGroupChat(false) , downloader_(0) { regx.setMinimal(true); jidList_ = QStringList() << juick << jubo; } QString JuickPlugin::name() const { return constPluginName; } QString JuickPlugin::shortName() const { return "juick"; } QString JuickPlugin::version() const { return constVersion; } QWidget* JuickPlugin::options() { if (!enabled) { return 0; } optionsWid = new QWidget(); ui_.setupUi(optionsWid); QSignalMapper *sm = new QSignalMapper(optionsWid); QList list = QList() << ui_.tb_link << ui_.tb_message << ui_.tb_name << ui_.tb_quote << ui_.tb_tag; foreach(QToolButton* b, list) { sm->setMapping(b, b); connect(b, SIGNAL(clicked()), sm, SLOT(map())); } restoreOptions(); connect(sm, SIGNAL(mapped(QWidget*)), SLOT(chooseColor(QWidget*))); connect(ui_.pb_clearCache, SIGNAL(released()), SLOT(clearCache())); connect(ui_.pb_editJids, SIGNAL(released()), SLOT(requestJidList())); return optionsWid; } bool JuickPlugin::enable() { enabled = true; QVariant v = psiOptions->getPluginOption(constVersionOpt, QVariant::Invalid); //Проверяем, обновился ли плагин if(!v.isValid() || v.toString() != constVersion) { QDir dir(applicationInfo->appHomeDir(ApplicationInfoAccessingHost::CacheLocation)+"/avatars"); foreach(const QString& f, QDir(dir.path()+"/juick/per").entryList(QDir::Files)) { QFile::remove(dir.path()+"/juick/per/"+f); } foreach(const QString& f, QDir(dir.path()+"/juick").entryList(QDir::Files)) { QFile::remove(dir.path()+"/juick/"+f); } dir.rmdir("juick/per"); psiOptions->setPluginOption(constVersionOpt, constVersion); } userColor = psiOptions->getPluginOption(constuserColor, userColor).toString(); tagColor = psiOptions->getPluginOption(consttagColor, tagColor).toString(); msgColor = psiOptions->getPluginOption(constmsgColor, msgColor).toString(); quoteColor = psiOptions->getPluginOption(constQcolor, quoteColor).toString(); lineColor = psiOptions->getPluginOption(constLcolor, lineColor).toString(); //bold userBold = psiOptions->getPluginOption(constUbold, userBold).toBool(); tagBold = psiOptions->getPluginOption(constTbold, tagBold).toBool(); msgBold = psiOptions->getPluginOption(constMbold, msgBold).toBool(); quoteBold = psiOptions->getPluginOption(constQbold, quoteBold).toBool(); lineBold = psiOptions->getPluginOption(constLbold, lineBold).toBool(); //italic userItalic = psiOptions->getPluginOption(constUitalic, userItalic).toBool(); tagItalic = psiOptions->getPluginOption(constTitalic, tagItalic).toBool(); msgItalic = psiOptions->getPluginOption(constMitalic, msgItalic).toBool(); quoteItalic = psiOptions->getPluginOption(constQitalic, quoteItalic).toBool(); lineItalic = psiOptions->getPluginOption(constLitalic, lineItalic).toBool(); //underline userUnderline = psiOptions->getPluginOption(constUunderline, userUnderline).toBool(); tagUnderline = psiOptions->getPluginOption(constTunderline, tagUnderline).toBool(); msgUnderline = psiOptions->getPluginOption(constMunderline, msgUnderline).toBool(); quoteUnderline = psiOptions->getPluginOption(constQunderline, quoteUnderline).toBool(); lineUnderline = psiOptions->getPluginOption(constLunderline, lineUnderline).toBool(); idAsResource = psiOptions->getPluginOption(constIdAsResource, idAsResource).toBool(); commonLinkColor = psiOptions->getGlobalOption("options.ui.look.colors.chat.link-color").toString(); showPhoto = psiOptions->getPluginOption(constShowPhoto, showPhoto).toBool(); showAvatars = psiOptions->getPluginOption(constShowAvatars, showAvatars).toBool(); workInGroupChat = psiOptions->getPluginOption(constWorkInGroupchat, workInGroupChat).toBool(); jidList_ = psiOptions->getPluginOption("constJidList",QVariant(jidList_)).toStringList(); applicationInfo->getProxyFor(constPluginName); // init proxy settings for Juick plugin if (showAvatars || showPhoto) { createAvatarsDir(); } downloader_ = new JuickDownloader(applicationInfo, this); connect(downloader_, SIGNAL(finished(QList)), SLOT(updateWidgets(QList))); setStyles(); return true; } bool JuickPlugin::disable() { enabled = false; logs_.clear(); QDir dir(applicationInfo->appHomeDir(ApplicationInfoAccessingHost::CacheLocation)+"/avatars/juick/photos"); foreach(const QString& file, dir.entryList(QDir::Files)) { QFile::remove(dir.absolutePath()+"/"+file); } JuickParser::reset(); downloader_->disconnect(); downloader_->deleteLater(); downloader_ = 0; return true; } void JuickPlugin::createAvatarsDir() { QDir dir(applicationInfo->appHomeDir(ApplicationInfoAccessingHost::CacheLocation)+"/avatars"); dir.mkpath("juick/photos"); if (!dir.exists("juick/photos")) { QMessageBox::warning(0, tr("Warning"),tr("can't create folder %1 \ncaching avatars will be not available") .arg(applicationInfo->appHomeDir(ApplicationInfoAccessingHost::CacheLocation)+"/avatars/juick")); } } void JuickPlugin::applyOptions() { if (!optionsWid) return; userColor = ui_.tb_name->property("psi_color").value(); tagColor = ui_.tb_tag->property("psi_color").value(); msgColor = ui_.tb_message->property("psi_color").value(); quoteColor = ui_.tb_quote->property("psi_color").value(); lineColor = ui_.tb_link->property("psi_color").value(); psiOptions->setPluginOption(constuserColor, userColor); psiOptions->setPluginOption(consttagColor, tagColor); psiOptions->setPluginOption(constmsgColor, msgColor); psiOptions->setPluginOption(constQcolor, quoteColor); psiOptions->setPluginOption(constLcolor, lineColor); //bold userBold = ui_.cb_nameBold->isChecked(); tagBold = ui_.cb_tagBold->isChecked(); msgBold = ui_.cb_messageBold->isChecked(); quoteBold = ui_.cb_quoteBold->isChecked(); lineBold = ui_.cb_linkBold->isChecked(); psiOptions->setPluginOption(constUbold, userBold); psiOptions->setPluginOption(constTbold, tagBold); psiOptions->setPluginOption(constMbold, msgBold); psiOptions->setPluginOption(constQbold, quoteBold); psiOptions->setPluginOption(constLbold, lineBold); //italic userItalic = ui_.cb_nameItalic->isChecked(); tagItalic = ui_.cb_tagItalic->isChecked(); msgItalic = ui_.cb_messageItalic->isChecked(); quoteItalic = ui_.cb_quoteItalic->isChecked(); lineItalic = ui_.cb_linkItalic->isChecked(); psiOptions->setPluginOption(constUitalic, userItalic); psiOptions->setPluginOption(constTitalic, tagItalic); psiOptions->setPluginOption(constMitalic, msgItalic); psiOptions->setPluginOption(constQitalic, quoteItalic); psiOptions->setPluginOption(constLitalic, lineItalic); //underline userUnderline = ui_.cb_nameUnderline->isChecked(); tagUnderline = ui_.cb_tagUnderline->isChecked(); msgUnderline = ui_.cb_messageUnderline->isChecked(); quoteUnderline = ui_.cb_quoteUnderline->isChecked(); lineUnderline = ui_.cb_linkUnderline->isChecked(); psiOptions->setPluginOption(constUunderline, userUnderline); psiOptions->setPluginOption(constTunderline, tagUnderline); psiOptions->setPluginOption(constMunderline, msgUnderline); psiOptions->setPluginOption(constQunderline, quoteUnderline); psiOptions->setPluginOption(constLunderline, lineUnderline); //asResource idAsResource = ui_.cb_idAsResource->isChecked(); psiOptions->setPluginOption(constIdAsResource, idAsResource); showPhoto = ui_.cb_showPhoto->isChecked(); psiOptions->setPluginOption(constShowPhoto, showPhoto); showAvatars = ui_.cb_showAvatar->isChecked(); if (showAvatars || showPhoto) createAvatarsDir(); psiOptions->setPluginOption(constShowAvatars, showAvatars); workInGroupChat = ui_.cb_conference->isChecked(); psiOptions->setPluginOption(constWorkInGroupchat, workInGroupChat); psiOptions->setPluginOption("constJidList",QVariant(jidList_)); setStyles(); } void JuickPlugin::restoreOptions() { if (!optionsWid) return; ui_.tb_name->setStyleSheet(QString("background-color: %1;").arg(userColor.name())); ui_.tb_tag->setStyleSheet(QString("background-color: %1;").arg(tagColor.name())); ui_.tb_message->setStyleSheet(QString("background-color: %1;").arg(msgColor.name())); ui_.tb_quote->setStyleSheet(QString("background-color: %1;").arg(quoteColor.name())); ui_.tb_link->setStyleSheet(QString("background-color: %1;").arg(lineColor.name())); ui_.tb_name->setProperty("psi_color",userColor); ui_.tb_tag->setProperty("psi_color",tagColor); ui_.tb_message->setProperty("psi_color",msgColor); ui_.tb_quote->setProperty("psi_color",quoteColor); ui_.tb_link->setProperty("psi_color",lineColor); //bold ui_.cb_nameBold->setChecked(userBold); ui_.cb_tagBold->setChecked(tagBold); ui_.cb_messageBold->setChecked(msgBold); ui_.cb_quoteBold->setChecked(quoteBold); ui_.cb_linkBold->setChecked(lineBold); //italic ui_.cb_nameItalic->setChecked(userItalic); ui_.cb_tagItalic->setChecked(tagItalic); ui_.cb_messageItalic->setChecked(msgItalic); ui_.cb_quoteItalic->setChecked(quoteItalic); ui_.cb_linkItalic->setChecked(lineItalic); //underline ui_.cb_nameUnderline->setChecked(userUnderline); ui_.cb_tagUnderline->setChecked(tagUnderline); ui_.cb_messageUnderline->setChecked(msgUnderline); ui_.cb_quoteUnderline->setChecked(quoteUnderline); ui_.cb_linkUnderline->setChecked(lineUnderline); ui_.cb_idAsResource->setChecked(idAsResource); ui_.cb_showPhoto->setChecked(showPhoto); ui_.cb_showAvatar->setChecked(showAvatars); ui_.cb_conference->setChecked(workInGroupChat); } QPixmap JuickPlugin::icon() const { return QPixmap(":/icons/juick.png"); } void JuickPlugin::requestJidList() { JuickJidList *jjl = new JuickJidList(jidList_, optionsWid); connect(jjl, SIGNAL(listUpdated(QStringList)), SLOT(updateJidList(QStringList))); jjl->show(); } void JuickPlugin::updateJidList(const QStringList& jids) { jidList_ = jids; //HACK if(optionsWid) { ui_.cb_idAsResource->toggle(); ui_.cb_idAsResource->toggle(); } } void JuickPlugin::setStyles() { //Задаём стили idStyle = "color: " + msgColor.name() + ";"; if (msgBold) { idStyle += "font-weight: bold;"; } if (msgItalic) { idStyle += "font-style: italic;"; } if (!msgUnderline) { idStyle += "text-decoration: none;"; } userStyle = "color: " + userColor.name() + ";"; if (userBold) { userStyle += "font-weight: bold;"; } if (userItalic) { userStyle += "font-style: italic;"; } if (!userUnderline) { userStyle += "text-decoration: none;"; } tagStyle = "color: " + tagColor.name() + ";"; if (tagBold) { tagStyle += "font-weight: bold;"; } if (tagItalic) { tagStyle += "font-style: italic;"; } if (!tagUnderline) { tagStyle += "text-decoration: none;"; } quoteStyle = "color: " + quoteColor.name() + ";"; if (quoteBold) { quoteStyle += "font-weight: bold;"; } if (quoteItalic) { quoteStyle += "font-style: italic;"; } if (!quoteUnderline) { quoteStyle += "text-decoration: none;"; } quoteStyle += "margin: 5px;"; linkStyle = "color: " + lineColor.name() + ";"; if (lineBold) { linkStyle += "font-weight: bold;"; } if (lineItalic) { linkStyle += "font-style: italic;"; } if (!lineUnderline) { linkStyle += "text-decoration: none;"; } } void JuickPlugin::chooseColor(QWidget* w) { QToolButton *button = static_cast(w); QColor c(button->property("psi_color").value()); c = QColorDialog::getColor(c); if(c.isValid()) { button->setProperty("psi_color", c); button->setStyleSheet(QString("background-color: %1").arg(c.name())); //HACK ui_.cb_idAsResource->toggle(); ui_.cb_idAsResource->toggle(); } } void JuickPlugin::clearCache() { QDir dir(applicationInfo->appHomeDir(ApplicationInfoAccessingHost::CacheLocation)+"/avatars/juick"); foreach(const QString& file, dir.entryList(QDir::Files)) { QFile::remove(dir.absolutePath()+"/"+file); } } void JuickPlugin::setOptionAccessingHost(OptionAccessingHost* host) { psiOptions = host; } void JuickPlugin::setActiveTabAccessingHost(ActiveTabAccessingHost* host) { activeTab = host; } void JuickPlugin::setApplicationInfoAccessingHost(ApplicationInfoAccessingHost* host) { applicationInfo = host; } bool JuickPlugin::incomingStanza(int /*account*/, const QDomElement& stanza) { if(!enabled) return false; if (stanza.tagName() == "message" ) { const QString jid(stanza.attribute("from").split('/').first()); const QString usernameJ(jid.split("@").first()); if (workInGroupChat && jid == "juick@conference.jabber.ru") { QString msg = stanza.firstChild().nextSibling().firstChild().nodeValue(); msg.replace(QRegExp("#(\\d+)"),"http://juick.com/\\1"); stanza.firstChild().nextSibling().firstChild().setNodeValue(msg); } if(jidList_.contains(jid) || usernameJ == "juick%juick.com" || usernameJ == "jubo%nologin.ru") { // qDebug() << "BEFORE"; // debugElement(stanza); QDomDocument doc = stanza.ownerDocument(); QDomElement nonConstStanza = const_cast(stanza); JuickParser jp(&nonConstStanza); QString resource(""); QString res(""); QString jidToSend(juick); if (usernameJ == "juick%juick.com") { jidToSend = jid; } if (usernameJ == "jubo%nologin.ru") { jidToSend = "juick%juick.com@"+jid.split("@").last(); } userLinkPattern = chatPlusAction; altTextUser = userInfoString; if ( jid == jubo ) { messageLinkPattern = chatAction; altTextMsg = replyMsgString; } else { messageLinkPattern = "xmpp:%1%3?message;type=chat;body=%2+"; altTextMsg = showAllmsgString; } if (showAvatars) { const QString ava = jp.avatarLink(); if(!ava.isEmpty()) { const QString unick("@" + jp.nick()); bool getAv = true; QDir dir(applicationInfo->appHomeDir(ApplicationInfoAccessingHost::CacheLocation)+"/avatars/juick"); if(!dir.exists()) { getAv = false; } else { QFile file(QString("%1/%2").arg(dir.absolutePath()).arg(unick)); if (file.exists()) { if (QFileInfo(file).lastModified().daysTo(QDateTime::currentDateTime()) > avatarsUpdateInterval || file.size() == 0) { file.remove(); } else { getAv = false; } } } if(getAv) { QDir dir(applicationInfo->appHomeDir(ApplicationInfoAccessingHost::CacheLocation)+"/avatars/juick"); const QString path(QString("%1/%2").arg(dir.absolutePath()).arg(unick)); const QString url = QString("http://i.juick.com%1").arg(ava); JuickDownloadItem it(path, url); downloader_->get(it); } } } //добавляем перевод строки для обработки ссылок и номеров сообщений в конце сообщения QString msg = "\n" + jp.originMessage() + "\n"; msg.replace(">",">"); msg.replace("<","<"); //Создаем xhtml-im элемент QDomElement element = doc.createElement("html"); element.setAttribute("xmlns","http://jabber.org/protocol/xhtml-im"); QDomElement body = doc.createElement("body"); body.setAttribute("xmlns","http://www.w3.org/1999/xhtml"); //HELP if (msg.indexOf("\nNICK mynickname - Set a nickname\n\n") != -1) { nl2br(&body, &doc, msg); if (idAsResource) { QStringList tmp = activeTab->getJid().split('/'); if (tmp.count() > 1 && jid == tmp.first()) { resource = tmp.last(); } } msg.clear(); } const QString photo = jp.photoLink(); JuickMessages jm = jp.getMessages(); const JuickParser::JMType type = jp.type(); switch (type) { case JuickParser::JM_10_Messages: { body.appendChild(doc.createTextNode(jp.infoText())); foreach(const JuickMessage& m, jm) { body.appendChild(doc.createElement("br")); addUserLink(&body, &doc, "@" + m.unick, altTextUser, chatPlusAction, jidToSend); body.appendChild(doc.createTextNode(": ")); //добавляем теги foreach (const QString& tag, m.tags){ addTagLink(&body, &doc, tag, jidToSend); } body.appendChild(doc.createElement("br")); //обрабатываем текст сообщения QString newMsg = " " + m.body + " "; elementFromString(&body, &doc, newMsg, jidToSend); //xmpp ссылка на сообщение addMessageId(&body, &doc, m.messageId, replyMsgString, chatAction, jidToSend); body.appendChild(doc.createTextNode(" ")); addPlus(&body, &doc, m.messageId,jidToSend); //ссылка на сообщение body.appendChild(doc.createTextNode(" ")); addSubscribe(&body, &doc, m.messageId, jidToSend); body.appendChild(doc.createTextNode(" ")); addFavorite(&body, &doc, m.messageId, jidToSend); body.appendChild(doc.createTextNode(" "+m.infoText)); addHttpLink(&body, &doc, m.link); body.appendChild(doc.createElement("br")); } body.removeChild(body.lastChild()); msg.clear(); break; } case JuickParser::JM_Tags_Top: { body.appendChild(doc.createTextNode(jp.infoText())); body.appendChild(doc.createElement("br")); JuickMessage m = jm.first(); foreach(const QString& tag, m.tags) { addTagLink(&body, &doc, tag, jidToSend); body.appendChild(doc.createElement("br")); } break; } case JuickParser::JM_Recomendation: case JuickParser::JM_Message: case JuickParser::JM_All_Messages: case JuickParser::JM_Post_View: case JuickParser::JM_Jubo: { JuickMessage m = jm.first(); QString resLink(""); if (idAsResource && type != JuickParser::JM_Post_View && type != JuickParser::JM_Jubo) { resource = m.messageId; resLink = "/" + resource; resLink.replace("#","%23"); } if(type == JuickParser::JM_Jubo) { body.appendChild(doc.createTextNode(jp.infoText())); } body.appendChild(doc.createElement("br")); if(type == JuickParser::JM_Recomendation && !jp.timeStamp().isEmpty()) { body.appendChild(doc.createTextNode(tr("Time stamp: %1").arg(jp.timeStamp()))); body.appendChild(doc.createElement("br")); } if(type == JuickParser::JM_Recomendation) { QStringList tmp = jp.infoText().split("@"); body.appendChild(doc.createTextNode(tmp.first())); addUserLink(&body, &doc, "@" + tmp.last(), altTextUser, chatPlusAction, jidToSend); body.appendChild(doc.createTextNode(":")); body.appendChild(doc.createElement("br")); } addUserLink(&body, &doc, "@" + m.unick, altTextUser, chatPlusAction, jidToSend); body.appendChild(doc.createTextNode(": ")); //добавляем теги foreach (const QString& tag, m.tags) { addTagLink(&body, &doc, tag, jidToSend); } msg = " " + m.body + " "; if (showAvatars) { addAvatar(&body, &doc, msg, jidToSend, m.unick); } else { body.appendChild(doc.createElement("br")); //обрабатываем текст сообщения elementFromString(&body, &doc, msg, jidToSend); } if (type == JuickParser::JM_Post_View && m.infoText.isEmpty()) { messageLinkPattern = chatAction; altTextMsg = replyMsgString; } //xmpp ссылка на сообщение addMessageId(&body, &doc, m.messageId, replyMsgString, chatAction, jidToSend, resLink); //ссылка на сообщение body.appendChild(doc.createTextNode(" ")); if(type != JuickParser::JM_All_Messages && type != JuickParser::JM_Post_View) { addPlus(&body, &doc, m.messageId, jidToSend, resLink); body.appendChild(doc.createTextNode(" ")); } addSubscribe(&body, &doc, m.messageId, jidToSend, resLink); body.appendChild(doc.createTextNode(" ")); addFavorite(&body, &doc, m.messageId, jidToSend, resLink); body.appendChild(doc.createTextNode(" ")); if(!m.infoText.isEmpty() && type != JuickParser::JM_All_Messages) { body.appendChild(doc.createTextNode(m.infoText)); body.appendChild(doc.createTextNode(" ")); } addHttpLink(&body, &doc, m.link); if(type == JuickParser::JM_All_Messages) msg = m.infoText; else msg.clear(); break; } case JuickParser::JM_Reply: { JuickMessage m = jm.first(); QString resLink(""); QString replyId(m.messageId); if (idAsResource) { resource = replyId.left(replyId.indexOf("/")); resLink = "/" + resource; resLink.replace("#","%23"); } body.appendChild(doc.createElement("br")); addUserLink(&body, &doc, "@" + m.unick, altTextUser ,chatPlusAction, jidToSend); body.appendChild(doc.createTextNode(tr(" replied:"))); //цитата QDomElement blockquote = doc.createElement("blockquote"); blockquote.setAttribute("style",quoteStyle); blockquote.appendChild(doc.createTextNode(jp.infoText())); //обрабатываем текст сообщения msg = " " + m.body + " "; body.appendChild(blockquote); if (showAvatars) { addAvatar(&body, &doc, msg, jidToSend, m.unick); //td2.appendChild(blockquote); } else { //body.appendChild(blockquote); elementFromString(&body, &doc, msg, jidToSend); } //xmpp ссылка на сообщение addMessageId(&body, &doc,m.messageId, replyMsgString, chatAction, jidToSend, resLink); //ссылка на сообщение body.appendChild(doc.createTextNode(" ")); QString msgId = m.messageId.split("/").first(); addUnsubscribe(&body, &doc, m.messageId, jidToSend, resLink); body.appendChild(doc.createTextNode(" ")); addPlus(&body, &doc, msgId, jidToSend, resLink); body.appendChild(doc.createTextNode(" ")); addHttpLink(&body, &doc, m.link); msg.clear(); break; } case JuickParser::JM_Reply_Posted: case JuickParser::JM_Message_Posted: { JuickMessage m = jm.first(); QString resLink(""); if (idAsResource) { if(type == JuickParser::JM_Reply_Posted) { resource = m.messageId.split("/").first(); resLink = "/" + resource; } else { QStringList tmp = activeTab->getJid().split('/'); if (tmp.count() > 1 && jid == tmp.first()) { resource = tmp.last(); resLink = "/" + resource; } else { resLink = "/" + m.messageId.split("/").first(); } } resLink.replace("#","%23"); } body.appendChild(doc.createElement("br")); body.appendChild(doc.createTextNode(jp.infoText())); body.appendChild(doc.createElement("br")); //xmpp ссылка на сообщение addMessageId(&body, &doc, m.messageId, replyMsgString, chatAction,jidToSend,resLink); body.appendChild(doc.createTextNode(" ")); if(type == JuickParser::JM_Message_Posted) { addPlus(&body, &doc, m.messageId, jidToSend, resLink); body.appendChild(doc.createTextNode(" ")); } addDelete(&body, &doc, m.messageId, jidToSend, resLink); body.appendChild(doc.createTextNode(" ")); //ссылка на сообщение body.appendChild(doc.createTextNode(" ")); addHttpLink(&body, &doc, m.link); msg.clear(); break; } case JuickParser::JM_Your_Post_Recommended: { JuickMessage m = jm.first(); QString resLink(""); if (idAsResource) { resource = m.messageId; resLink = "/" + resource; resLink.replace("#","%23"); } body.appendChild(doc.createElement("br")); addUserLink(&body, &doc, "@" + m.unick, altTextUser ,chatPlusAction, jidToSend); body.appendChild(doc.createTextNode(m.infoText)); addMessageId(&body, &doc, m.messageId, replyMsgString, chatAction, jidToSend, resLink); body.appendChild(doc.createElement("br")); addPlus(&body, &doc, m.messageId, jidToSend, resLink); body.appendChild(doc.createTextNode(" ")); addHttpLink(&body, &doc, m.link); msg.clear(); break; } case JuickParser::JM_Private: { userLinkPattern = "xmpp:%1?message;type=chat;body=PM %2"; altTextUser = tr("Send personal message to %1"); break; } case JuickParser::JM_User_Info: { userLinkPattern = "xmpp:%1?message;type=chat;body=S %2"; altTextUser = tr("Subscribe to %1's blog"); break; } default: { if (msg.indexOf("Recommended blogs:") != -1) { //если команда @ userLinkPattern = "xmpp:%1?message;type=chat;body=S %2"; altTextUser = tr("Subscribe to %1's blog"); } // else if (msg == "\nPONG\n" // || msg == "\nSubscribed!\n" // || msg == "\nUnsubscribed!\n" // || msg == "\nPrivate message sent.\n" // || msg == "\nInvalid request.\n" // || msg == "\nMessage added to your favorites.\n" // || msg == "\nMessage, you are replying to, not found.\n" // || msg == "\nThis nickname is already taken by someone\n" // || msg == "\nUser not found.\n" // || delMsgRx.indexIn(msg) != -1 // || delReplyRx.indexIn(msg) != -1 ) { // msg = msg.left(msg.size() - 1); // } break; } } if (idAsResource && resource.isEmpty() && jid != jubo && usernameJ != "jubo%nologin.ru") { QStringList tmp = activeTab->getJid().split('/'); if (tmp.count() > 1 && jid == tmp.first()) { resource = tmp.last(); } } if (!photo.isEmpty()) { if(showPhoto) { //photo post const QUrl photoUrl(photo); const QDir dir(applicationInfo->appHomeDir(ApplicationInfoAccessingHost::CacheLocation)+"/avatars/juick/photos"); const QString path(QString("%1/%2").arg(dir.absolutePath()).arg(photoUrl.path().replace("/", "%"))); JuickDownloadItem it(path, photoUrl.toString().replace("/photos-1024/","/ps/")); downloader_->get(it); QDomElement link = doc.createElement("a"); link.setAttribute("href", photo); QDomElement img = doc.createElement("img"); QString imgdata = photoUrl.path().replace("/", "%"); img.setAttribute("src", QString(QUrl::fromLocalFile(QString("%1/%2").arg(dir.absolutePath()).arg(imgdata)).toEncoded())); link.appendChild(img); link.appendChild(doc.createElement("br")); body.insertAfter(link, body.lastChildElement("table")); } //удаление вложения, пока шлётся ссылка в сообщении nonConstStanza.removeChild(jp.findElement("x", "jabber:x:oob")); } //обработка по умолчанию elementFromString(&body, &doc, msg, jidToSend, res); element.appendChild(body); nonConstStanza.appendChild(element); if (!resource.isEmpty()) { QString from = stanza.attribute("from"); from.replace(QRegExp("(.*)/.*"), "\\1/"+resource); nonConstStanza.setAttribute("from", from); } // qDebug() << "AFTER"; // debugElement(stanza); } } return false; } void JuickPlugin::elementFromString(QDomElement* body,QDomDocument* e, const QString& msg, const QString& jid, const QString& resource) { int new_pos = 0; int pos = 0; while ((new_pos = regx.indexIn(msg, pos)) != -1) { QString before = msg.mid(pos,new_pos-pos+regx.cap(1).length()); int quoteSize = 0; nl2br(body, e, before.right(before.size() - quoteSize)); QString seg = regx.cap(2); switch (seg.at(0).toLatin1()) { case '#':{ idRx.indexIn(seg); if (!idRx.cap(2).isEmpty()) { //для #1234/12 - +ненужен messageLinkPattern = chatAction; altTextMsg = replyMsgString; } addMessageId(body, e,idRx.cap(1)+idRx.cap(2), altTextMsg, messageLinkPattern,jid, resource); body->appendChild(e->createTextNode(idRx.cap(3))); break;} case '@':{ nickRx.indexIn(seg); addUserLink(body, e, nickRx.cap(1), altTextUser ,userLinkPattern,jid); body->appendChild(e->createTextNode(nickRx.cap(2))); //tag if (nickRx.cap(2) == ":" && (regx.cap(1) == "\n" || regx.cap(1) == "\n\n")){ body->appendChild(e->ownerDocument().createTextNode(" ")); QString tagMsg = msg.right(msg.size()-(new_pos+regx.matchedLength()-regx.cap(3).size())); for (int i=0; i < 6; ++i){ if (tagRx.indexIn(tagMsg, 0) != -1){ addTagLink(body, e, tagRx.cap(1),jid); tagMsg = tagMsg.right(tagMsg.size() - tagRx.matchedLength()); new_pos += tagRx.matchedLength(); } else { break; } } new_pos += regx.cap(3).size() - 1; } break;} case '*':{ QDomElement bold = e->createElement("b"); bold.appendChild(e->createTextNode(seg.mid(1,seg.size()-2))); body->appendChild(bold); break;} case '_':{ QDomElement under = e->createElement("u"); under.appendChild(e->createTextNode(seg.mid(1,seg.size()-2))); body->appendChild(under); break;} case '/':{ QDomElement italic = e->createElement("i"); italic.appendChild(e->createTextNode(seg.mid(1,seg.size()-2))); body->appendChild(italic); break;} case 'h': case 'f':{ QDomElement ahref = e->createElement("a"); ahref.setAttribute("style","color:" + commonLinkColor + ";"); ahref.setAttribute("href",seg); ahref.appendChild(e->createTextNode(seg)); body->appendChild(ahref); break;} case '[':{ QDomElement ahref = e->createElement("a"); linkRx.indexIn(seg); ahref.setAttribute("style","color:" + commonLinkColor + ";"); ahref.setAttribute("href",linkRx.cap(2)); ahref.appendChild(e->createTextNode(linkRx.cap(1))); body->appendChild(ahref); break;} default:{} } pos = new_pos+regx.matchedLength()-regx.cap(3).size(); new_pos = pos; } nl2br(body, e , msg.right(msg.size()-pos)); body->appendChild(e->createElement("br")); } void JuickPlugin::addAvatar(QDomElement* body, QDomDocument* doc, const QString& msg, const QString& jidToSend, const QString& ujid) { QDomElement table = doc->createElement("table"); table.setAttribute("style", "word-wrap:break-word; table-layout: fixed; width:100%"); QDomElement tableRow = doc->createElement("tr"); QDomElement td1 = doc->createElement("td"); td1.setAttribute("valign","top"); td1.setAttribute("style", "width:50px"); QDomElement td2 = doc->createElement("td"); QDir dir(applicationInfo->appHomeDir(ApplicationInfoAccessingHost::CacheLocation)+"/avatars/juick"); if (dir.exists()) { QDomElement img = doc->createElement("img"); img.setAttribute("src", QString(QUrl::fromLocalFile(QString("%1/@%2").arg(dir.absolutePath()).arg(ujid)).toEncoded())); td1.appendChild(img); } // td2.appendChild(blockquote); elementFromString(&td2, doc, msg, jidToSend); tableRow.appendChild(td1); tableRow.appendChild(td2); table.appendChild(tableRow); body->appendChild(table); } void JuickPlugin::addPlus(QDomElement *body,QDomDocument* e, const QString& msg_, const QString& jid, const QString& resource) { QString msg(msg_); QDomElement plus = e->createElement("a"); plus.setAttribute("style",idStyle); plus.setAttribute("title",showAllmsgString); plus.setAttribute("href",QString("xmpp:%1%3?message;type=chat;body=%2+").arg(jid).arg(msg.replace("#","%23")).arg(resource)); plus.appendChild(e->createTextNode("+")); body->appendChild(plus); } void JuickPlugin::addSubscribe(QDomElement* body,QDomDocument* e, const QString& msg_, const QString& jid, const QString& resource) { QString msg(msg_); QDomElement subscribe = e->createElement("a"); subscribe.setAttribute("style",idStyle); subscribe.setAttribute("title",subscribeString); subscribe.setAttribute("href",QString("xmpp:%1%3?message;type=chat;body=S %2").arg(jid).arg(msg.replace("#","%23")).arg(resource)); subscribe.appendChild(e->createTextNode("S")); body->appendChild(subscribe); } void JuickPlugin::addHttpLink(QDomElement* body,QDomDocument* e, const QString& msg) { QDomElement ahref = e->createElement("a"); ahref.setAttribute("href",msg); ahref.setAttribute("style",linkStyle); ahref.appendChild(e->createTextNode(msg)); body->appendChild(ahref); } void JuickPlugin::addTagLink(QDomElement* body,QDomDocument* e, const QString& tag, const QString& jid) { QDomElement taglink = e->createElement("a"); taglink.setAttribute("style",tagStyle); taglink.setAttribute("title",showLastTenString.arg(tag)); taglink.setAttribute("href",QString("xmpp:%1?message;type=chat;body=%2").arg(jid).arg(tag)); taglink.appendChild(e->createTextNode( tag)); body->appendChild(taglink); body->appendChild(e->createTextNode(" ")); } void JuickPlugin::addUserLink(QDomElement* body,QDomDocument* e, const QString& nick, const QString& altText, const QString& pattern, const QString& jid) { QDomElement ahref = e->createElement("a"); ahref.setAttribute("style", userStyle); ahref.setAttribute("title", altText.arg(nick)); ahref.setAttribute("href", pattern.arg(jid).arg(nick)); ahref.appendChild(e->createTextNode(nick)); body->appendChild(ahref); } void JuickPlugin::addMessageId(QDomElement* body,QDomDocument* e, const QString& mId_, const QString& altText, const QString& pattern, const QString& jid, const QString& resource) { QString mId(mId_); QDomElement ahref = e->createElement("a"); ahref.setAttribute("style",idStyle); ahref.setAttribute("title",altText); ahref.setAttribute("href",QString(pattern).arg(jid).arg(mId.replace("#","%23")).arg(resource)); ahref.appendChild(e->createTextNode(mId.replace("%23","#"))); body->appendChild(ahref); } void JuickPlugin::addUnsubscribe(QDomElement* body,QDomDocument* e, const QString& msg_, const QString& jid, const QString& resource) { QString msg(msg_); QDomElement unsubscribe = e->createElement("a"); unsubscribe.setAttribute("style",idStyle); unsubscribe.setAttribute("title",unsubscribeString); unsubscribe.setAttribute("href",QString("xmpp:%1%3?message;type=chat;body=U %2").arg(jid).arg(msg.left(msg.indexOf("/")).replace("#","%23")).arg(resource)); unsubscribe.appendChild(e->createTextNode("U")); body->appendChild(unsubscribe); } void JuickPlugin::addDelete(QDomElement* body, QDomDocument* e, const QString& msg_, const QString& jid, const QString& resource) { QString msg(msg_); QDomElement unsubscribe = e->createElement("a"); unsubscribe.setAttribute("style",idStyle); unsubscribe.setAttribute("title",tr("Delete")); unsubscribe.setAttribute("href",QString("xmpp:%1%3?message;type=chat;body=D %2").arg(jid).arg(msg.replace("#","%23")).arg(resource)); unsubscribe.appendChild(e->createTextNode("D")); body->appendChild(unsubscribe); } void JuickPlugin::addFavorite(QDomElement* body,QDomDocument* e, const QString& msg_, const QString& jid, const QString& resource) { QString msg(msg_); QDomElement unsubscribe = e->createElement("a"); unsubscribe.setAttribute("style",idStyle); unsubscribe.setAttribute("title",tr("Add to favorites")); unsubscribe.setAttribute("href",QString("xmpp:%1%3?message;type=chat;body=! %2").arg(jid).arg(msg.replace("#","%23")).arg(resource)); unsubscribe.appendChild(e->createTextNode("!")); body->appendChild(unsubscribe); } // Здесь мы просто ищем и сохраняем список уже открытых // чатов с juick void JuickPlugin::setupChatTab(QWidget* tab, int /*account*/, const QString &contact) { const QString jid = contact.split("/").first(); const QString usernameJ = jid.split("@").first(); if(jidList_.contains(jid) || usernameJ == "juick%juick.com"|| usernameJ == "jubo%nologin.ru") { QWidget* log = tab->findChild("log"); if(log) { logs_.append(log); connect(log, SIGNAL(destroyed()), SLOT(removeWidget())); } } } void JuickPlugin::removeWidget() { QWidget* w = static_cast(sender()); logs_.removeAll(w); } // Этот слот обновляет чатлоги, чтобы они перезагрузили // картинки с диска. void JuickPlugin::updateWidgets(const QList& urls) { foreach(QWidget *w, logs_) { QTextEdit* te = qobject_cast(w); if(te) { QTextDocument* td = te->document(); foreach(const QByteArray& url, urls) { QUrl u(url); td->addResource(QTextDocument::ImageResource, u, QPixmap(u.toLocalFile())); } te->setLineWrapColumnOrWidth(te->lineWrapColumnOrWidth()); } else { int t = qrand()%(QTime::currentTime().msec() + 1); #ifdef HAVE_WEBKIT QWebView *wv = w->findChild(); if(wv) { QWebFrame* wf = wv->page()->mainFrame(); foreach(const QByteArray& url, urls) { QUrl u(url); QWebElement elem = wf->findFirstElement(QString("img[src=\"%1\"]").arg(u.toString())); if(!elem.isNull()) { elem.setAttribute("src", u.toString() + "?" + QString::number(++t)); } } } #endif #ifdef HAVE_WEBENGINE #ifdef __GNUC__ #warning "JuickPlugin TODO: check webengine staff works" #endif QWebEngineView *wv = w->findChild(); if(wv) { QWebEnginePage* wf = wv->page(); foreach(const QByteArray& url, urls) { QUrl u(url); const QString js = QString("var els=document.querySelectorAll(\"img[src='%1']\");" "for(var i=0;irunJavaScript(js); } } #endif } } } QString JuickPlugin::pluginInfo() { return tr("Authors: ") + "VampiRUS, Dealer_WeARE\n\n" + trUtf8("This plugin is designed to work efficiently and comfortably with the Juick microblogging service.\n" "Currently, the plugin is able to: \n" "* Coloring @nick, *tag and #message_id in messages from the juick@juick.com bot\n" "* Detect >quotes in messages\n" "* Enable clickable @nick, *tag, #message_id and other control elements to insert them into the typing area\n\n" "Note: To work correctly, the option options.html.chat.render must be set to true. "); } plugins-1.5/generic/juickplugin/juickplugin.h000066400000000000000000000117631336777360500215260ustar00rootroot00000000000000/* * juickplugin.h - plugin * Copyright (C) 2009-2012 Kravtsov Nikolai, Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef JUICKPLUGIN_H #define JUICKPLUGIN_H #include "psiplugin.h" #include "stanzafilter.h" #include "optionaccessor.h" #include "activetabaccessor.h" #include "plugininfoprovider.h" #include "chattabaccessor.h" #include "applicationinfoaccessor.h" #include "ui_settings.h" class OptionAccessingHost; class ActiveTabAccessingHost; class ApplicationInfoAccessingHost; class JuickDownloader; class QDomDocument; class JuickPlugin : public QObject, public PsiPlugin, public OptionAccessor, public ActiveTabAccessor, public StanzaFilter, public ApplicationInfoAccessor, public PluginInfoProvider, public ChatTabAccessor { Q_OBJECT #ifdef HAVE_QT5 Q_PLUGIN_METADATA(IID "com.psi-plus.JuickPlugin") #endif Q_INTERFACES(PsiPlugin OptionAccessor ActiveTabAccessor StanzaFilter ApplicationInfoAccessor PluginInfoProvider ChatTabAccessor) public: JuickPlugin(); virtual QString name() const; virtual QString shortName() const; virtual QString version() const; virtual QWidget* options(); virtual bool enable(); virtual bool disable(); virtual void applyOptions(); virtual void restoreOptions(); virtual QPixmap icon() const; virtual void setOptionAccessingHost(OptionAccessingHost* host); virtual void optionChanged(const QString& ) {} virtual void setActiveTabAccessingHost(ActiveTabAccessingHost* host); virtual void setApplicationInfoAccessingHost(ApplicationInfoAccessingHost* host); virtual QString pluginInfo(); // ChatTabAccessor void setupChatTab(QWidget* tab, int account, const QString& contact); void setupGCTab(QWidget* /*tab*/, int /*account*/, const QString& /*contact*/) { /* do nothing*/ } bool appendingChatMessage(int, const QString&, QString&, QDomElement&, bool) { return false; } virtual bool incomingStanza(int account, const QDomElement& stanza); virtual bool outgoingStanza(int , QDomElement& ) { return false; } private slots: void chooseColor(QWidget *); void clearCache(); void updateJidList(const QStringList& jids); void requestJidList(); void removeWidget(); void updateWidgets(const QList &urls); private: void createAvatarsDir(); void setStyles(); void elementFromString(QDomElement* body, QDomDocument* e, const QString &msg, const QString &jid, const QString &resource = ""); void addPlus(QDomElement* body, QDomDocument* e, const QString &msg, const QString &jid, const QString &resource = ""); void addSubscribe(QDomElement* body, QDomDocument* e, const QString &msg, const QString &jid, const QString &resource = ""); void addHttpLink(QDomElement* body, QDomDocument* e, const QString &msg); void addTagLink(QDomElement* body, QDomDocument* e, const QString &tag, const QString &jid); void addUserLink(QDomElement* body, QDomDocument* e, const QString& nick, const QString& altText, const QString& pattern, const QString& jid); void addMessageId(QDomElement* body, QDomDocument* e, const QString& mId, const QString& altText, const QString& pattern, const QString& jid, const QString& resource = ""); void addUnsubscribe(QDomElement* body, QDomDocument* e, const QString &msg, const QString &jid, const QString &resource = ""); void addDelete(QDomElement* body ,QDomDocument* e, const QString& msg, const QString& jid, const QString& resource = ""); void addFavorite(QDomElement* body, QDomDocument* e, const QString &msg, const QString &jid, const QString &resource = ""); void addAvatar(QDomElement *body, QDomDocument *doc, const QString &msg, const QString &jidToSend, const QString &ujid); private: bool enabled; OptionAccessingHost* psiOptions; ActiveTabAccessingHost* activeTab; ApplicationInfoAccessingHost* applicationInfo; QColor userColor, tagColor, msgColor, quoteColor, lineColor; bool userBold,tagBold,msgBold,quoteBold,lineBold; bool userItalic,tagItalic,msgItalic,quoteItalic,lineItalic; bool userUnderline,tagUnderline,msgUnderline,quoteUnderline,lineUnderline; QString idStyle,userStyle,tagStyle,quoteStyle,linkStyle; QRegExp tagRx, regx, idRx, nickRx, linkRx; QString userLinkPattern,messageLinkPattern,altTextUser,altTextMsg,commonLinkColor; bool idAsResource,showPhoto,showAvatars,workInGroupChat; QStringList jidList_; QPointer optionsWid; QList logs_; Ui::settings ui_; JuickDownloader* downloader_; }; #endif // JUICKPLUGIN_H plugins-1.5/generic/juickplugin/juickplugin.pro000066400000000000000000000013021336777360500220630ustar00rootroot00000000000000isEmpty(PSISDK) { include(../../psiplugin.pri) } else { include($$PSISDK/plugins/psiplugin.pri) } SOURCES += \ juickplugin.cpp \ juickjidlist.cpp \ juickparser.cpp \ juickdownloader.cpp HEADERS += \ juickjidlist.h \ juickparser.h \ juickdownloader.h \ defines.h \ juickplugin.h QT += network widgets greaterThan(QT_MAJOR_VERSION, 4) { contains(psi_features, qtwebengine) { QT += webengine webenginewidgets } contains(psi_features, qtwebkit) { QT += webkit webkitwidgets } } else { contains(psi_features, qtwebkit) { QT += webkit } } FORMS += \ juickjidlist.ui \ settings.ui RESOURCES += resources.qrc plugins-1.5/generic/juickplugin/resources.qrc000066400000000000000000000001351336777360500215410ustar00rootroot00000000000000 juick.png plugins-1.5/generic/juickplugin/settings.ui000066400000000000000000000536421336777360500212320ustar00rootroot00000000000000 settings 0 0 501 417 settings Qt::Horizontal 40 20 Edit JIDs Qt::Horizontal 40 20 75 true bold Qt::AlignCenter true italic Qt::AlignCenter true underline Qt::AlignCenter color Qt::AlignCenter @username Qt::AlignCenter Qt::Horizontal 40 20 Qt::Horizontal 40 20 Qt::Horizontal 40 20 Qt::Horizontal 40 20 Qt::Horizontal 40 20 Qt::Horizontal 40 20 *tag Qt::AlignCenter Qt::Horizontal 40 20 Qt::Horizontal 40 20 Qt::Horizontal 40 20 Qt::Horizontal 40 20 Qt::Horizontal 40 20 Qt::Horizontal 40 20 #message id Qt::AlignCenter Qt::Horizontal 40 20 Qt::Horizontal 40 20 Qt::Horizontal 40 20 Qt::Horizontal 40 20 Qt::Horizontal 40 20 Qt::Horizontal 40 20 >quote Qt::AlignCenter Qt::Horizontal 40 20 Qt::Horizontal 40 20 Qt::Horizontal 40 20 Qt::Horizontal 40 20 Qt::Horizontal 40 20 Qt::Horizontal 40 20 http://link Qt::AlignCenter Qt::Horizontal 40 20 Qt::Horizontal 40 20 Qt::Horizontal 40 20 Qt::Horizontal 40 20 Qt::Horizontal 40 20 Qt::Horizontal 40 20 Use message Id as resource Show Photo Show Avatars Replaces message id with a link to this message in juick@conference.jabber.ru Qt::Vertical 20 40 Clear avatar cache <a href="http://psi-plus.com/wiki/plugins#juick_plugin">Wiki (Online)</a> true plugins-1.5/generic/messagefilterplugin/000077500000000000000000000000001336777360500205465ustar00rootroot00000000000000plugins-1.5/generic/messagefilterplugin/CMakeLists.txt000066400000000000000000000027121336777360500233100ustar00rootroot00000000000000unset(_HDRS) unset(_UIS) unset(_SRCS) unset(_RSCS) unset(PLUGIN) set( PLUGIN messagefilterplugin ) project(${PLUGIN}) cmake_minimum_required(VERSION 3.1.0) set( CMAKE_AUTOMOC TRUE ) IF( NOT WIN32 ) set( LIB_SUFFIX "" CACHE STRING "Define suffix of directory name (32/64)" ) set( PLUGINS_PATH "lib${LIB_SUFFIX}/psi-plus/plugins" CACHE STRING "Install suffix for plugins" ) ELSE() set( PLUGINS_PATH "psi-plus/plugins" CACHE STRING "Install suffix for plugins" ) ENDIF() add_definitions( -DQT_PLUGIN -DHAVE_QT5 ) if( WIN32 ) add_definitions( -DQ_OS_WIN ) endif( WIN32 ) include_directories( ${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ../../include . ) set( _SRCS messagefilter.cpp options.cpp ) set( _UIS options.ui ) set( _RSCS resources.qrc ) find_package( Qt5 COMPONENTS Widgets Xml REQUIRED ) set(QT_DEPLIBS Qt5::Widgets Qt5::Xml ) qt5_wrap_ui(UIS ${_UIS}) qt5_add_resources(RSCS ${_RSCS}) add_library( ${PLUGIN} MODULE ${_SRCS} ${UIS} ${RSCS} ) if( UNIX AND NOT( APPLE OR CYGWIN ) ) target_link_libraries( ${PLUGIN} ${QT_DEPLIBS} ) install( TARGETS ${PLUGIN} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} ) endif() if( WIN32 ) target_link_libraries( ${PLUGIN} ${QT_DEPLIBS} ) install( TARGETS ${PLUGIN} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} ) endif() plugins-1.5/generic/messagefilterplugin/changelog.txt000066400000000000000000000001261336777360500232350ustar00rootroot000000000000002015-12-18 v0.0.1 + Initial release 2017-03-31 v0.0.2 + Added full Jid conditionsplugins-1.5/generic/messagefilterplugin/list-add.png000066400000000000000000000014131336777360500227540ustar00rootroot00000000000000PNG  IHDRw=sBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<tEXtTitleOptical Drive>g iIDATHݕ=kQ3sgwIZmڤvbH-AlRXJ&(jG@%* bDLX,&kx{=W̌h_ eщKӓFD|ĵg7^gW&_U=̜ COA463Z iUG*YzacLjUUbf l=kk.#naf`#;W`f%𝕵:yƒqYѼ́D4+AIG9-Q.'*@_KPT"J$V $!MʥrkZ&PowӨYJ}q@]ԍc#lcyX4 'bd)2Fd`o.MZ /Fu7uW.Z׌w k- D`|0IENDB`plugins-1.5/generic/messagefilterplugin/list-remove.png000066400000000000000000000007251336777360500235260ustar00rootroot00000000000000PNG  IHDRw=sBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<tEXtTitleOptical Drive>g 3IDATH1N@EKp@8phr@HTTH;bcILaH»ޱĐV Ósw=H$B4y,̦g1 L $Asw:}lxL᭎\=h%$03hf1+?,OFr#CncFLyrUj˲vM&uo3+G7<`D%-2`L>h!>ʯ\D_lQ.yn:8idIENDB`plugins-1.5/generic/messagefilterplugin/messagefilter.cpp000066400000000000000000000106521336777360500241100ustar00rootroot00000000000000/* * messagefilter.cpp - plugin main class * * Copyright (C) 2015 Ivan Romanov * * 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 "messagefilter.h" #include "options.h" #include #include #include #include #include #include #include #include #include #include #include #include #ifndef HAVE_QT5 Q_EXPORT_PLUGIN(MessageFilter); #endif MessageFilter::MessageFilter() : _enabled(false) , _optionsForm(0) , _accountHost(0) , _optionHost(0) , _stanzaSending(0) , _accountInfo(0) , _rules(QList()) { } MessageFilter::~MessageFilter() { } QWidget *MessageFilter::options() { if (!_enabled) { return 0; } loadRules(); _optionsForm = new Options(_rules); _optionsForm->setOptionAccessingHost(_optionHost); return qobject_cast(_optionsForm); } bool MessageFilter::enable() { _enabled = true; loadRules(); return true; } bool MessageFilter::disable() { _enabled = false; return true; } void MessageFilter::applyOptions() { _optionsForm->saveSettings(); loadRules(); } void MessageFilter::restoreOptions() { } QPixmap MessageFilter::icon() const { return QPixmap(":/icons/messagefilter.png"); } QString MessageFilter::pluginInfo() { return tr("Author: ") + "Ivan Romanov\n" + tr("e-mail: ") + "drizt@land.ru\n\n"; } bool MessageFilter::incomingStanza(int account, const QDomElement &stanza) { Q_UNUSED(account); if (!_enabled) { return false; } if (stanza.tagName() != "message") { return false; } QString message = stanza.firstChildElement("body").text(); QString from_full = stanza.attribute("from"); QString from = from_full.split("/").takeFirst(); QString to_full = stanza.attribute("to"); QString to = to_full.split("/").takeFirst(); foreach (const Rule &rule, _rules) { bool match = true; foreach (const Condition &condition, rule.conditions) { QString val; switch (condition.type) { case From: val = from; break; case To: val = to; break; case FromFull: val = from_full; break; case ToFull: val = to_full; break; case Message: val = message; break; } switch (condition.comparison) { case Equal: if (val != condition.text) match = false; break; case NotEqual: if (val == condition.text) match = false; break; case Contains: if (!val.contains(QRegExp(condition.text))) match = false; break; case NotContains: if (val.contains(QRegExp(condition.text))) match = false; break; } if (!match) break; } if (match) return !rule.showMessage; } return false; } void MessageFilter::loadRules() { if (!_optionHost || !_enabled) return; _rules.clear(); int rulesSize = _optionHost->getPluginOption("rules.size", 0).toInt(); for (int i = 0; i < rulesSize; ++i) { QString optionName = QString("rules.l%1.").arg(i); Rule rule; rule.name = _optionHost->getPluginOption(optionName + "name").toString(); rule.showMessage = _optionHost->getPluginOption(optionName + "show-message").toBool(); int conditionsSize = _optionHost->getPluginOption(optionName + "conditions.size").toInt(); for (int j = 0; j < conditionsSize; ++j) { QString optionName1 = QString("%1conditions.l%2.").arg(optionName).arg(j); Condition condition; condition.type = static_cast(_optionHost->getPluginOption(optionName1 + "type").toInt()); condition.comparison = static_cast(_optionHost->getPluginOption(optionName1 + "comparison").toInt()); condition.text = _optionHost->getPluginOption(optionName1 + "text").toString(); rule.conditions << condition; } _rules << rule; } } plugins-1.5/generic/messagefilterplugin/messagefilter.h000066400000000000000000000060331336777360500235530ustar00rootroot00000000000000/* * messagefilter.h - plugin main class * * Copyright (C) 2015 Ivan Romanov * * 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. */ #ifndef MESSAGEFILTER_H #define MESSAGEFILTER_H #include "options.h" #include #include #include #include #include #include #include #include #include #include #include class Options; class QMenu; class MessageFilter : public QObject , public PsiPlugin , public PluginInfoProvider , public StanzaFilter , public PsiAccountController , public OptionAccessor , public StanzaSender , public AccountInfoAccessor { Q_OBJECT #ifdef HAVE_QT5 Q_PLUGIN_METADATA(IID "com.psi-plus.MessageFilter") #endif Q_INTERFACES(PsiPlugin PluginInfoProvider StanzaFilter PsiAccountController OptionAccessor StanzaSender AccountInfoAccessor) public: MessageFilter(); ~MessageFilter(); // from PsiPlugin QString name() const { return "Message Filter Plugin"; } QString shortName() const { return "messagefilter"; } QString version() const { return "0.0.2"; } QWidget *options(); bool enable(); bool disable(); void applyOptions(); void restoreOptions(); QPixmap icon() const; // from PluginInfoProvider QString pluginInfo(); // from StanzaSender void setStanzaSendingHost(StanzaSendingHost *host) { _stanzaSending = host; } // from StanzaFilter bool incomingStanza(int account, const QDomElement &stanza); bool outgoingStanza(int /*account*/, QDomElement &/*stanza*/) { return false; } // from PsiAccountController void setPsiAccountControllingHost(PsiAccountControllingHost *host) { _accountHost = host; } // from OptionAccessor void setOptionAccessingHost(OptionAccessingHost *host) { _optionHost = host; } void optionChanged(const QString &/*option*/) { } // from AccountInfoAccessor void setAccountInfoAccessingHost(AccountInfoAccessingHost* host) { _accountInfo = host; } private: void loadRules(); bool _enabled; Options *_optionsForm; PsiAccountControllingHost *_accountHost; OptionAccessingHost *_optionHost; StanzaSendingHost *_stanzaSending; AccountInfoAccessingHost *_accountInfo; QList _rules; }; #endif // MESSAGEFILTER_H plugins-1.5/generic/messagefilterplugin/messagefilter.png000066400000000000000000000027761336777360500241220ustar00rootroot00000000000000PNG  IHDR szzIDATx^Ŗm\W9wf2;b6o˶il!K!*KAlSBA| (X"~P_HKƱͦIm֍Ml6MvgfyΎ u`?~<7{gDU} 1f !UNtRDQeWs5:7~) TcpsN: *`T7B1sŵ - җO'%)?w_pfLARLT(P,'e93(&J|M0l;ܺV#}@#PvqWMLeC)\*PaC あ(jHk\XYlyf@TI80}s!NjE+JpTGh^+Dq}[62P(st^QP;[="U qR%uӔ4UUDbp[s-RuYm2rnb&_:p]K@@Z0X $)'NIR{|Ǿw^,gwc@arph"aJ x&Jf(J)8 (CDK@ӥZ7/_'wRf͔Ha1RĐR]^" 5)KރoPXUX~G?\l-ώ^AjHLxK/TO2 byϝTqN !0ɫ#y1 ]IU8q~ /pq ]ֶ:tF<7"4K㫄w &qCHϗcViA6x$bۼ>?nRtoٱ)"6,;P#\:k3==@ ?|txϮLJ:,(Wrx?vnG8|Y~\nT }_ * * 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 "options.h" #include "ui_options.h" #include "optionaccessinghost.h" #include #include #include Options::Options(const QList &rules, QWidget *parent) : QWidget(parent) , ui(new Ui::Options) , _optionHost(0) , _rules(rules) , _currentRule(-1) { ui->setupUi(this); ui->btAddRule->setIcon(QIcon::fromTheme("list-add", QIcon(":/icons/list-add.png"))); ui->btRemoveRule->setIcon(QIcon::fromTheme("list-remove", QIcon(":/icons/list-remove.png"))); ui->btUpRule->setIcon(qApp->style()->standardIcon(QStyle::SP_ArrowUp)); ui->btDownRule->setIcon(qApp->style()->standardIcon(QStyle::SP_ArrowDown)); ui->btAddCondition->setIcon(QIcon::fromTheme("list-add", QIcon(":/icons/list-add.png"))); ui->btRemoveCondition->setIcon(QIcon::fromTheme("list-remove", QIcon(":/icons/list-remove.png"))); ui->btUpCondition->setIcon(qApp->style()->standardIcon(QStyle::SP_ArrowUp)); ui->btDownCondition->setIcon(qApp->style()->standardIcon(QStyle::SP_ArrowDown)); ui->wRulePane->setEnabled(false); updateRuleButtons(); updateConditionButtons(); foreach (const Rule &rule, _rules) { ui->lwRules->addItem(rule.name); } } Options::~Options() { delete ui; } void Options::update() { } void Options::saveSettings() { if (_currentRule >= 0) { _rules[_currentRule].name = ui->lneRuleName->text(); _rules[_currentRule].showMessage = ui->chkShowMessage->isChecked(); for (int i = 0; i < ui->twConditions->rowCount(); ++i) saveCondition(_currentRule, i); } _optionHost->setPluginOption("rules.size", _rules.size()); for (int i = 0; i < _rules.size(); ++i) { QString optionName = QString("rules.l%1.").arg(i); Rule rule = _rules.at(i); _optionHost->setPluginOption(optionName + "name", rule.name); _optionHost->setPluginOption(optionName + "show-message", rule.showMessage); _optionHost->setPluginOption(optionName + "conditions.size", rule.conditions.size()); for (int j = 0; j < rule.conditions.size(); ++j) { Condition condition = rule.conditions.at(j); QString optionName1 = QString("%1conditions.l%2.").arg(optionName).arg(j); _optionHost->setPluginOption(optionName1 + "type", static_cast(condition.type)); _optionHost->setPluginOption(optionName1 + "comparison", static_cast(condition.comparison)); _optionHost->setPluginOption(optionName1 + "text", condition.text); } } } void Options::addRule() { ui->lwRules->addItem("New rule"); Rule rule; rule.name = "New rule"; rule.showMessage = false; _rules << rule; ui->lwRules->setCurrentRow(ui->lwRules->count() - 1); addCondition(); } void Options::removeRule() { int rule = ui->lwRules->currentRow(); ui->lwRules->setCurrentRow(-1); _rules.removeAt(rule); delete ui->lwRules->takeItem(rule); ui->lwRules->setCurrentRow(rule == _rules.size() ? -1 : rule); } void Options::upRule() { int rule = ui->lwRules->currentRow(); _rules.swap(rule, rule - 1); QListWidgetItem *item = ui->lwRules->takeItem(rule); ui->lwRules->insertItem(rule - 1, item); ui->lwRules->setCurrentRow(rule - 1); } void Options::downRule() { int rule = ui->lwRules->currentRow(); _rules.swap(rule, rule + 1); QListWidgetItem *item = ui->lwRules->takeItem(rule); ui->lwRules->insertItem(rule + 1, item); ui->lwRules->setCurrentRow(rule + 1); } void Options::updateRuleButtons() { if (ui->lwRules->currentRow() < 0) { ui->btRemoveRule->setEnabled(false); ui->btUpRule->setEnabled(false); ui->btDownRule->setEnabled(false); } else { ui->btRemoveRule->setEnabled(true); if (ui->lwRules->currentRow() > 0) ui->btUpRule->setEnabled(true); else ui->btUpRule->setEnabled(false); if (ui->lwRules->currentRow() < ui->lwRules->count() - 1) ui->btDownRule->setEnabled(true); else ui->btDownRule->setEnabled(false); } } void Options::addCondition() { Condition condition; condition.type = From; condition.comparison = Equal; condition.text = ""; _rules[ui->lwRules->currentRow()].conditions << condition; setRulePane(ui->lwRules->currentRow()); } void Options::removeCondition() { int rule = ui->lwRules->currentRow(); int condition = ui->twConditions->currentRow(); _rules[rule].conditions.removeAt(condition); ui->twConditions->removeRow(condition); updateConditionButtons(); } void Options::upCondition() { int rule = ui->lwRules->currentRow(); int condition = ui->twConditions->currentRow(); int conditionColumn = ui->twConditions->currentColumn(); saveCondition(rule, condition - 1); saveCondition(rule, condition); _rules[rule].conditions.swap(condition, condition - 1); fillCondition(condition - 1); fillCondition(condition); ui->twConditions->setCurrentCell(condition - 1, conditionColumn); } void Options::downCondition() { int rule = ui->lwRules->currentRow(); int condition = ui->twConditions->currentRow(); int conditionColumn = ui->twConditions->currentColumn(); saveCondition(rule, condition); saveCondition(rule, condition + 1); _rules[rule].conditions.swap(condition, condition + 1); fillCondition(condition); fillCondition(condition + 1); ui->twConditions->setCurrentCell(condition + 1, conditionColumn); } void Options::updateConditionButtons() { if (ui->twConditions->currentRow() < 0) { ui->btRemoveCondition->setEnabled(false); ui->btUpCondition->setEnabled(false); ui->btDownCondition->setEnabled(false); } else { ui->btRemoveCondition->setEnabled(true); if (ui->twConditions->currentRow() > 0) ui->btUpCondition->setEnabled(true); else ui->btUpCondition->setEnabled(false); if (ui->twConditions->currentRow() < ui->twConditions->rowCount() - 1) ui->btDownCondition->setEnabled(true); else ui->btDownCondition->setEnabled(false); } } void Options::updateRuleName(const QString &name) { ui->lwRules->currentItem()->setText(name); _rules[ui->lwRules->currentRow()].name = name; } void Options::setRulePane(int row) { if (_currentRule >= 0) { _rules[_currentRule].name = ui->lneRuleName->text(); _rules[_currentRule].showMessage = ui->chkShowMessage->isChecked(); for (int i = 0; i < ui->twConditions->rowCount(); ++i) saveCondition(_currentRule, i); } qDebug() << "New current row" << row; _currentRule = row; clearConditionsTable(); if (row >= 0 && row < _rules.size()) { ui->wRulePane->setEnabled(true); Rule rule = _rules[row]; ui->lneRuleName->setText(rule.name); ui->chkShowMessage->setChecked(rule.showMessage); QList conditions = rule.conditions; for (int i = 0; i < conditions.size(); ++i) { ui->twConditions->insertRow(i); QComboBox *comboBox = new QComboBox(); comboBox->addItem("From jid"); comboBox->addItem("To jid"); comboBox->addItem("From full jid"); comboBox->addItem("To full jid"); comboBox->addItem("Message"); comboBox->setSizeAdjustPolicy(QComboBox::AdjustToContents); ui->twConditions->setCellWidget(i, 0, comboBox); connect(comboBox, SIGNAL(currentIndexChanged(int)), SLOT(hack())); comboBox = new QComboBox(); comboBox->addItem("equal"); comboBox->addItem("not equal"); comboBox->addItem("contains"); comboBox->addItem("not contains"); comboBox->setSizeAdjustPolicy(QComboBox::AdjustToContents); ui->twConditions->setCellWidget(i, 1, comboBox); connect(comboBox, SIGNAL(currentIndexChanged(int)), SLOT(hack())); QLineEdit *lineEdit = new QLineEdit(); lineEdit->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); ui->twConditions->setCellWidget(i, 2, lineEdit); connect(lineEdit, SIGNAL(textEdited(QString)), SLOT(hack())); fillCondition(i); } #if QT_VERSION > QT_VERSION_CHECK(5, 0, 0) ui->twConditions->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); #else ui->twConditions->horizontalHeader()->setResizeMode(QHeaderView::ResizeToContents); #endif } else { ui->wRulePane->setEnabled(false); ui->lneRuleName->setText(""); ui->chkShowMessage->setChecked(false); } updateRuleButtons(); updateConditionButtons(); } // Hack to enable Apply button void Options::hack() { ui->chkShowMessage->toggle(); ui->chkShowMessage->toggle(); } void Options::clearConditionsTable() { while (ui->twConditions->rowCount()) ui->twConditions->removeRow(0); } void Options::fillCondition(int row) { int rule = ui->lwRules->currentRow(); qobject_cast(ui->twConditions->cellWidget(row, 0))->setCurrentIndex(_rules.at(rule).conditions.at(row).type); qobject_cast(ui->twConditions->cellWidget(row, 1))->setCurrentIndex(_rules.at(rule).conditions.at(row).comparison); qobject_cast(ui->twConditions->cellWidget(row, 2))->setText(_rules.at(rule).conditions.at(row).text); } void Options::saveCondition(int rule, int row) { _rules[rule].conditions[row].type = static_cast(qobject_cast(ui->twConditions->cellWidget(row, 0))->currentIndex()); _rules[rule].conditions[row].comparison = static_cast(qobject_cast(ui->twConditions->cellWidget(row, 1))->currentIndex()); _rules[rule].conditions[row].text = qobject_cast(ui->twConditions->cellWidget(row, 2))->text(); } plugins-1.5/generic/messagefilterplugin/options.h000066400000000000000000000040151336777360500224120ustar00rootroot00000000000000/* * options.h - plugin widget * * Copyright (C) 2015 Ivan Romanov * * 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. */ #ifndef OPTIONS_H #define OPTIONS_H #include #include #include class OptionAccessingHost; namespace Ui { class Options; } enum ConditionType { From, To, FromFull, ToFull, Message }; enum Comparison { Equal, NotEqual, Contains, NotContains }; struct Condition { ConditionType type; Comparison comparison; QString text; }; struct Rule { QString name; bool showMessage; QList conditions; }; class Options : public QWidget { Q_OBJECT public: explicit Options(const QList &rules, QWidget *parent = 0); ~Options(); void update(); void setOptionAccessingHost(OptionAccessingHost* host) { _optionHost = host; } void saveSettings(); public slots: void addRule(); void removeRule(); void upRule(); void downRule(); void updateRuleButtons(); void addCondition(); void removeCondition(); void upCondition(); void downCondition(); void updateConditionButtons(); void updateRuleName(const QString &name); void setRulePane(int row); void hack(); private: void clearConditionsTable(); void fillCondition(int row); void saveCondition(int rule, int row); Ui::Options *ui; OptionAccessingHost* _optionHost; QList _rules; int _currentRule; }; #endif // OPTIONS_H plugins-1.5/generic/messagefilterplugin/options.ui000066400000000000000000000307041336777360500226040ustar00rootroot00000000000000 Options 0 0 993 558 Form Rules ... ... ... ... Qt::Horizontal QSizePolicy::Preferred 69 20 0 0 Name Conditions ... ... ... ... Qt::Horizontal 42 20 false 3 false true Show message if it satisfies the rule lneRuleName textEdited(QString) Options updateRuleName(QString) 388 31 994 22 btAddRule clicked() Options addRule() 44 64 -1 55 btRemoveRule clicked() Options removeRule() 87 67 2 110 btUpRule clicked() Options upRule() 121 64 0 157 btDownRule clicked() Options downRule() 170 57 0 224 btAddCondition clicked() Options addCondition() 329 112 995 89 btRemoveCondition clicked() Options removeCondition() 360 121 991 159 btUpCondition clicked() Options upCondition() 408 120 990 217 btDownCondition clicked() Options downCondition() 460 108 991 275 lwRules currentRowChanged(int) Options setRulePane(int) 192 276 992 535 lwRules currentRowChanged(int) Options updateRuleButtons() 191 300 993 489 twConditions currentCellChanged(int,int,int,int) Options updateConditionButtons() 516 355 993 379 btAddRule clicked() Options hack() 42 69 281 5 btRemoveRule clicked() Options hack() 74 60 343 4 btUpRule clicked() Options hack() 110 53 420 3 btDownRule clicked() Options hack() 160 53 495 1 btAddCondition clicked() Options hack() 316 118 639 0 btRemoveCondition clicked() Options hack() 376 103 735 2 btUpCondition clicked() Options hack() 394 112 804 -3 btDownCondition clicked() Options hack() 450 113 876 4 addRule() removeRule() upRule() downRule() addCondition() removeCondition() upCondition() downCondition() updateRuleName(QString) setRulePane(int) updateRuleButtons() updateConditionButtons() hack() plugins-1.5/generic/messagefilterplugin/resources.qrc000066400000000000000000000002541336777360500232700ustar00rootroot00000000000000 list-add.png list-remove.png messagefilter.png plugins-1.5/generic/otrplugin/000077500000000000000000000000001336777360500165205ustar00rootroot00000000000000plugins-1.5/generic/otrplugin/CMakeLists.txt000066400000000000000000000057201336777360500212640ustar00rootroot00000000000000unset(_HDRS) unset(_UIS) unset(_SRCS) unset(_RSCS) unset(PLUGIN) set( PLUGIN otrplugin ) project(${PLUGIN}) cmake_minimum_required(VERSION 3.1.0) set( CMAKE_AUTOMOC TRUE ) IF( NOT WIN32 ) set( LIB_SUFFIX "" CACHE STRING "Define suffix of directory name (32/64)" ) set( PLUGINS_PATH "lib${LIB_SUFFIX}/psi-plus/plugins" CACHE STRING "Install suffix for plugins" ) ELSE() set( PLUGINS_PATH "psi-plus/plugins" CACHE STRING "Install suffix for plugins" ) ENDIF() IF( ${PROJECT_SOURCE_DIR} ) set( CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH}" "${PROJECT_SOURCE_DIR}/cmake/modules" ) ELSE() set( CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH}" "${CMAKE_CURRENT_SOURCE_DIR}/../../../../cmake/modules") ENDIF() IF( WIN32 ) if(NOT LIBGCRYPT_ROOT) set( LIBGCRYPT_ROOT "C:\\build\\psibuild\\psideps\\libgcrypt\\i386" CACHE STRING "Path to libgcrypt library" ) endif() if(NOT LIBGPGERROR_ROOT) set( LIBGPGERROR_ROOT "C:\\build\\psibuild\\psideps\\libgpg-error\\i386" CACHE STRING "Path to libgpg-error library" ) endif() if(NOT LIBOTR_ROOT) set( LIBOTR_ROOT "C:\\build\\psibuild\\psideps\\libotr\\i386" CACHE STRING "Path to libotr library" ) endif() if(NOT LIBGCRYPT_ROOT) set( LIBTIDY_ROOT "C:\\build\\psibuild\\psideps\\libtidy\\i386" CACHE STRING "Path to libtidy library" ) endif() add_definitions( -DQ_WS_WIN ) ENDIF() find_package( LibGcrypt REQUIRED ) find_package( LibOtr REQUIRED ) find_package( LibTidy REQUIRED ) find_package( LibGpgError REQUIRED ) add_definitions( -DQT_PLUGIN -DHAVE_QT5 ${LIBOTR_DEFINITIONS} ${LIBTIDY_DEFINITIONS} ${LIBGCRYPT_DEFINITIONS} ${LIBGPGERROR_DEFINITIONS} ) #dirty hack for windows IF( WIN32 ) set(TIDY_INCLUDES ${LIBTIDY_INCLUDE_DIR}/.. ) ENDIF() # include_directories( ${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${LIBOTR_INCLUDE_DIR} ${LIBTIDY_INCLUDE_DIR} ${LIBGCRYPT_INCLUDE_DIR} ${LIBGPGERROR_INCLUDE_DIR} ${TIDY_INCLUDES} ../../include ./src . ) set( _HDRS src/psiotrplugin.h src/otrmessaging.h src/otrinternal.h src/psiotrconfig.h src/psiotrclosure.h src/htmltidy.h src/otrlextensions.h ) set( _SRCS src/psiotrplugin.cpp src/otrmessaging.cpp src/otrinternal.cpp src/psiotrconfig.cpp src/psiotrclosure.cpp src/htmltidy.cpp src/otrlextensions.c ) set( _RSCS ${PLUGIN}.qrc ) find_package( Qt5 COMPONENTS Widgets Xml Concurrent REQUIRED ) set(QT_DEPLIBS Qt5::Widgets Qt5::Xml Qt5::Concurrent ) qt5_add_resources(RSCS ${_RSCS}) add_library( ${PLUGIN} MODULE ${_SRCS} ${UIS} ${RSCS} ) target_link_libraries( ${PLUGIN} ${QT_DEPLIBS} ${LIBOTR_LIBRARY} ${LIBTIDY_LIBRARY} ${LIBGCRYPT_LIBRARY} ${LIBGPGERROR_LIBRARY} ) if( UNIX AND NOT( APPLE OR CYGWIN ) ) install( TARGETS ${PLUGIN} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} ) endif() if( WIN32 ) install( TARGETS ${PLUGIN} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} ) endif() plugins-1.5/generic/otrplugin/COPYING000066400000000000000000000431031336777360500175540ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 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. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. plugins-1.5/generic/otrplugin/INSTALL000066400000000000000000000034321336777360500175530ustar00rootroot00000000000000Off-the-Record messaging plugin for Psi The plugin currently only runs with Psi+ (aka Psi-dev). If you don't have Psi+ installed on your computer, you can get it from http://code.google.com/p/psi-dev/ To compile the plugin you need to have installed the following libraries: - Qt4 or Qt5 (http://qt.digia.com/) - libotr2 (http://www.cypherpunks.ca/otr/) - TidyLib (http://tidy.sourceforge.net/) Perform the following steps: - Get Psi+ and apply the patches to the latest sources of Psi. Therefor you can use one of the scripts provided by Psi+. - Make the Psi/Psi+ include files available to the plugin. To achieve this, copy the psi-otr-X.X/ directory to the src/plugins/generic/ directory of your patched Psi/Psi+ source tree. - change to the psi-otr-X.X/ directory and run qmake to generate a Makefile: $ qmake - Then run make to compile everything: $ make The resulting binary is libotrplugin.so or otrplugin.dll. This file should be copied to the plugins subdirectory of the Psi+ resources: * /usr/lib/psi-plus/plugins/ or /usr/local/lib/psi-plus/plugins/ or ~/.local/share/psi+/plugins on Linux-based and FreeBSD systems * C:\Program Files\Psi+\plugins\ or %PSI_PLUS_DIRECTORY%\plugins\ on MS Windows systems Build and installation in Mac OS X is possible as well, but it requires some magic. If you have successfully installed OTR plugin, do the following steps when you run Psi+ for the first time: - Enable the plugin in the 'Options'-->'Plugins' dialog and click on 'Apply'. - Set the OTR policy in the 'Config' Tab of the plugin options. In most cases 'Automatically start private messaging' should be a good choice. - There is no button etc. to generate your private key. It will be generated when it's needed. I.e. when you start your first private conversation. plugins-1.5/generic/otrplugin/README000066400000000000000000000041141336777360500174000ustar00rootroot00000000000000Off-The-Record-Messaging plugin for Psi+ This is a Off-The-Record-Messaging plugin for the Psi+ instant messenger. Psi+ (aka Psi-dev) is a collection of patches for Psi. It is available from http://psi-dev.googlecode.com/ See the file INSTALL for instructions how to build this plugin. Please note that the plugin may be instable and security is not guaranteed. See http://www.cypherpunks.ca/otr/ for more information about OTR. TODO * Configure OTR policy per contact * Documentation KNOWN ISSUES * Currently only works for top priority resources * System messages are only displayed for existing chat windows, might be displayed in wrong order (needs to be fixed in Psi+) THANKS Thanks to Prof. Dr. Ruediger Weis for supporting this work. Thanks to all people who sent patches. Especially to specThor for UTF8 patches, Hannes Mehnert for chatdialog. Rolf Wuerdemann for configure patch and several bugfixes. Thanks to wadealer from Psi+ for adapting and including the patches into Psi+. Thanks to Boris Pek for porting to libotr >= 4.0.0. LICENSE The Off-the-Record Messaging plugin for Psi+ is covered by the following (GPL) license: Off-the-Record Messaging plugin for Psi+ Copyright (C) 2007-2011 Timo Engel (timo-e@freenet.de) 2011-2012 Florian Fieber This program is free software; you can redistribute it and/or modify it under the terms of version 2 of the GNU General Public License as published by the Free Software Foundation. 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, see . CONTACT http://public.beuth-hochschule.de/~s30935/ Timo Engel Psi+ developers can be contacted via XMPP conference: psi-dev@conference.jabber.ru plugins-1.5/generic/otrplugin/changelog.txt000066400000000000000000000111261336777360500212110ustar00rootroot000000000000002017-10-04 v1.0.3 ValdikSS * Do not handle OTR events in MUC * Send OTR messages with proper message hints and disabled carbon copies * Ignore incoming carbon-copied OTR messages 2014-03-26 v1.0.2 tehnick * Fix a queue of events for modal dialogs. * Fix possible memory leak after disabling of the plugin. 2014-03-15 v1.0.1 tehnick * Use a queue of events for some modal dialogs. They will not be shown immediately; user should trigger them manually. 2014-03-07 v1.0.0 tehnick * Minimize the number of modal dialogs: use other ways for notifying user (system messages in chat). * Small code improvements. [Thanks to Michael Kurz] 2014-01-09 v0.9.9 tehnick * Minimize the number of modal dialogs: use other ways for notifying user (system messages in chat). * Do not block program windows during generating of private key. 2014-01-06 v0.9.8 tehnick * Fix OTRv3 support: added limited support of instance tags. Previous temporary solution is not needed anymore. (Affects only build with libotr 4.x.) 2013-10-14 v0.9.7 tehnick * Fix problem of initialization of private conversation when both sides use libotr 4.x. Protocol OTRv2 is forced. This is temporary solution. * Fix tiny memory leak when libotr 4.x is used. * Tiny improvement in endSession() function when libotr 4.x is used. * Better error handling when libotr 4.x is used. 2013-08-13 v0.9.6 taurus * Add function returning plugin's icon. * Fix build with Qt 5.x. 2013-06-30 v0.9.5 tehnick * Add support of libotr >= 4.0.0. 2012-04-04 v0.9.5pre * Ignore internal messages, report state changes and notifications via system messages * The authentication dialog now differs between 'question and answer' and 'shared secret', enabling mutual authentication for the latter. * Add plugin info 2011-11-17 v0.9.4 * Add authentication via Socialist Millionaires' Protocol * Fix escaping of plaintext OTR messages * Ignore incoming messages of type "error" * Fix OtrInternal::account_name() * Use radio boxes for policy settings * Add option to close a session when a contact goes offline * Enable sorting for fingerprint and key table 2011-08-22 v0.9.3 * Fix fetching private keys * Finish session when forgetting a fingerprint * Enforce Unix line feeds * Don't quote non-breaking spaces * Use JID instead of account ID in libotr messages * Remove HTML from outgoing libotr messages * Add key generation and deletion to options * Add context menu to fingerprint and private key widget * Fix file path encoding for non-UTF-8 systems v0.9.2 * Encode strings as UTF-8 before passing them to libotr * Fix fingerprint verification and deletion * Only handle decrypted messages as HTML if they look like HTML * Escape XML entities before encrypting * Change options namespace and short name * Identify accounts by ID, not by index * Output accounts by name * Auto-resize table columns in options * Don't send empty messages * Handle multiple selections in the fingerprint widget, fix selections made without mouse v0.9.1 * OTR data is now stored in the data directory of the current profile * Fix OTR for private messages * Fix fingerprint verification * Add indication for unverified sessions * New Icons * Improved HTML to plaintext conversion * Make strings translatable v0.9 * update to Psi+ revision 3961. * fix html tidying for incoming messages. * rework message boxes and button in chatdialog. v0.8 * update to Psi+ revision 3763. * Html is removed in outgoing encrypted messages. v0.7 * Use icons for otr button. * Fixed update of message state on button. * Default policy is now 'enabled'. * Problem related to key generation fixed. * Enabling and disabling of plugin fixed. * Adapted to Psi+ interface changes. v0.6 * adapt to Psi+ plugin interface * use HtmlTidy for invalid XHTML in encrypted messages * changed handling of callbacks * several bugfixes v0.5 * adapted to Psi 0.13 * ignore plugin for groupchat messages * repaired window shown during key generation * enable "End private Conversation" button in "finish" state. * add --enable-plugins to Psi configure script * several bugfixes and code cleanups v0.4 * menu in chatdialog to start OTR session, etc. * incoming messages with invalid html markup were discarded in previous versions. * problem with 'status' information of known fingerprints resolved v0.3 * character encoding in tagged-plaintext-messages * send otr-disconnect message when going offline * resolved problems with configuration widget v0.2 * character encoding in encrypted messages plugins-1.5/generic/otrplugin/otrplugin.pro000066400000000000000000000016471336777360500212750ustar00rootroot00000000000000isEmpty(PSISDK) { include(../../psiplugin.pri) } else { include($$PSISDK/plugins/psiplugin.pri) } win32-msvc* { # consider compiling https://github.com/Ri0n/libotr/tree/master/vs2015 LIBS += -lotr -ltidy } else { LIBS += -lotr -ltidy -lgcrypt -lgpg-error } !win32:!exists(/usr/include/tidybuffio.h):!exists(/usr/include/tidy/tidybuffio.h) { DEFINES += LEGACY_TIDY } RESOURCES = otrplugin.qrc unix { INCLUDEPATH += /usr/include/tidy } greaterThan(QT_MAJOR_VERSION, 4) { QT += concurrent } HEADERS += src/psiotrplugin.h HEADERS += src/otrmessaging.h HEADERS += src/otrinternal.h HEADERS += src/psiotrconfig.h HEADERS += src/psiotrclosure.h HEADERS += src/htmltidy.h HEADERS += src/otrlextensions.h SOURCES += src/psiotrplugin.cpp SOURCES += src/otrmessaging.cpp SOURCES += src/otrinternal.cpp SOURCES += src/psiotrconfig.cpp SOURCES += src/psiotrclosure.cpp SOURCES += src/htmltidy.cpp SOURCES += src/otrlextensions.c plugins-1.5/generic/otrplugin/otrplugin.qrc000066400000000000000000000004601336777360500212520ustar00rootroot00000000000000 resources/otr_yes.png resources/otr_no.png resources/otr_unverified.png plugins-1.5/generic/otrplugin/resources/000077500000000000000000000000001336777360500205325ustar00rootroot00000000000000plugins-1.5/generic/otrplugin/resources/otr_no.png000066400000000000000000000007021336777360500225370ustar00rootroot00000000000000PNG  IHDR7sRGB|IDAT(KTq;_aVEAR AcR[CQHBџPsP98d868Cp-a?0\4}>"vuJc#\mXqޅ'8|ֱ\j@\=04>65_Rs`}[N IgǧQkkd3ۦ;Lfk_f:mCTߜ*@FH(@CD))y!Bb>?fj7&y9cg>Xhffɢ~vHTALY^it-*I$2 djRUn8irqwM.UeÃ.ەJRT&I仵^utA /[m?+1@IENDB`plugins-1.5/generic/otrplugin/resources/otr_unverified.png000066400000000000000000000015321336777360500242650ustar00rootroot00000000000000PNG  IHDRasRGBIDAT8ohusvsVLrκhi20BdbJ|QDEs6)td fs Eƴcmmn=ϯ' |c߾cܷ3Ado'H3'NThChussgeRHLkl6Bm= lF= MůRwcc}DT(g,6baӨX.7V~ڷEb|{-)in[66lܺikdJ}v.q3]-s>Q~v{uxawoqKd \1N}7G-mũ:qxPo]O#aԜJFcJsj !ZTGRZy|[^ [VxF]G(bı ]"lߌRRi _a\D'xKJK]4/ OG2װ%R2'dtbfKsDW`T_0VMDقLRlb f/h$xej 75eJ(lOZBZӥC% E #3ey96=aBA . Hq82=8sբaEV6k vnmgIrҚܾHpOx*c_6|!ݼQyZm|8-{vBf/ S/NN k*o.-]7λ@>|fopkEzZwM+FGAv۵ҙt:[YwNJIn<>0\:3iƦ|hD6+`~XC*šg|C/<\kbO֢Tшz-`#SI>H3;4?A:RIuEAݕ   D f\ kQ*ו]PA 9 yKzd-8׿J 3%x \ ~C&xgh+$0؎tUrvjAL Bhkyu\t]S4IENDB`plugins-1.5/generic/otrplugin/src/000077500000000000000000000000001336777360500173075ustar00rootroot00000000000000plugins-1.5/generic/otrplugin/src/htmltidy.cpp000066400000000000000000000072631336777360500216610ustar00rootroot00000000000000/* * htmltidy.cpp - Tidy html with libtidy * * Off-the-Record Messaging plugin for Psi+ * Copyright (C) 2007-2011 Timo Engel (timo-e@freenet.de) * 2011 Florian Fieber * * 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, see . * */ #include "htmltidy.h" #include #include #include #include //----------------------------------------------------------------------------- HtmlTidy::HtmlTidy(const QString& html) : m_tidyDoc(tidyCreate()), m_errorOutput(), m_output(), m_input(html) { tidyOptSetBool (m_tidyDoc, TidyXmlOut, yes); tidyOptSetValue(m_tidyDoc, TidyCharEncoding, "utf8"); tidyOptSetInt (m_tidyDoc, TidyNewline, TidyLF); tidyOptSetBool (m_tidyDoc, TidyQuoteNbsp, no); tidyOptSetBool (m_tidyDoc, TidyForceOutput, yes); tidySetErrorBuffer(m_tidyDoc, &m_errorOutput); tidyParseString(m_tidyDoc, m_input.toUtf8().data()); tidyCleanAndRepair(m_tidyDoc); } //----------------------------------------------------------------------------- HtmlTidy::~HtmlTidy() { tidyRelease(m_tidyDoc); tidyBufFree(&m_errorOutput); } //----------------------------------------------------------------------------- QString HtmlTidy::writeOutput() { m_output.clear(); TidyOutputSink sink; #ifdef Q_OS_WIN sink.putByte = callPutByte; #else sink.putByte = putByte; #endif sink.sinkData = this; tidySaveSink(m_tidyDoc, &sink); return QString::fromUtf8(m_output); } //----------------------------------------------------------------------------- QString HtmlTidy::output() { QDomDocument document; QDomElement body = output(document); QString s; QTextStream ts(&s) ; body.save(ts, 0); return s; } //----------------------------------------------------------------------------- QDomElement HtmlTidy::output(QDomDocument& document) { int errorLine = 0; int errorColumn = 0; QString errorText; QString html = writeOutput(); if (!document.setContent(html, true, &errorText, &errorLine, &errorColumn)) { qWarning() << "---- parsing error:\n" << html << "\n----\n" << errorText << " line:" << errorLine << " column:" << errorColumn; QDomElement domBody = document.createElement("body"); domBody.appendChild(document.createTextNode(m_input)); return domBody; } return document.documentElement().firstChildElement("body"); } //----------------------------------------------------------------------------- void HtmlTidy::putByte(void* sinkData, byte bt) { static_cast(sinkData)->putByte(bt); } //----------------------------------------------------------------------------- #ifdef Q_OS_WIN void TIDY_CALL HtmlTidy::callPutByte(void* sinkData, byte bt) { static_cast(sinkData)->putByte(sinkData, bt); } //----------------------------------------------------------------------------- #endif void HtmlTidy::putByte(byte bt) { m_output.append(bt); } //----------------------------------------------------------------------------- plugins-1.5/generic/otrplugin/src/htmltidy.h000066400000000000000000000032131336777360500213150ustar00rootroot00000000000000/* * htmltidy.h - Tidy html with libtidy * * Off-the-Record Messaging plugin for Psi+ * Copyright (C) 2007-2011 Timo Engel (timo-e@freenet.de) * 2011 Florian Fieber * * 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, see . * */ #ifndef HTMLTIDY_H_ #define HTMLTIDY_H_ #include #include #include #ifdef LEGACY_TIDY # ifdef Q_OS_WIN # include # include # else # include # include # endif #else # include # include #endif class QDomDocument; class QDomElement; class HtmlTidy { public: HtmlTidy(const QString& html); ~HtmlTidy(); QString output(); QDomElement output(QDomDocument& document); static void putByte(void* sinkData, byte bt); #ifdef Q_OS_WIN static void TIDY_CALL callPutByte(void* sinkData, byte bt); #endif protected: void putByte(byte bt); QString writeOutput(); private: TidyDoc m_tidyDoc; TidyBuffer m_errorOutput; QByteArray m_output; QString m_input; }; #endif plugins-1.5/generic/otrplugin/src/otrinternal.cpp000066400000000000000000001316201336777360500223570ustar00rootroot00000000000000/* * otrinternal.cpp - Manages the OTR connection * * Off-the-Record Messaging plugin for Psi+ * Copyright (C) 2007-2011 Timo Engel (timo-e@freenet.de) * 2011-2012 Florian Fieber * 2013 Georg Rudoy * 2013-2014 Boris Pek (tehnick-8@mail.ru) * * This program was originally written as part of a diplom thesis * advised by Prof. Dr. Ruediger Weis (PST Labor) * at the Technical University of Applied Sciences Berlin. * * 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, see . * */ #include "otrinternal.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include //----------------------------------------------------------------------------- static const char* OTR_PROTOCOL_STRING = "prpl-jabber"; static const QString OTR_FINGERPRINTS_FILE = "otr.fingerprints"; static const QString OTR_KEYS_FILE = "otr.keys"; static const QString OTR_INSTAGS_FILE = "otr.instags"; // ============================================================================ OtrInternal::OtrInternal(psiotr::OtrCallback* callback, psiotr::OtrPolicy& policy) : m_userstate(), m_uiOps(), m_callback(callback), m_otrPolicy(policy), is_generating(false) { QDir profileDir(callback->dataDir()); m_keysFile = profileDir.filePath(OTR_KEYS_FILE); m_instagsFile = profileDir.filePath(OTR_INSTAGS_FILE); m_fingerprintFile = profileDir.filePath(OTR_FINGERPRINTS_FILE); OTRL_INIT; m_userstate = otrl_userstate_create(); m_uiOps.policy = (*OtrInternal::cb_policy); m_uiOps.create_privkey = (*OtrInternal::cb_create_privkey); m_uiOps.is_logged_in = (*OtrInternal::cb_is_logged_in); m_uiOps.inject_message = (*OtrInternal::cb_inject_message); m_uiOps.update_context_list = (*OtrInternal::cb_update_context_list); m_uiOps.new_fingerprint = (*OtrInternal::cb_new_fingerprint); m_uiOps.write_fingerprints = (*OtrInternal::cb_write_fingerprints); m_uiOps.gone_secure = (*OtrInternal::cb_gone_secure); m_uiOps.gone_insecure = (*OtrInternal::cb_gone_insecure); m_uiOps.still_secure = (*OtrInternal::cb_still_secure); #if (OTRL_VERSION_MAJOR > 3 || (OTRL_VERSION_MAJOR == 3 && OTRL_VERSION_MINOR >= 2)) m_uiOps.max_message_size = NULL; m_uiOps.account_name = (*OtrInternal::cb_account_name); m_uiOps.account_name_free = (*OtrInternal::cb_account_name_free); #endif #if (OTRL_VERSION_MAJOR >= 4) m_uiOps.handle_msg_event = (*OtrInternal::cb_handle_msg_event); m_uiOps.handle_smp_event = (*OtrInternal::cb_handle_smp_event); m_uiOps.create_instag = (*OtrInternal::cb_create_instag); #else m_uiOps.log_message = (*OtrInternal::cb_log_message); m_uiOps.notify = (*OtrInternal::cb_notify); m_uiOps.display_otr_message = (*OtrInternal::cb_display_otr_message); m_uiOps.protocol_name = (*OtrInternal::cb_protocol_name); m_uiOps.protocol_name_free = (*OtrInternal::cb_protocol_name_free); #endif otrl_privkey_read(m_userstate, QFile::encodeName(m_keysFile).constData()); otrl_privkey_read_fingerprints(m_userstate, QFile::encodeName(m_fingerprintFile).constData(), NULL, NULL); #if (OTRL_VERSION_MAJOR >= 4) otrl_instag_read(m_userstate, QFile::encodeName(m_instagsFile).constData()); #endif } //----------------------------------------------------------------------------- OtrInternal::~OtrInternal() { otrl_userstate_free(m_userstate); } //----------------------------------------------------------------------------- QString OtrInternal::encryptMessage(const QString& account, const QString& contact, const QString& message) { char* encMessage = NULL; gcry_error_t err; err = otrl_message_sending(m_userstate, &m_uiOps, this, account.toUtf8().constData(), OTR_PROTOCOL_STRING, contact.toUtf8().constData(), #if (OTRL_VERSION_MAJOR >= 4) OTRL_INSTAG_BEST, #endif message.toUtf8().constData(), NULL, &encMessage, #if (OTRL_VERSION_MAJOR >= 4) OTRL_FRAGMENT_SEND_SKIP, NULL, #endif NULL, NULL); if (err) { QString err_message = QObject::tr("Encrypting message to %1 " "failed.\nThe message was not sent.") .arg(contact); if (!m_callback->displayOtrMessage(account, contact, err_message)) { m_callback->notifyUser(account, contact, err_message, psiotr::OTR_NOTIFY_ERROR); } return QString(); } if (encMessage) { QString retMessage(QString::fromUtf8(encMessage)); otrl_message_free(encMessage); return retMessage; } return message; } //----------------------------------------------------------------------------- psiotr::OtrMessageType OtrInternal::decryptMessage(const QString& account, const QString& contact, const QString& cryptedMessage, QString& decrypted) { QByteArray accArray = account.toUtf8(); QByteArray userArray = contact.toUtf8(); const char* accountName = accArray.constData(); const char* userName = userArray.constData(); int ignoreMessage = 0; char* newMessage = NULL; OtrlTLV* tlvs = NULL; OtrlTLV* tlv = NULL; ignoreMessage = otrl_message_receiving(m_userstate, &m_uiOps, this, accountName, OTR_PROTOCOL_STRING, userName, cryptedMessage.toUtf8().constData(), &newMessage, &tlvs, NULL, #if (OTRL_VERSION_MAJOR >= 4) NULL, #endif NULL); tlv = otrl_tlv_find(tlvs, OTRL_TLV_DISCONNECTED); if (tlv) { m_callback->stateChange(accountName, userName, psiotr::OTR_STATECHANGE_REMOTECLOSE); } #if (OTRL_VERSION_MAJOR >= 4) // Magic hack to force it work similar to libotr < 4.0.0. // If user received unencrypted message he (she) should be notified. // See OTRL_MSGEVENT_RCVDMSG_UNENCRYPTED as well. if (ignoreMessage && !newMessage && !cryptedMessage.startsWith("?OTR")) { ignoreMessage = 0; } #else // Check for SMP data (required only with libotr < 4.0.0) ConnContext* context = otrl_context_find(m_userstate, userName, accountName, OTR_PROTOCOL_STRING, false, NULL, NULL, NULL); if (context) { NextExpectedSMP nextMsg = context->smstate->nextExpected; if (context->smstate->sm_prog_state == OTRL_SMP_PROG_CHEATED) { abortSMP(context); // Reset state context->smstate->nextExpected = OTRL_SMP_EXPECT1; context->smstate->sm_prog_state = OTRL_SMP_PROG_OK; // Report result to user m_callback->updateSMP(accountName, userName, -2); } else { tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP1Q); if (tlv) { if (nextMsg != OTRL_SMP_EXPECT1) { abortSMP(context); } else { char* question = (char *)tlv->data; char* eoq = static_cast(memchr(question, '\0', tlv->len)); if (eoq) { m_callback->receivedSMP(accountName, userName, QString::fromUtf8(question)); } } } tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP1); if (tlv) { if (nextMsg != OTRL_SMP_EXPECT1) { abortSMP(context); } else { m_callback->receivedSMP(accountName, userName, QString()); } } tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP2); if (tlv) { if (nextMsg != OTRL_SMP_EXPECT2) { abortSMP(context); } else { // If we received TLV2, we will send TLV3 and expect TLV4 context->smstate->nextExpected = OTRL_SMP_EXPECT4; // Report result to user m_callback->updateSMP(accountName, userName, 66); } } tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP3); if (tlv) { if (nextMsg != OTRL_SMP_EXPECT3) { abortSMP(context); } else { // SMP finished, reset context->smstate->nextExpected = OTRL_SMP_EXPECT1; // Report result to user m_callback->updateSMP(accountName, userName, 100); } } tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP4); if (tlv) { if (nextMsg != OTRL_SMP_EXPECT4) { abortSMP(context); } else { // SMP finished, reset context->smstate->nextExpected = OTRL_SMP_EXPECT1; // Report result to user m_callback->updateSMP(accountName, userName, 100); } } tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP_ABORT); if (tlv) { // SMP aborted, reset context->smstate->nextExpected = OTRL_SMP_EXPECT1; // Report result to user m_callback->updateSMP(accountName, userName, -1); } } } #endif otrl_tlv_free(tlvs); if (ignoreMessage == 1) { // Internal protocol message return psiotr::OTR_MESSAGETYPE_IGNORE; } else if ((ignoreMessage == 0) && newMessage) { // Message has been decrypted, replace it decrypted = QString::fromUtf8(newMessage); otrl_message_free(newMessage); return psiotr::OTR_MESSAGETYPE_OTR; } return psiotr::OTR_MESSAGETYPE_NONE; } //----------------------------------------------------------------------------- QList OtrInternal::getFingerprints() { QList fpList; ConnContext* context; ::Fingerprint* fingerprint; for (context = m_userstate->context_root; context != NULL; context = context->next) { fingerprint = context->fingerprint_root.next; while(fingerprint) { psiotr::Fingerprint fp (fingerprint->fingerprint, QString::fromUtf8(context->accountname), QString::fromUtf8(context->username), QString::fromUtf8(fingerprint->trust)); fpList.append(fp); fingerprint = fingerprint->next; } } return fpList; } //----------------------------------------------------------------------------- void OtrInternal::verifyFingerprint(const psiotr::Fingerprint& fingerprint, bool verified) { ConnContext* context = otrl_context_find(m_userstate, fingerprint.username.toUtf8().constData(), fingerprint.account.toUtf8().constData(), OTR_PROTOCOL_STRING, #if (OTRL_VERSION_MAJOR >= 4) OTRL_INSTAG_BEST, #endif false, NULL, NULL, NULL); if (context) { ::Fingerprint* fp = otrl_context_find_fingerprint(context, fingerprint.fingerprint, 0, NULL); if (fp) { otrl_context_set_trust(fp, verified? "verified" : ""); write_fingerprints(); if (context->active_fingerprint == fp) { m_callback->stateChange(QString::fromUtf8(context->accountname), QString::fromUtf8(context->username), psiotr::OTR_STATECHANGE_TRUST); } } } } //----------------------------------------------------------------------------- void OtrInternal::deleteFingerprint(const psiotr::Fingerprint& fingerprint) { ConnContext* context = otrl_context_find(m_userstate, fingerprint.username.toUtf8().constData(), fingerprint.account.toUtf8().constData(), OTR_PROTOCOL_STRING, #if (OTRL_VERSION_MAJOR >= 4) OTRL_INSTAG_BEST, #endif false, NULL, NULL, NULL); if (context) { ::Fingerprint* fp = otrl_context_find_fingerprint(context, fingerprint.fingerprint, 0, NULL); if (fp) { if (context->active_fingerprint == fp) { otrl_context_force_finished(context); } otrl_context_forget_fingerprint(fp, true); write_fingerprints(); } } } //----------------------------------------------------------------------------- QHash OtrInternal::getPrivateKeys() { QHash privKeyList; OtrlPrivKey* privKey; for (privKey = m_userstate->privkey_root; privKey != NULL; privKey = privKey->next) { char fingerprintBuf[OTRL_PRIVKEY_FPRINT_HUMAN_LEN]; char* success = otrl_privkey_fingerprint(m_userstate, fingerprintBuf, privKey->accountname, OTR_PROTOCOL_STRING); if (success) { privKeyList.insert(QString::fromUtf8(privKey->accountname), QString(fingerprintBuf)); } } return privKeyList; } //----------------------------------------------------------------------------- void OtrInternal::deleteKey(const QString& account) { OtrlPrivKey* privKey = otrl_privkey_find(m_userstate, account.toUtf8().constData(), OTR_PROTOCOL_STRING); otrl_privkey_forget(privKey); otrl_privkey_write(m_userstate, QFile::encodeName(m_keysFile).constData()); } //----------------------------------------------------------------------------- void OtrInternal::startSession(const QString& account, const QString& contact) { m_callback->stateChange(account, contact, psiotr::OTR_STATECHANGE_GOINGSECURE); if (!otrl_privkey_find(m_userstate, account.toUtf8().constData(), OTR_PROTOCOL_STRING)) { create_privkey(account.toUtf8().constData(), OTR_PROTOCOL_STRING); } //TODO: make allowed otr versions configureable char* msg = otrl_proto_default_query_msg(m_callback->humanAccountPublic(account).toUtf8().constData(), OTRL_POLICY_DEFAULT); m_callback->sendMessage(account, contact, QString::fromUtf8(msg)); free(msg); } //----------------------------------------------------------------------------- void OtrInternal::endSession(const QString& account, const QString& contact) { ConnContext* context = otrl_context_find(m_userstate, contact.toUtf8().constData(), account.toUtf8().constData(), OTR_PROTOCOL_STRING, #if (OTRL_VERSION_MAJOR >= 4) OTRL_INSTAG_BEST, #endif false, NULL, NULL, NULL); if (context && (context->msgstate != OTRL_MSGSTATE_PLAINTEXT)) { m_callback->stateChange(account, contact, psiotr::OTR_STATECHANGE_CLOSE); } otrl_message_disconnect(m_userstate, &m_uiOps, this, account.toUtf8().constData(), OTR_PROTOCOL_STRING, contact.toUtf8().constData() #if (OTRL_VERSION_MAJOR >= 4) ,OTRL_INSTAG_BEST #endif ); } //----------------------------------------------------------------------------- void OtrInternal::expireSession(const QString& account, const QString& contact) { ConnContext* context = otrl_context_find(m_userstate, contact.toUtf8().constData(), account.toUtf8().constData(), OTR_PROTOCOL_STRING, #if (OTRL_VERSION_MAJOR >= 4) OTRL_INSTAG_BEST, #endif false, NULL, NULL, NULL); if (context && (context->msgstate == OTRL_MSGSTATE_ENCRYPTED)) { otrl_context_force_finished(context); m_callback->stateChange(account, contact, psiotr::OTR_STATECHANGE_GONEINSECURE); } } //----------------------------------------------------------------------------- void OtrInternal::startSMP(const QString& account, const QString& contact, const QString& question, const QString& secret) { ConnContext* context = otrl_context_find(m_userstate, contact.toUtf8().constData(), account.toUtf8().constData(), OTR_PROTOCOL_STRING, #if (OTRL_VERSION_MAJOR >= 4) OTRL_INSTAG_BEST, #endif false, NULL, NULL, NULL); if (context) { QByteArray secretArray = secret.toUtf8(); const char* secretPointer = secretArray.constData(); size_t secretLength = qstrlen(secretPointer); if (question.isEmpty()) { otrl_message_initiate_smp(m_userstate, &m_uiOps, this, context, reinterpret_cast(const_cast(secretPointer)), secretLength); } else { otrl_message_initiate_smp_q(m_userstate, &m_uiOps, this, context, question.toUtf8().constData(), reinterpret_cast(const_cast(secretPointer)), secretLength); } } } void OtrInternal::continueSMP(const QString& account, const QString& contact, const QString& secret) { ConnContext* context = otrl_context_find(m_userstate, contact.toUtf8().constData(), account.toUtf8().constData(), OTR_PROTOCOL_STRING, #if (OTRL_VERSION_MAJOR >= 4) OTRL_INSTAG_BEST, #endif false, NULL, NULL, NULL); if (context) { QByteArray secretArray = secret.toUtf8(); const char* secretPointer = secretArray.constData(); size_t secretLength = qstrlen(secretPointer); otrl_message_respond_smp(m_userstate, &m_uiOps, this, context, reinterpret_cast(secretPointer), secretLength); } } void OtrInternal::abortSMP(const QString& account, const QString& contact) { ConnContext* context = otrl_context_find(m_userstate, contact.toUtf8().constData(), account.toUtf8().constData(), OTR_PROTOCOL_STRING, #if (OTRL_VERSION_MAJOR >= 4) OTRL_INSTAG_BEST, #endif false, NULL, NULL, NULL); if (context) { abortSMP(context); } } void OtrInternal::abortSMP(ConnContext* context) { otrl_message_abort_smp(m_userstate, &m_uiOps, this, context); } //----------------------------------------------------------------------------- psiotr::OtrMessageState OtrInternal::getMessageState(const QString& account, const QString& contact) { ConnContext* context = otrl_context_find(m_userstate, contact.toUtf8().constData(), account.toUtf8().constData(), OTR_PROTOCOL_STRING, #if (OTRL_VERSION_MAJOR >= 4) OTRL_INSTAG_BEST, #endif false, NULL, NULL, NULL); if (context) { if (context->msgstate == OTRL_MSGSTATE_PLAINTEXT) { return psiotr::OTR_MESSAGESTATE_PLAINTEXT; } else if (context->msgstate == OTRL_MSGSTATE_ENCRYPTED) { return psiotr::OTR_MESSAGESTATE_ENCRYPTED; } else if (context->msgstate == OTRL_MSGSTATE_FINISHED) { return psiotr::OTR_MESSAGESTATE_FINISHED; } } return psiotr::OTR_MESSAGESTATE_UNKNOWN; } //----------------------------------------------------------------------------- QString OtrInternal::getMessageStateString(const QString& account, const QString& contact) { psiotr::OtrMessageState state = getMessageState(account, contact); if (state == psiotr::OTR_MESSAGESTATE_PLAINTEXT) { return QObject::tr("plaintext"); } else if (state == psiotr::OTR_MESSAGESTATE_ENCRYPTED) { return QObject::tr("encrypted"); } else if (state == psiotr::OTR_MESSAGESTATE_FINISHED) { return QObject::tr("finished"); } return QObject::tr("unknown"); } //----------------------------------------------------------------------------- QString OtrInternal::getSessionId(const QString& account, const QString& contact) { ConnContext* context; context = otrl_context_find(m_userstate, contact.toUtf8().constData(), account.toUtf8().constData(), OTR_PROTOCOL_STRING, #if (OTRL_VERSION_MAJOR >= 4) OTRL_INSTAG_BEST, #endif false, NULL, NULL, NULL); if (context && (context->sessionid_len > 0)) { QString firstHalf; QString secondHalf; for (unsigned int i = 0; i < context->sessionid_len / 2; i++) { if (context->sessionid[i] <= 0xf) { firstHalf.append("0"); } firstHalf.append(QString::number(context->sessionid[i], 16)); } for (size_t i = context->sessionid_len / 2; i < context->sessionid_len; i++) { if (context->sessionid[i] <= 0xf) { secondHalf.append("0"); } secondHalf.append(QString::number(context->sessionid[i], 16)); } if (context->sessionid_half == OTRL_SESSIONID_FIRST_HALF_BOLD) { return QString("" + firstHalf + " " + secondHalf); } else { return QString(firstHalf + " " + secondHalf + ""); } } return QString(); } //----------------------------------------------------------------------------- psiotr::Fingerprint OtrInternal::getActiveFingerprint(const QString& account, const QString& contact) { ConnContext* context; context = otrl_context_find(m_userstate, contact.toUtf8().constData(), account.toUtf8().constData(), OTR_PROTOCOL_STRING, #if (OTRL_VERSION_MAJOR >= 4) OTRL_INSTAG_BEST, #endif false, NULL, NULL, NULL); if (context && context->active_fingerprint) { return psiotr::Fingerprint(context->active_fingerprint->fingerprint, QString::fromUtf8(context->accountname), QString::fromUtf8(context->username), QString::fromUtf8(context->active_fingerprint->trust)); } return psiotr::Fingerprint(); } //----------------------------------------------------------------------------- bool OtrInternal::isVerified(const QString& account, const QString& contact) { ConnContext* context; context = otrl_context_find(m_userstate, contact.toUtf8().constData(), account.toUtf8().constData(), OTR_PROTOCOL_STRING, #if (OTRL_VERSION_MAJOR >= 4) OTRL_INSTAG_BEST, #endif false, NULL, NULL, NULL); return isVerified(context); } //----------------------------------------------------------------------------- bool OtrInternal::isVerified(ConnContext* context) { if (context && context->active_fingerprint) { return (context->active_fingerprint->trust && context->active_fingerprint->trust[0]); } return false; } //----------------------------------------------------------------------------- bool OtrInternal::smpSucceeded(const QString& account, const QString& contact) { ConnContext* context; context = otrl_context_find(m_userstate, contact.toUtf8().constData(), account.toUtf8().constData(), OTR_PROTOCOL_STRING, #if (OTRL_VERSION_MAJOR >= 4) OTRL_INSTAG_BEST, #endif false, NULL, NULL, NULL); if (context) { return context->smstate->sm_prog_state == OTRL_SMP_PROG_SUCCEEDED; } return false; } //----------------------------------------------------------------------------- void OtrInternal::generateKey(const QString& account) { create_privkey(account.toUtf8().constData(), OTR_PROTOCOL_STRING); } //----------------------------------------------------------------------------- QString OtrInternal::humanFingerprint(const unsigned char* fingerprint) { char fpHash[OTRL_PRIVKEY_FPRINT_HUMAN_LEN]; otrl_privkey_hash_to_human(fpHash, fingerprint); return QString(fpHash); } //----------------------------------------------------------------------------- /*** implemented callback functions for libotr ***/ OtrlPolicy OtrInternal::policy(ConnContext*) { if (m_otrPolicy == psiotr::OTR_POLICY_OFF) { return OTRL_POLICY_NEVER; // otr disabled } else if (m_otrPolicy == psiotr::OTR_POLICY_ENABLED) { return OTRL_POLICY_MANUAL; // otr enabled, session started manual } else if (m_otrPolicy == psiotr::OTR_POLICY_AUTO) { return OTRL_POLICY_OPPORTUNISTIC; // automatically initiate private messaging } else if (m_otrPolicy == psiotr::OTR_POLICY_REQUIRE) { return OTRL_POLICY_ALWAYS; // require private messaging } return OTRL_POLICY_NEVER; } // --------------------------------------------------------------------------- void OtrInternal::create_privkey(const char* accountname, const char* protocol) { if (is_generating) { return; } QMessageBox qMB(QMessageBox::Question, QObject::tr("Psi OTR"), QObject::tr("Private keys for account \"%1\" need to be generated. " "This takes quite some time (from a few seconds to a " "couple of minutes), and while you can use Psi+ in the " "meantime, all the messages will be sent unencrypted " "until keys are generated. You will be notified when " "this process finishes.\n" "\n" "Do you want to generate keys now?") .arg(m_callback->humanAccount( QString::fromUtf8(accountname))), QMessageBox::Yes | QMessageBox::No); if (qMB.exec() != QMessageBox::Yes) { return; } is_generating = true; QByteArray keysfile = QFile::encodeName(m_keysFile); QEventLoop loop; QFutureWatcher watcher; QObject::connect(&watcher, SIGNAL(finished()), &loop, SLOT(quit())); QFuture future = QtConcurrent::run(otrl_privkey_generate, m_userstate, keysfile.constData(), accountname, protocol); watcher.setFuture(future); loop.exec(); is_generating = false; char fingerprint[OTRL_PRIVKEY_FPRINT_HUMAN_LEN]; if (otrl_privkey_fingerprint(m_userstate, fingerprint, accountname, protocol)) { QMessageBox infoMb(QMessageBox::Information, QObject::tr("Psi OTR"), QObject::tr("Keys have been generated. " "Fingerprint for account \"%1\":\n" "%2\n" "\n" "Thanks for your patience.") .arg(m_callback->humanAccount( QString::fromUtf8(accountname))) .arg(QString(fingerprint))); infoMb.exec(); } else { QMessageBox failMb(QMessageBox::Critical, QObject::tr("Psi OTR"), QObject::tr("Failed to generate keys for account \"%1\"." "\nThe OTR Plugin will not work.") .arg(m_callback->humanAccount( QString::fromUtf8(accountname))), QMessageBox::Ok); failMb.exec(); } } // --------------------------------------------------------------------------- int OtrInternal::is_logged_in(const char* accountname, const char* protocol, const char* recipient) { Q_UNUSED(protocol); if (m_callback->isLoggedIn(QString::fromUtf8(accountname), QString::fromUtf8(recipient))) { return 1; // contact online } else { return 0; // contact offline } } // --------------------------------------------------------------------------- void OtrInternal::inject_message(const char* accountname, const char* protocol, const char* recipient, const char* message) { Q_UNUSED(protocol); m_callback->sendMessage(QString::fromUtf8(accountname), QString::fromUtf8(recipient), QString::fromUtf8(message)); } // --------------------------------------------------------------------------- #if (OTRL_VERSION_MAJOR >= 4) void OtrInternal::handle_msg_event(OtrlMessageEvent msg_event, ConnContext* context, const char* message, gcry_error_t err) { Q_UNUSED(err); Q_UNUSED(message); QString account = QString::fromUtf8(context->accountname); QString contact = QString::fromUtf8(context->username); QString errorString; switch (msg_event) { case OTRL_MSGEVENT_RCVDMSG_UNENCRYPTED: errorString = QObject::tr("The following message received " "from %1 was not encrypted:") .arg(m_callback->humanContact(account, contact)); break; case OTRL_MSGEVENT_CONNECTION_ENDED: errorString = QObject::tr("Your message was not sent. Either end your " "private conversation, or restart it."); break; case OTRL_MSGEVENT_RCVDMSG_UNRECOGNIZED: errorString = QObject::tr("Unreadable encrypted message was received."); break; case OTRL_MSGEVENT_RCVDMSG_NOT_IN_PRIVATE: errorString = QObject::tr("Received an encrypted message but it cannot " "be read because no private connection is " "established yet."); break; case OTRL_MSGEVENT_RCVDMSG_UNREADABLE: errorString = QObject::tr("Received message is unreadable."); break; case OTRL_MSGEVENT_RCVDMSG_MALFORMED: errorString = QObject::tr("Received message contains malformed data."); break; default: ; } if (!errorString.isEmpty()) { m_callback->displayOtrMessage(QString::fromUtf8(context->accountname), QString::fromUtf8(context->username), errorString); } } void OtrInternal::handle_smp_event(OtrlSMPEvent smp_event, ConnContext* context, unsigned short progress_percent, char* question) { if (smp_event == OTRL_SMPEVENT_CHEATED || smp_event == OTRL_SMPEVENT_ERROR) { abortSMP(context); m_callback->updateSMP(QString::fromUtf8(context->accountname), QString::fromUtf8(context->username), -2); } else if (smp_event == OTRL_SMPEVENT_ASK_FOR_SECRET || smp_event == OTRL_SMPEVENT_ASK_FOR_ANSWER) { m_callback->receivedSMP(QString::fromUtf8(context->accountname), QString::fromUtf8(context->username), QString::fromUtf8(question)); } else { m_callback->updateSMP(QString::fromUtf8(context->accountname), QString::fromUtf8(context->username), progress_percent); } } void OtrInternal::create_instag(const char* accountname, const char* protocol) { otrl_instag_generate(m_userstate, QFile::encodeName(m_instagsFile).constData(), accountname, protocol); } #else void OtrInternal::notify(OtrlNotifyLevel level, const char* accountname, const char* protocol, const char* username, const char* title, const char* primary, const char* secondary) { Q_UNUSED(protocol); Q_UNUSED(title); QString account = QString::fromUtf8(accountname); QString contact = QString::fromUtf8(username); QString message = QString(primary) + "\n" + QString(secondary); if (!m_callback->displayOtrMessage(account, contact, message)) { psiotr::OtrNotifyType type; if (level == OTRL_NOTIFY_ERROR ) { type = psiotr::OTR_NOTIFY_ERROR; } else if (level == OTRL_NOTIFY_WARNING) { type = psiotr::OTR_NOTIFY_WARNING; } else { type = psiotr::OTR_NOTIFY_ERROR; } m_callback->notifyUser(account, contact, message, type); } } int OtrInternal::display_otr_message(const char* accountname, const char* protocol, const char* username, const char* msg) { Q_UNUSED(protocol); QString message = QString::fromUtf8(msg); if (QRegExp("^The following message received " "from .+ was not encrypted: " "\\[.+\\]$").exactMatch(message)) { return -1; } else { return m_callback->displayOtrMessage(QString::fromUtf8(accountname), QString::fromUtf8(username), message)? 0 : -1; } } #endif // --------------------------------------------------------------------------- void OtrInternal::update_context_list() { } // --------------------------------------------------------------------------- #if !(OTRL_VERSION_MAJOR >= 4) const char* OtrInternal::protocol_name(const char* protocol) { Q_UNUSED(protocol); return OTR_PROTOCOL_STRING; } void OtrInternal::protocol_name_free(const char* protocol_name) { Q_UNUSED(protocol_name); } #endif // --------------------------------------------------------------------------- void OtrInternal::new_fingerprint(OtrlUserState us, const char* accountname, const char* protocol, const char* username, unsigned char fingerprint[20]) { Q_UNUSED(us); Q_UNUSED(protocol); QString account = QString::fromUtf8(accountname); QString contact = QString::fromUtf8(username); QString message = QObject::tr("You have received a new " "fingerprint from %1:\n%2") .arg(m_callback->humanContact(account, contact)) .arg(humanFingerprint(fingerprint)); if (!m_callback->displayOtrMessage(account, contact, message)) { m_callback->notifyUser(account, contact, message, psiotr::OTR_NOTIFY_INFO); } } // --------------------------------------------------------------------------- void OtrInternal::write_fingerprints() { otrl_privkey_write_fingerprints(m_userstate, QFile::encodeName(m_fingerprintFile).constData()); } // --------------------------------------------------------------------------- void OtrInternal::gone_secure(ConnContext* context) { m_callback->stateChange(QString::fromUtf8(context->accountname), QString::fromUtf8(context->username), psiotr::OTR_STATECHANGE_GONESECURE); } // --------------------------------------------------------------------------- void OtrInternal::gone_insecure(ConnContext* context) { m_callback->stateChange(QString::fromUtf8(context->accountname), QString::fromUtf8(context->username), psiotr::OTR_STATECHANGE_GONEINSECURE); } // --------------------------------------------------------------------------- void OtrInternal::still_secure(ConnContext* context, int is_reply) { Q_UNUSED(is_reply); m_callback->stateChange(QString::fromUtf8(context->accountname), QString::fromUtf8(context->username), psiotr::OTR_STATECHANGE_STILLSECURE); } // --------------------------------------------------------------------------- #if !(OTRL_VERSION_MAJOR >= 4) void OtrInternal::log_message(const char* message) { Q_UNUSED(message); } #endif // --------------------------------------------------------------------------- const char* OtrInternal::account_name(const char* account, const char* protocol) { Q_UNUSED(protocol); return qstrdup(m_callback->humanAccountPublic(QString::fromUtf8(account)) .toUtf8().constData()); } // --------------------------------------------------------------------------- void OtrInternal::account_name_free(const char* account_name) { delete [] account_name; } // --------------------------------------------------------------------------- /*** static wrapper functions ***/ OtrlPolicy OtrInternal::cb_policy(void* opdata, ConnContext* context) { return static_cast(opdata)->policy(context); } void OtrInternal::cb_create_privkey(void* opdata, const char* accountname, const char* protocol) { static_cast(opdata)->create_privkey(accountname, protocol); } int OtrInternal::cb_is_logged_in(void* opdata, const char* accountname, const char* protocol, const char* recipient) { return static_cast(opdata)->is_logged_in(accountname, protocol, recipient); } void OtrInternal::cb_inject_message(void* opdata, const char* accountname, const char* protocol, const char* recipient, const char* message) { static_cast(opdata)->inject_message(accountname, protocol, recipient, message); } #if (OTRL_VERSION_MAJOR >= 4) void OtrInternal::cb_handle_msg_event(void* opdata, OtrlMessageEvent msg_event, ConnContext* context, const char* message, gcry_error_t err) { static_cast(opdata)->handle_msg_event(msg_event, context, message, err); } void OtrInternal::cb_handle_smp_event(void* opdata, OtrlSMPEvent smp_event, ConnContext* context, unsigned short progress_percent, char* question) { static_cast(opdata)->handle_smp_event(smp_event, context, progress_percent, question); } void OtrInternal::cb_create_instag(void* opdata, const char* accountname, const char* protocol) { static_cast(opdata)->create_instag(accountname, protocol); } #else void OtrInternal::cb_notify(void* opdata, OtrlNotifyLevel level, const char* accountname, const char* protocol, const char* username, const char* title, const char* primary, const char* secondary) { static_cast(opdata)->notify(level, accountname, protocol, username, title, primary, secondary); } int OtrInternal::cb_display_otr_message(void* opdata, const char* accountname, const char* protocol, const char* username, const char* msg) { return static_cast(opdata)->display_otr_message(accountname, protocol, username, msg); } #endif void OtrInternal::cb_update_context_list(void* opdata) { static_cast(opdata)->update_context_list(); } #if !(OTRL_VERSION_MAJOR >= 4) const char* OtrInternal::cb_protocol_name(void* opdata, const char* protocol) { return static_cast(opdata)->protocol_name(protocol); } void OtrInternal::cb_protocol_name_free(void* opdata, const char* protocol_name) { static_cast(opdata)->protocol_name(protocol_name); } #endif void OtrInternal::cb_new_fingerprint(void* opdata, OtrlUserState us, const char* accountname, const char* protocol, const char* username, unsigned char fingerprint[20]) { static_cast(opdata)->new_fingerprint(us, accountname, protocol, username, fingerprint); } void OtrInternal::cb_write_fingerprints(void* opdata) { static_cast(opdata)->write_fingerprints(); } void OtrInternal::cb_gone_secure(void* opdata, ConnContext* context) { static_cast(opdata)->gone_secure(context); } void OtrInternal::cb_gone_insecure(void* opdata, ConnContext* context) { static_cast(opdata)->gone_insecure(context); } void OtrInternal::cb_still_secure(void* opdata, ConnContext* context, int is_reply) { static_cast(opdata)->still_secure(context, is_reply); } #if !(OTRL_VERSION_MAJOR >= 4) void OtrInternal::cb_log_message(void* opdata, const char* message) { static_cast(opdata)->log_message(message); } #endif const char* OtrInternal::cb_account_name(void* opdata, const char* account, const char* protocol) { return static_cast(opdata)->account_name(account, protocol); } void OtrInternal::cb_account_name_free(void* opdata, const char* account_name) { static_cast(opdata)->account_name_free(account_name); } // --------------------------------------------------------------------------- plugins-1.5/generic/otrplugin/src/otrinternal.h000066400000000000000000000217211336777360500220240ustar00rootroot00000000000000/* * otrinternal.h - Manages the OTR connection * * Off-the-Record Messaging plugin for Psi+ * Copyright (C) 2007-2011 Timo Engel (timo-e@freenet.de) * 2011 Florian Fieber * 2013-2014 Boris Pek (tehnick-8@mail.ru) * * This program was originally written as part of a diplom thesis * advised by Prof. Dr. Ruediger Weis (PST Labor) * at the Technical University of Applied Sciences Berlin. * * 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, see . * */ #ifndef OTRINTERNAL_H_ #define OTRINTERNAL_H_ #include "otrmessaging.h" #include #include extern "C" { #include #include #include #ifndef OTRL_PRIVKEY_FPRINT_HUMAN_LEN #define OTRL_PRIVKEY_FPRINT_HUMAN_LEN 45 #endif #if (OTRL_VERSION_MAJOR >= 4) #include #endif #include "otrlextensions.h" } class QString; // --------------------------------------------------------------------------- /** * Handles all libotr calls and callbacks. */ class OtrInternal { public: OtrInternal(psiotr::OtrCallback* callback, psiotr::OtrPolicy& policy); ~OtrInternal(); QString encryptMessage(const QString& account, const QString& contact, const QString& message); psiotr::OtrMessageType decryptMessage(const QString& account, const QString& contact, const QString& message, QString& decrypted); QList getFingerprints(); void verifyFingerprint(const psiotr::Fingerprint& fingerprint, bool verified); void deleteFingerprint(const psiotr::Fingerprint& fingerprint); QHash getPrivateKeys(); void deleteKey(const QString& account); void startSession(const QString& account, const QString& contact); void endSession(const QString& account, const QString& contact); void expireSession(const QString& account, const QString& contact); void startSMP(const QString& account, const QString& contact, const QString& question, const QString& secret); void continueSMP(const QString& account, const QString& contact, const QString& secret); void abortSMP(const QString& account, const QString& contact); void abortSMP(ConnContext* context); psiotr::OtrMessageState getMessageState(const QString& account, const QString& contact); QString getMessageStateString(const QString& account, const QString& contact); QString getSessionId(const QString& account, const QString& contact); psiotr::Fingerprint getActiveFingerprint(const QString& account, const QString& contact); bool isVerified(const QString& account, const QString& contact); bool isVerified(ConnContext* context); bool smpSucceeded(const QString& account, const QString& contact); void generateKey(const QString& account); static QString humanFingerprint(const unsigned char* fingerprint); /*** otr callback functions ***/ OtrlPolicy policy(ConnContext* context); void create_privkey(const char* accountname, const char* protocol); int is_logged_in(const char* accountname, const char* protocol, const char* recipient); void inject_message(const char* accountname, const char* protocol, const char* recipient, const char* message); void update_context_list(); void new_fingerprint(OtrlUserState us, const char* accountname, const char* protocol, const char* username, unsigned char fingerprint[20]); void write_fingerprints(); void gone_secure(ConnContext* context); void gone_insecure(ConnContext* context); void still_secure(ConnContext* context, int is_reply); #if (OTRL_VERSION_MAJOR >= 4) void handle_msg_event(OtrlMessageEvent msg_event, ConnContext* context, const char* message, gcry_error_t err); void handle_smp_event(OtrlSMPEvent smp_event, ConnContext* context, unsigned short progress_percent, char* question); void create_instag(const char* accountname, const char* protocol); #else void log_message(const char* message); void notify(OtrlNotifyLevel level, const char* accountname, const char* protocol, const char* username, const char* title, const char* primary, const char* secondary); int display_otr_message(const char* accountname, const char* protocol, const char* username, const char* msg); const char* protocol_name(const char* protocol); void protocol_name_free(const char* protocol_name); #endif const char* account_name(const char* account, const char* protocol); void account_name_free(const char* account_name); /*** static otr callback wrapper-functions ***/ static OtrlPolicy cb_policy(void* opdata, ConnContext* context); static void cb_create_privkey(void* opdata, const char* accountname, const char* protocol); static int cb_is_logged_in(void* opdata, const char* accountname, const char* protocol, const char* recipient); static void cb_inject_message(void* opdata, const char* accountname, const char* protocol, const char* recipient, const char* message); static void cb_update_context_list(void* opdata); static void cb_new_fingerprint(void* opdata, OtrlUserState us, const char* accountname, const char* protocol, const char* username, unsigned char fingerprint[20]); static void cb_write_fingerprints(void* opdata); static void cb_gone_secure(void* opdata, ConnContext* context); static void cb_gone_insecure(void* opdata, ConnContext* context); static void cb_still_secure(void* opdata, ConnContext* context, int is_reply); #if (OTRL_VERSION_MAJOR >= 4) static void cb_handle_msg_event(void* opdata, OtrlMessageEvent msg_event, ConnContext* context, const char* message, gcry_error_t err); static void cb_handle_smp_event(void* opdata, OtrlSMPEvent smp_event, ConnContext* context, unsigned short progress_percent, char* question); static void cb_create_instag(void* opdata, const char* accountname, const char* protocol); #else static void cb_log_message(void* opdata, const char* message); static void cb_notify(void* opdata, OtrlNotifyLevel level, const char* accountname, const char* protocol, const char* username, const char* title, const char* primary, const char* secondary); static int cb_display_otr_message(void* opdata, const char* accountname, const char* protocol, const char* username, const char* msg); static const char* cb_protocol_name(void* opdata, const char* protocol); static void cb_protocol_name_free(void* opdata, const char* protocol_name); #endif static const char* cb_account_name(void* opdata, const char* account, const char* protocol); static void cb_account_name_free(void* opdata, const char* account_name); private: /** * The userstate contains keys and known fingerprints. */ OtrlUserState m_userstate; /** * Pointers to callback functions. */ OtrlMessageAppOps m_uiOps; /** * Pointer to a class for callbacks from OTR to application. */ psiotr::OtrCallback* m_callback; /** * Name of the file storing dsa-keys. */ QString m_keysFile; /** * Name of the file storing instance tags. */ QString m_instagsFile; /** * Name of the file storing known fingerprints. */ QString m_fingerprintFile; /** * Reference to the default OTR policy */ psiotr::OtrPolicy& m_otrPolicy; /** * Variable used during generating of private key. */ bool is_generating; }; // --------------------------------------------------------------------------- #endif plugins-1.5/generic/otrplugin/src/otrlextensions.c000066400000000000000000000062221336777360500225550ustar00rootroot00000000000000/* * otrlextensions.c - Off-the-Record Messaging library extensions * * Strongly based on parts of the Off-the-Record Messaging library, * Copyright (C) 2004-2008 Ian Goldberg, Chris Alexander, Nikita Borisov * * * This library is free software; you can redistribute it and/or * modify it under the terms of version 2.1 of the GNU Lesser General * Public License as published by the Free Software Foundation. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * */ /* system headers */ #include #include #include #include /* libgcrypt headers */ #include /* libotr headers */ #include #include "otrlextensions.h" static gcry_error_t sexp_write(FILE* privf, gcry_sexp_t sexp) { size_t buflen; char* buf; buflen = gcry_sexp_sprint(sexp, GCRYSEXP_FMT_ADVANCED, NULL, 0); buf = malloc(buflen); if (buf == NULL && buflen > 0) { return gcry_error(GPG_ERR_ENOMEM); } gcry_sexp_sprint(sexp, GCRYSEXP_FMT_ADVANCED, buf, buflen); fprintf(privf, "%s", buf); free(buf); return gcry_error(GPG_ERR_NO_ERROR); } static gcry_error_t account_write(FILE* privf, const char* accountname, const char* protocol, gcry_sexp_t privkey) { gcry_error_t err; gcry_sexp_t names, protos; fprintf(privf, " (account\n"); err = gcry_sexp_build(&names, NULL, "(name %s)", accountname); if (!err) { err = sexp_write(privf, names); gcry_sexp_release(names); } if (!err) err = gcry_sexp_build(&protos, NULL, "(protocol %s)", protocol); if (!err) { err = sexp_write(privf, protos); gcry_sexp_release(protos); } if (!err) err = sexp_write(privf, privkey); fprintf(privf, " )\n"); return err; } /* Store all keys of an OtrlUserState. * The FILE* must be open for reading and writing. */ gcry_error_t otrl_privkey_write_FILEp(OtrlUserState us, FILE* privf) { OtrlPrivKey* p; /* Output the other keys we know */ fprintf(privf, "(privkeys\n"); for (p=us->privkey_root; p; p=p->next) { account_write(privf, p->accountname, p->protocol, p->privkey); } fprintf(privf, ")\n"); fseek(privf, 0, SEEK_SET); return otrl_privkey_read_FILEp(us, privf); } /* Store all keys of an OtrlUserState. */ gcry_error_t otrl_privkey_write(OtrlUserState us, const char* filename) { gcry_error_t err; FILE* privf; #ifndef WIN32 mode_t oldmask; #endif #ifndef WIN32 oldmask = umask(077); #endif privf = fopen(filename, "w+b"); if (!privf) { #ifndef WIN32 umask(oldmask); #endif err = gcry_error_from_errno(errno); return err; } err = otrl_privkey_write_FILEp(us, privf); fclose(privf); #ifndef WIN32 umask(oldmask); #endif return err; } plugins-1.5/generic/otrplugin/src/otrlextensions.h000066400000000000000000000023501336777360500225600ustar00rootroot00000000000000/* * otrlextensions.h - Off-the-Record Messaging library extensions * * Strongly based on parts of the Off-the-Record Messaging library, * Copyright (C) 2004-2008 Ian Goldberg, Chris Alexander, Nikita Borisov * * * This library is free software; you can redistribute it and/or * modify it under the terms of version 2.1 of the GNU Lesser General * Public License as published by the Free Software Foundation. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library. If not, see . * */ #ifndef __OTRLEXT_H__ #define __OTRLEXT_H__ #include #include /* Store all keys of an OtrlUserState. */ gcry_error_t otrl_privkey_write(OtrlUserState us, const char* filename); /* Store all keys of an OtrlUserState. * The FILE* must be open for reading and writing. */ gcry_error_t otrl_privkey_write_FILEp(OtrlUserState us, FILE* privf); #endif plugins-1.5/generic/otrplugin/src/otrmessaging.cpp000066400000000000000000000203171336777360500225200ustar00rootroot00000000000000/* * otrmessaging.cpp - Interface to libotr * * Off-the-Record Messaging plugin for Psi+ * Copyright (C) 2007-2011 Timo Engel (timo-e@freenet.de) * 2011 Florian Fieber * 2014 Boris Pek (tehnick-8@mail.ru) * * 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, see . * */ #include "otrmessaging.h" #include "otrinternal.h" #include #include #include namespace psiotr { Fingerprint::Fingerprint() : fingerprint(NULL) { } Fingerprint::Fingerprint(const Fingerprint &fp) : fingerprint(fp.fingerprint), account(fp.account), username(fp.username), fingerprintHuman(fp.fingerprintHuman), trust(fp.trust) { } Fingerprint::Fingerprint(unsigned char* fingerprint, QString account, QString username, QString trust) : fingerprint(fingerprint), account(account), username(username), trust(trust) { fingerprintHuman = OtrInternal::humanFingerprint(fingerprint); } //----------------------------------------------------------------------------- OtrMessaging::OtrMessaging(OtrCallback* callback, OtrPolicy policy) : m_otrPolicy(policy), m_impl(new OtrInternal(callback, m_otrPolicy)), m_callback(callback) { } //----------------------------------------------------------------------------- OtrMessaging::~OtrMessaging() { delete m_impl; } //----------------------------------------------------------------------------- QString OtrMessaging::encryptMessage(const QString& account, const QString& contact, const QString& message) { return m_impl->encryptMessage(account, contact, message); } //----------------------------------------------------------------------------- OtrMessageType OtrMessaging::decryptMessage(const QString& account, const QString& contact, const QString& message, QString& decrypted) { return m_impl->decryptMessage(account, contact, message, decrypted); } //----------------------------------------------------------------------------- QList OtrMessaging::getFingerprints() { return m_impl->getFingerprints(); } //----------------------------------------------------------------------------- void OtrMessaging::verifyFingerprint(const psiotr::Fingerprint& fingerprint, bool verified) { m_impl->verifyFingerprint(fingerprint, verified); } //----------------------------------------------------------------------------- void OtrMessaging::deleteFingerprint(const psiotr::Fingerprint& fingerprint) { m_impl->deleteFingerprint(fingerprint); } //----------------------------------------------------------------------------- QHash OtrMessaging::getPrivateKeys() { return m_impl->getPrivateKeys(); } //----------------------------------------------------------------------------- void OtrMessaging::deleteKey(const QString& account) { m_impl->deleteKey(account); } //----------------------------------------------------------------------------- void OtrMessaging::startSession(const QString& account, const QString& contact) { m_impl->startSession(account, contact); } //----------------------------------------------------------------------------- void OtrMessaging::endSession(const QString& account, const QString& contact) { m_impl->endSession(account, contact); } //----------------------------------------------------------------------------- void OtrMessaging::expireSession(const QString& account, const QString& contact) { m_impl->expireSession(account, contact); } //----------------------------------------------------------------------------- void OtrMessaging::startSMP(const QString& account, const QString& contact, const QString& question, const QString& secret) { m_impl->startSMP(account, contact, question, secret); } //----------------------------------------------------------------------------- void OtrMessaging::continueSMP(const QString& account, const QString& contact, const QString& secret) { m_impl->continueSMP(account, contact, secret); } //----------------------------------------------------------------------------- void OtrMessaging::abortSMP(const QString& account, const QString& contact) { m_impl->abortSMP(account, contact); } //----------------------------------------------------------------------------- OtrMessageState OtrMessaging::getMessageState(const QString& account, const QString& contact) { return m_impl->getMessageState(account, contact); } //----------------------------------------------------------------------------- QString OtrMessaging::getMessageStateString(const QString& account, const QString& contact) { return m_impl->getMessageStateString(account, contact); } //----------------------------------------------------------------------------- QString OtrMessaging::getSessionId(const QString& account, const QString& contact) { return m_impl->getSessionId(account, contact); } //----------------------------------------------------------------------------- psiotr::Fingerprint OtrMessaging::getActiveFingerprint(const QString& account, const QString& contact) { return m_impl->getActiveFingerprint(account, contact); } //----------------------------------------------------------------------------- bool OtrMessaging::isVerified(const QString& account, const QString& contact) { return m_impl->isVerified(account, contact); } //----------------------------------------------------------------------------- bool OtrMessaging::smpSucceeded(const QString& account, const QString& contact) { return m_impl->smpSucceeded(account, contact); } //----------------------------------------------------------------------------- void OtrMessaging::setPolicy(psiotr::OtrPolicy policy) { m_otrPolicy = policy; } //----------------------------------------------------------------------------- OtrPolicy OtrMessaging::getPolicy() { return m_otrPolicy; } //----------------------------------------------------------------------------- void OtrMessaging::generateKey(const QString& account) { m_impl->generateKey(account); } //----------------------------------------------------------------------------- bool OtrMessaging::displayOtrMessage(const QString& account, const QString& contact, const QString& message) { return m_callback->displayOtrMessage(account, contact, message); } //----------------------------------------------------------------------------- void OtrMessaging::stateChange(const QString& account, const QString& contact, OtrStateChange change) { return m_callback->stateChange(account, contact, change); } //----------------------------------------------------------------------------- QString OtrMessaging::humanAccount(const QString& accountId) { return m_callback->humanAccount(accountId); } //----------------------------------------------------------------------------- QString OtrMessaging::humanContact(const QString& accountId, const QString& contact) { return m_callback->humanContact(accountId, contact); } //----------------------------------------------------------------------------- } // namespace psiotr plugins-1.5/generic/otrplugin/src/otrmessaging.h000066400000000000000000000227761336777360500222000ustar00rootroot00000000000000/* * otrmessaging.h - Interface to libotr * * Off-the-Record Messaging plugin for Psi+ * Copyright (C) 2007-2011 Timo Engel (timo-e@freenet.de) * 2011 Florian Fieber * 2014 Boris Pek (tehnick-8@mail.ru) * * 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, see . * */ #ifndef OTRMESSAGING_H_ #define OTRMESSAGING_H_ #include #include #include class OtrInternal; // --------------------------------------------------------------------------- namespace psiotr { // --------------------------------------------------------------------------- enum OtrPolicy { OTR_POLICY_OFF, OTR_POLICY_ENABLED, OTR_POLICY_AUTO, OTR_POLICY_REQUIRE }; // --------------------------------------------------------------------------- enum OtrMessageType { OTR_MESSAGETYPE_NONE, OTR_MESSAGETYPE_IGNORE, OTR_MESSAGETYPE_OTR }; // --------------------------------------------------------------------------- enum OtrMessageState { OTR_MESSAGESTATE_UNKNOWN, OTR_MESSAGESTATE_PLAINTEXT, OTR_MESSAGESTATE_ENCRYPTED, OTR_MESSAGESTATE_FINISHED }; // --------------------------------------------------------------------------- enum OtrStateChange { OTR_STATECHANGE_GOINGSECURE, OTR_STATECHANGE_GONESECURE, OTR_STATECHANGE_GONEINSECURE, OTR_STATECHANGE_STILLSECURE, OTR_STATECHANGE_CLOSE, OTR_STATECHANGE_REMOTECLOSE, OTR_STATECHANGE_TRUST }; // --------------------------------------------------------------------------- enum OtrNotifyType { OTR_NOTIFY_INFO, OTR_NOTIFY_WARNING, OTR_NOTIFY_ERROR }; // --------------------------------------------------------------------------- /** * Interface for callbacks from libotr to application */ class OtrCallback { public: virtual QString dataDir() = 0; /** * Sends a message from the Account account to the user contact. * The method is called from the OtrConnection to send messages * during key-exchange. */ virtual void sendMessage(const QString& account, const QString& contact, const QString& message) = 0; virtual bool isLoggedIn(const QString& account, const QString& contact) = 0; virtual void notifyUser(const QString& account, const QString& contact, const QString& message, const OtrNotifyType& type) = 0; virtual bool displayOtrMessage(const QString& account, const QString& contact, const QString& message) = 0; virtual void stateChange(const QString& account, const QString& contact, OtrStateChange change) = 0; virtual void receivedSMP(const QString& account, const QString& contact, const QString& question) = 0; virtual void updateSMP(const QString& account, const QString& contact, int progress) = 0; virtual void stopMessages() = 0; virtual void startMessages() = 0; virtual QString humanAccount(const QString& accountId) = 0; virtual QString humanAccountPublic(const QString& accountId) = 0; virtual QString humanContact(const QString& accountId, const QString& contact) = 0; }; // --------------------------------------------------------------------------- /** * This struct contains all data shown in the table of 'Known Fingerprints'. */ struct Fingerprint { /** * Pointer to fingerprint in libotr struct. Binary format. */ unsigned char* fingerprint; /** * own account */ QString account; /** * owner of the fingerprint */ QString username; /** * The fingerprint in a human-readable format */ QString fingerprintHuman; /** * the level of trust */ QString trust; Fingerprint(); Fingerprint(const Fingerprint &fp); Fingerprint(unsigned char* fingerprint, QString account, QString username, QString trust); }; // --------------------------------------------------------------------------- /** * This class is the interface to the Off the Record Messaging library. * See the libotr documentation for more information. */ class OtrMessaging { public: /** * Constructor * * @param plugin Pointer to the plugin, used for sending messages. * @param policy The default OTR policy */ OtrMessaging(OtrCallback* callback, OtrPolicy policy); /** * Deconstructor */ ~OtrMessaging(); /** * Process an outgoing message. * * @param account Account the message is send from * @param contact Recipient of the message * @param message The message itself * * @return The encrypted message */ QString encryptMessage(const QString& account, const QString& contact, const QString& message); /** * Decrypt an incoming message. * * @param account Account the message is send to * @param contact Sender of the message * @param message The message itself * @param decrypted The decrypted message if the original message was * encrypted * @return Type of incoming message */ OtrMessageType decryptMessage(const QString& account, const QString& contact, const QString& message, QString& decrypted); /** * Returns a list of known fingerprints. */ QList getFingerprints(); /** * Set fingerprint verified/not verified. */ void verifyFingerprint(const Fingerprint& fingerprint, bool verified); /** * Delete a known fingerprint. */ void deleteFingerprint(const Fingerprint& fingerprint); /** * Get hash of fingerprints of own private keys. * Account -> KeyFingerprint */ QHash getPrivateKeys(); /** * Delete a private key. */ void deleteKey(const QString& account); /** * Send an OTR query message from account to contact. */ void startSession(const QString& account, const QString& contact); /** * Send otr-finished message to user. */ void endSession(const QString& account, const QString& contact); /** * Force a session to expire. */ void expireSession(const QString& account, const QString& contact); /** * Start the SMP with an optional question. */ void startSMP(const QString& account, const QString& contact, const QString& question, const QString& secret); /** * Continue the SMP. */ void continueSMP(const QString& account, const QString& contact, const QString& secret); /** * Abort the SMP. */ void abortSMP(const QString& account, const QString& contact); /** * Return the messageState of a context, * i.e. plaintext, encrypted, finished. */ OtrMessageState getMessageState(const QString& account, const QString& contact); /** * Return the messageState as human-readable string. */ QString getMessageStateString(const QString& account, const QString& contact); /** * Return the secure session id (ssid) for a context. */ QString getSessionId(const QString& account, const QString& contact); /** * Return the active fingerprint for a context. */ psiotr::Fingerprint getActiveFingerprint(const QString& account, const QString& contact); /** * Return true if the active fingerprint has been verified. */ bool isVerified(const QString& account, const QString& contact); /** * Return true if Socialist Millionaires' Protocol succeeded. */ bool smpSucceeded(const QString& account, const QString& contact); /** * Set the default OTR policy. */ void setPolicy(OtrPolicy policy); /** * Return the default OTR policy. */ OtrPolicy getPolicy(); /** * Generate own keys. * This function blocks until keys are available. */ void generateKey(const QString& account); /** * Display OTR message. */ bool displayOtrMessage(const QString& account, const QString& contact, const QString& message); /** * Report a change of state. */ void stateChange(const QString& account, const QString& contact, OtrStateChange change); /** * Return a human-readable representation * of an account identified by accountId. */ QString humanAccount(const QString& accountId); /** * Return the name of a contact. */ QString humanContact(const QString& accountId, const QString& contact); private: OtrPolicy m_otrPolicy; OtrInternal* m_impl; OtrCallback* m_callback; }; // --------------------------------------------------------------------------- } // namespace psiotr #endif plugins-1.5/generic/otrplugin/src/psiotrclosure.cpp000066400000000000000000000555371336777360500227470ustar00rootroot00000000000000/* * psiotrclosure.cpp * * Off-the-Record Messaging plugin for Psi+ * Copyright (C) 2007-2011 Timo Engel (timo-e@freenet.de) * 2011-2012 Florian Fieber * 2014 Boris Pek (tehnick-8@mail.ru) * * This program was originally written as part of a diplom thesis * advised by Prof. Dr. Ruediger Weis (PST Labor) * at the Technical University of Applied Sciences Berlin. * * 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, see . * */ #include "psiotrclosure.h" #include #include #include #include #include #include #include #include #include #include #include #include #include namespace psiotr { AuthenticationDialog::AuthenticationDialog(OtrMessaging* otrc, const QString& account, const QString& contact, const QString& question, bool sender, QWidget* parent) : QDialog(parent), m_otr(otrc), m_method(METHOD_QUESTION), m_account(account), m_contact(contact), m_isSender(sender) { setAttribute(Qt::WA_DeleteOnClose); m_contactName = m_otr->humanContact(m_account, m_contact); QString qaExplanation; QString ssExplanation; QString fprExplanation; if (m_isSender) { setWindowTitle(tr("Authenticate %1").arg(m_contactName)); qaExplanation = tr("To authenticate via question and answer, " "ask a question whose answer is only known " "to you and %1.").arg(m_contactName); ssExplanation = tr("To authenticate via shared secret, " "enter a secret only known " "to you and %1.").arg(m_contactName); fprExplanation = tr("To authenticate manually, exchange your " "fingerprints over an authenticated channel and " "compare each other's fingerprint with the one " "listed beneath."); } else { setWindowTitle(tr("Authenticate to %1").arg(m_contactName)); qaExplanation = tr("%1 wants to authenticate you. To authenticate, " "answer the question asked below.") .arg(m_contactName); ssExplanation = tr("%1 wants to authenticate you. To authenticate, " "enter your shared secret below.") .arg(m_contactName); } m_methodBox = new QComboBox(this); m_methodBox->setMinimumWidth(300); m_methodBox->addItem(tr("Question and answer")); m_methodBox->addItem(tr("Shared secret")); m_methodBox->addItem(tr("Fingerprint verification")); QLabel* qaExplanationLabel = new QLabel(qaExplanation, this); qaExplanationLabel->setWordWrap(true); QLabel* ssExplanationLabel = new QLabel(ssExplanation, this); ssExplanationLabel->setWordWrap(true); m_questionEdit = new QLineEdit(this); m_answerEdit = new QLineEdit(this); m_sharedSecretEdit = new QLineEdit(this); QLabel* questionLabel = new QLabel(tr("&Question:"), this); questionLabel->setBuddy(m_questionEdit); QLabel* answerLabel = new QLabel(tr("A&nswer:"), this); answerLabel->setBuddy(m_answerEdit); QLabel* sharedSecretLabel = new QLabel(tr("&Shared Secret:"), this); sharedSecretLabel->setBuddy(m_sharedSecretEdit); m_progressBar = new QProgressBar(this); m_cancelButton = new QPushButton(tr("&Cancel"), this); m_startButton = new QPushButton(tr("&Authenticate"), this); m_startButton->setDefault(true); m_methodWidget[METHOD_QUESTION] = new QWidget(this); QVBoxLayout* qaLayout = new QVBoxLayout; qaLayout->setContentsMargins(0, 0, 0, 0); qaLayout->addWidget(qaExplanationLabel); qaLayout->addSpacing(20); qaLayout->addWidget(questionLabel); qaLayout->addWidget(m_questionEdit); qaLayout->addSpacing(10); qaLayout->addWidget(answerLabel); qaLayout->addWidget(m_answerEdit); qaLayout->addSpacing(20); m_methodWidget[METHOD_QUESTION]->setLayout(qaLayout); m_methodWidget[METHOD_SHARED_SECRET] = new QWidget(this); QVBoxLayout* ssLayout = new QVBoxLayout; ssLayout->setContentsMargins(0, 0, 0, 0); ssLayout->addWidget(ssExplanationLabel); ssLayout->addSpacing(20); ssLayout->addWidget(sharedSecretLabel); ssLayout->addWidget(m_sharedSecretEdit); ssLayout->addSpacing(20); m_methodWidget[METHOD_SHARED_SECRET]->setLayout(ssLayout); m_methodWidget[METHOD_FINGERPRINT] = NULL; QLabel* authenticatedLabel = NULL; if (m_isSender) { if (m_otr->isVerified(m_account, m_contact)) { authenticatedLabel = new QLabel(QString("%1") .arg(tr("This contact is already " "authenticated.")), this); } QString ownFpr = m_otr->getPrivateKeys().value( m_account, tr("No private key for account \"%1\"") .arg(m_otr->humanAccount(m_account))); m_fpr = m_otr->getActiveFingerprint(m_account, m_contact); QLabel* fprExplanationLabel = new QLabel(fprExplanation, this); fprExplanationLabel->setWordWrap(true); QLabel* ownFprDescLabel = new QLabel(tr("Your fingerprint:"), this); QLabel* ownFprLabel = new QLabel(ownFpr, this); QLabel* fprDescLabel = new QLabel(tr("%1's fingerprint:") .arg(m_contactName), this); QLabel* fprLabel = new QLabel(m_fpr.fingerprintHuman, this); ownFprLabel->setFont(QFont("monospace")); fprLabel->setFont(QFont("monospace")); m_methodWidget[METHOD_FINGERPRINT] = new QWidget(this); QVBoxLayout* fprLayout = new QVBoxLayout; fprLayout->setContentsMargins(0, 0, 0, 0); fprLayout->addWidget(fprExplanationLabel); fprLayout->addSpacing(20); fprLayout->addWidget(ownFprDescLabel); fprLayout->addWidget(ownFprLabel); fprLayout->addSpacing(10); fprLayout->addWidget(fprDescLabel); fprLayout->addWidget(fprLabel); m_methodWidget[METHOD_FINGERPRINT]->setLayout(fprLayout); } QHBoxLayout* buttonLayout = new QHBoxLayout; buttonLayout->setContentsMargins(0, 0, 0, 0); buttonLayout->addWidget(m_cancelButton); buttonLayout->addWidget(m_startButton); QVBoxLayout* mainLayout = new QVBoxLayout; mainLayout->setContentsMargins(20, 20, 20, 20); if (authenticatedLabel) { mainLayout->addWidget(authenticatedLabel); mainLayout->addSpacing(20); } mainLayout->addWidget(m_methodBox); mainLayout->addSpacing(20); mainLayout->addWidget(m_methodWidget[METHOD_QUESTION]); mainLayout->addWidget(m_methodWidget[METHOD_SHARED_SECRET]); if (m_methodWidget[METHOD_FINGERPRINT]) { mainLayout->addWidget(m_methodWidget[METHOD_FINGERPRINT]); } mainLayout->addWidget(m_progressBar); mainLayout->addSpacing(20); mainLayout->addLayout(buttonLayout); setLayout(mainLayout); connect(m_methodBox, SIGNAL(currentIndexChanged(int)), this, SLOT(changeMethod(int))); connect(m_methodBox, SIGNAL(currentIndexChanged(int)), this, SLOT(checkRequirements())); connect(m_questionEdit, SIGNAL(textChanged(const QString &)), this, SLOT(checkRequirements())); connect(m_answerEdit, SIGNAL(textChanged(const QString &)), this, SLOT(checkRequirements())); connect(m_sharedSecretEdit, SIGNAL(textChanged(const QString &)), this, SLOT(checkRequirements())); connect(m_cancelButton, SIGNAL(clicked()), this, SLOT(reject())); connect(m_startButton, SIGNAL(clicked()), this, SLOT(startAuthentication())); if (!m_isSender) { if (question.isEmpty()) { m_method = METHOD_SHARED_SECRET; } else { m_questionEdit->setText(question); } } changeMethod(m_method); m_methodBox->setCurrentIndex(m_method); reset(); } AuthenticationDialog::~AuthenticationDialog() { } void AuthenticationDialog::reject() { if (m_state == AUTH_IN_PROGRESS) { m_otr->abortSMP(m_account, m_contact); } QDialog::reject(); } void AuthenticationDialog::reset() { m_state = m_isSender? AUTH_READY : AUTH_IN_PROGRESS; m_methodBox->setEnabled(m_isSender); m_questionEdit->setEnabled(m_isSender); m_answerEdit->setEnabled(true); m_sharedSecretEdit->setEnabled(true); m_progressBar->setEnabled(false); m_progressBar->setValue(0); checkRequirements(); } bool AuthenticationDialog::finished() { return m_state == AUTH_FINISHED; } void AuthenticationDialog::checkRequirements() { m_startButton->setEnabled((m_method == METHOD_QUESTION && !m_questionEdit->text().isEmpty() && !m_answerEdit->text().isEmpty()) || (m_method == METHOD_SHARED_SECRET && !m_sharedSecretEdit->text().isEmpty()) || (m_method == METHOD_FINGERPRINT)); } void AuthenticationDialog::changeMethod(int index) { m_method = static_cast(index); for (int i=0; i<3; i++) { if (m_methodWidget[i]) { m_methodWidget[i]->setVisible(i == index); } } m_progressBar->setVisible(m_method != METHOD_FINGERPRINT); adjustSize(); } void AuthenticationDialog::startAuthentication() { switch (m_method) { case METHOD_QUESTION: if (m_questionEdit->text().isEmpty() || m_answerEdit->text().isEmpty()) { return; } m_state = AUTH_IN_PROGRESS; m_methodBox->setEnabled(false); m_questionEdit->setEnabled(false); m_answerEdit->setEnabled(false); m_progressBar->setEnabled(true); m_startButton->setEnabled(false); if (m_isSender) { m_otr->startSMP(m_account, m_contact, m_questionEdit->text(), m_answerEdit->text()); } else { m_otr->continueSMP(m_account, m_contact, m_answerEdit->text()); } updateSMP(33); break; case METHOD_SHARED_SECRET: if (m_sharedSecretEdit->text().isEmpty()) { return; } m_state = AUTH_IN_PROGRESS; m_methodBox->setEnabled(false); m_sharedSecretEdit->setEnabled(false); m_progressBar->setEnabled(true); m_startButton->setEnabled(false); if (m_isSender) { m_otr->startSMP(m_account, m_contact, QString(), m_sharedSecretEdit->text()); } else { m_otr->continueSMP(m_account, m_contact, m_sharedSecretEdit->text()); } updateSMP(33); break; case METHOD_FINGERPRINT: if (m_fpr.fingerprint) { QString msg(tr("Account: ") + m_otr->humanAccount(m_account) + "\n" + tr("User: ") + m_contact + "\n" + tr("Fingerprint: ") + m_fpr.fingerprintHuman + "\n\n" + tr("Have you verified that this is in fact the correct fingerprint?")); QMessageBox mb(QMessageBox::Information, tr("Psi OTR"), msg, QMessageBox::Yes | QMessageBox::No, this, Qt::Dialog | Qt::MSWindowsFixedSizeDialogHint); m_otr->verifyFingerprint(m_fpr, mb.exec() == QMessageBox::Yes); close(); } break; } } void AuthenticationDialog::updateSMP(int progress) { if (progress<0) { if (progress == -1) { notify(QMessageBox::Warning, tr("%1 has canceled the authentication process.") .arg(m_contactName)); } else { notify(QMessageBox::Warning, tr("An error occurred during the authentication process.")); } if (m_isSender) { reset(); } else { close(); } return; } m_progressBar->setValue(progress); if (progress == 100) { if (m_isSender || m_method == METHOD_SHARED_SECRET) { m_otr->stateChange(m_account, m_contact, psiotr::OTR_STATECHANGE_TRUST); } if (m_otr->smpSucceeded(m_account, m_contact)) { m_state = AUTH_FINISHED; if (m_otr->isVerified(m_account, m_contact)) { notify(QMessageBox::Information, tr("Authentication successful.")); } else { notify(QMessageBox::Information, tr("You have been successfully authenticated.\n\n" "You should authenticate %1 as " "well by asking your own question.") .arg(m_contactName)); } close(); } else { m_state = m_isSender? AUTH_READY : AUTH_FINISHED; notify(QMessageBox::Critical, tr("Authentication failed.")); if (m_isSender) { reset(); } else { close(); } } } } //----------------------------------------------------------------------------- void AuthenticationDialog::notify(const QMessageBox::Icon icon, const QString& message) { QMessageBox mb(icon, tr("Psi OTR"), message, QMessageBox::Ok, this, Qt::Dialog | Qt::MSWindowsFixedSizeDialogHint); mb.exec(); } //----------------------------------------------------------------------------- PsiOtrClosure::PsiOtrClosure(const QString& account, const QString& contact, OtrMessaging* otrc) : m_otr(otrc), m_account(account), m_contact(contact), m_chatDlgMenu(0), m_chatDlgAction(0), m_authenticateAction(0), m_sessionIdAction(0), m_fingerprintAction(0), m_startSessionAction(0), m_endSessionAction(0), m_isLoggedIn(false), m_parentWidget(0), m_authDialog(0) { } //----------------------------------------------------------------------------- PsiOtrClosure::~PsiOtrClosure() { if (m_chatDlgMenu) { delete m_chatDlgMenu; } } //----------------------------------------------------------------------------- void PsiOtrClosure::initiateSession(bool b) { Q_UNUSED(b); m_otr->startSession(m_account, m_contact); } //----------------------------------------------------------------------------- void PsiOtrClosure::authenticateContact(bool) { if (m_authDialog || !encrypted()) { return; } m_authDialog = new AuthenticationDialog(m_otr, m_account, m_contact, QString(), true); connect(m_authDialog, SIGNAL(destroyed()), this, SLOT(finishAuth())); m_authDialog->show(); } //----------------------------------------------------------------------------- void PsiOtrClosure::receivedSMP(const QString& question) { if ((m_authDialog && !m_authDialog->finished()) || !encrypted()) { m_otr->abortSMP(m_account, m_contact); return; } if (m_authDialog) { disconnect(m_authDialog, SIGNAL(destroyed()), this, SLOT(finishAuth())); finishAuth(); } m_authDialog = new AuthenticationDialog(m_otr, m_account, m_contact, question, false); connect(m_authDialog, SIGNAL(destroyed()), this, SLOT(finishAuth())); m_authDialog->show(); } //----------------------------------------------------------------------------- void PsiOtrClosure::updateSMP(int progress) { if (m_authDialog) { m_authDialog->updateSMP(progress); m_authDialog->show(); } } //----------------------------------------------------------------------------- void PsiOtrClosure::finishAuth() { m_authDialog = 0; updateMessageState(); } //----------------------------------------------------------------------------- void PsiOtrClosure::sessionID(bool) { QString sId = m_otr->getSessionId(m_account, m_contact); QString msg; if (sId.isEmpty()) { msg = tr("No active encrypted session"); } else { msg = tr("Session ID between account \"%1\" and %2: %3") .arg(m_otr->humanAccount(m_account)) .arg(m_contact) .arg(sId); } m_otr->displayOtrMessage(m_account, m_contact, msg); } //----------------------------------------------------------------------------- void PsiOtrClosure::endSession(bool b) { Q_UNUSED(b); m_otr->endSession(m_account, m_contact); updateMessageState(); } //----------------------------------------------------------------------------- void PsiOtrClosure::fingerprint(bool) { QString fingerprint = m_otr->getPrivateKeys() .value(m_account, tr("No private key for account \"%1\"") .arg(m_otr->humanAccount(m_account))); QString msg(tr("Fingerprint for account \"%1\": %2") .arg(m_otr->humanAccount(m_account)) .arg(fingerprint)); m_otr->displayOtrMessage(m_account, m_contact, msg); } //----------------------------------------------------------------------------- void PsiOtrClosure::updateMessageState() { if (m_chatDlgAction) { OtrMessageState state = m_otr->getMessageState(m_account, m_contact); QString stateString(m_otr->getMessageStateString(m_account, m_contact)); if (state == OTR_MESSAGESTATE_ENCRYPTED) { if (m_otr->isVerified(m_account, m_contact)) { m_chatDlgAction->setIcon(QIcon(":/otrplugin/otr_yes.png")); } else { m_chatDlgAction->setIcon(QIcon(":/otrplugin/otr_unverified.png")); stateString += ", " + tr("unverified"); } } else { m_chatDlgAction->setIcon(QIcon(":/otrplugin/otr_no.png")); } m_chatDlgAction->setText(tr("OTR Messaging [%1]").arg(stateString)); if (state == OTR_MESSAGESTATE_ENCRYPTED) { m_startSessionAction->setText(tr("Refre&sh private conversation")); m_authenticateAction->setEnabled(true); m_sessionIdAction->setEnabled(true); m_endSessionAction->setEnabled(true); } else { m_startSessionAction->setText(tr("&Start private conversation")); if (state == OTR_MESSAGESTATE_PLAINTEXT) { m_authenticateAction->setEnabled(false); m_sessionIdAction->setEnabled(false); m_endSessionAction->setEnabled(false); } else // finished, unknown { m_endSessionAction->setEnabled(true); m_authenticateAction->setEnabled(false); m_sessionIdAction->setEnabled(false); } } if (m_otr->getPolicy() < OTR_POLICY_ENABLED) { m_startSessionAction->setEnabled(false); m_endSessionAction->setEnabled(false); } } } //----------------------------------------------------------------------------- QAction* PsiOtrClosure::getChatDlgMenu(QObject* parent) { m_parentWidget = parent; m_chatDlgAction = new QAction(QString(), this); m_chatDlgMenu = new QMenu(); m_startSessionAction = m_chatDlgMenu->addAction(QString()); connect(m_startSessionAction, SIGNAL(triggered(bool)), this, SLOT(initiateSession(bool))); m_endSessionAction = m_chatDlgMenu->addAction(tr("&End private conversation")); connect(m_endSessionAction, SIGNAL(triggered(bool)), this, SLOT(endSession(bool))); m_chatDlgMenu->insertSeparator(NULL); m_authenticateAction = m_chatDlgMenu->addAction(tr("&Authenticate contact")); connect(m_authenticateAction, SIGNAL(triggered(bool)), this, SLOT(authenticateContact(bool))); m_sessionIdAction = m_chatDlgMenu->addAction(tr("Show secure session &ID")); connect(m_sessionIdAction, SIGNAL(triggered(bool)), this, SLOT(sessionID(bool))); m_fingerprintAction = m_chatDlgMenu->addAction(tr("Show own &fingerprint")); connect(m_fingerprintAction, SIGNAL(triggered(bool)), this, SLOT(fingerprint(bool))); connect(m_chatDlgAction, SIGNAL(triggered()), this, SLOT(showMenu())); updateMessageState(); return m_chatDlgAction; } //----------------------------------------------------------------------------- void PsiOtrClosure::showMenu() { m_chatDlgMenu->popup(QCursor::pos(), m_chatDlgAction); } //----------------------------------------------------------------------------- void PsiOtrClosure::setIsLoggedIn(bool isLoggedIn) { m_isLoggedIn = isLoggedIn; } //----------------------------------------------------------------------------- bool PsiOtrClosure::isLoggedIn() const { return m_isLoggedIn; } //----------------------------------------------------------------------------- void PsiOtrClosure::disable() { if (m_chatDlgAction) { m_chatDlgAction->setEnabled(false); } } //----------------------------------------------------------------------------- bool PsiOtrClosure::encrypted() const { return m_otr->getMessageState(m_account, m_contact) == OTR_MESSAGESTATE_ENCRYPTED; } //----------------------------------------------------------------------------- } // namespace plugins-1.5/generic/otrplugin/src/psiotrclosure.h000066400000000000000000000075701336777360500224060ustar00rootroot00000000000000/* * psiotrclosure.h * * Off-the-Record Messaging plugin for Psi+ * Copyright (C) 2007-2011 Timo Engel (timo-e@freenet.de) * 2011-2012 Florian Fieber * * This program was originally written as part of a diplom thesis * advised by Prof. Dr. Ruediger Weis (PST Labor) * at the Technical University of Applied Sciences Berlin. * * 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, see . * */ #ifndef PSIOTRCLOSURE_H_ #define PSIOTRCLOSURE_H_ #include "otrmessaging.h" #include #include #include class QAction; class QMenu; class QComboBox; class QLineEdit; class QProgressBar; class QPushButton; namespace psiotr { //----------------------------------------------------------------------------- class AuthenticationDialog : public QDialog { Q_OBJECT public: AuthenticationDialog(OtrMessaging* otrc, const QString& account, const QString& contact, const QString& question, bool sender, QWidget* parent = 0); ~AuthenticationDialog(); void reset(); bool finished(); void updateSMP(int progress); void notify(const QMessageBox::Icon icon, const QString& message); public slots: void reject(); private: enum AuthState {AUTH_READY, AUTH_IN_PROGRESS, AUTH_FINISHED}; enum Method {METHOD_QUESTION, METHOD_SHARED_SECRET, METHOD_FINGERPRINT}; OtrMessaging* m_otr; Method m_method; QString m_account; QString m_contact; QString m_contactName; bool m_isSender; AuthState m_state; Fingerprint m_fpr; QWidget* m_methodWidget[3]; QComboBox* m_methodBox; QLineEdit* m_questionEdit; QLineEdit* m_answerEdit; QLineEdit* m_sharedSecretEdit; QProgressBar* m_progressBar; QPushButton* m_cancelButton; QPushButton* m_startButton; private slots: void changeMethod(int index); void checkRequirements(); void startAuthentication(); }; //----------------------------------------------------------------------------- class PsiOtrClosure : public QObject { Q_OBJECT public: PsiOtrClosure(const QString& account, const QString& contact, OtrMessaging* otrc); ~PsiOtrClosure(); void updateMessageState(); void setIsLoggedIn(bool isLoggedIn); bool isLoggedIn() const; void disable(); QAction* getChatDlgMenu(QObject* parent); bool encrypted() const; void receivedSMP(const QString& question); void updateSMP(int progress); private: OtrMessaging* m_otr; QString m_account; QString m_contact; QMenu* m_chatDlgMenu; QAction* m_chatDlgAction; QAction* m_authenticateAction; QAction* m_sessionIdAction; QAction* m_fingerprintAction; QAction* m_startSessionAction; QAction* m_endSessionAction; bool m_isLoggedIn; QObject* m_parentWidget; AuthenticationDialog* m_authDialog; public slots: void initiateSession(bool b); void endSession(bool b); void authenticateContact(bool b); void sessionID(bool b); void fingerprint(bool b); void showMenu(); void finishAuth(); }; //----------------------------------------------------------------------------- } // namespace psiotr #endif plugins-1.5/generic/otrplugin/src/psiotrconfig.cpp000066400000000000000000000417161336777360500225320ustar00rootroot00000000000000/* * psiotrconfig.cpp - Configuration dialogs * * Off-the-Record Messaging plugin for Psi+ * Copyright (C) 2007-2011 Timo Engel (timo-e@freenet.de) * 2011 Florian Fieber * * 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, see . * */ #include "psiotrconfig.h" #include "optionaccessinghost.h" #include "accountinfoaccessinghost.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //----------------------------------------------------------------------------- namespace psiotr { //----------------------------------------------------------------------------- ConfigDialog::ConfigDialog(OtrMessaging* otr, OptionAccessingHost* optionHost, AccountInfoAccessingHost* accountInfo, QWidget* parent) : QWidget(parent), m_otr(otr), m_optionHost(optionHost), m_accountInfo(accountInfo) { QVBoxLayout* mainLayout = new QVBoxLayout(this); QTabWidget* tabWidget = new QTabWidget(this); tabWidget->addTab(new FingerprintWidget(m_otr, tabWidget), tr("Known fingerprints")); tabWidget->addTab(new PrivKeyWidget(m_accountInfo, m_otr, tabWidget), tr("My private keys")); tabWidget->addTab(new ConfigOtrWidget(m_optionHost, m_otr, tabWidget), tr("Configuration")); mainLayout->addWidget(tabWidget); setLayout(mainLayout); } //============================================================================= ConfigOtrWidget::ConfigOtrWidget(OptionAccessingHost* optionHost, OtrMessaging* otr, QWidget* parent) : QWidget(parent), m_optionHost(optionHost), m_otr(otr) { QVBoxLayout* layout = new QVBoxLayout(this); QGroupBox* policyGroup = new QGroupBox(tr("OTR Policy"), this); QVBoxLayout* policyLayout = new QVBoxLayout(policyGroup); m_policy = new QButtonGroup(policyGroup); QRadioButton* polDisable = new QRadioButton(tr("Disable private messaging"), policyGroup); QRadioButton* polEnable = new QRadioButton(tr("Manually start private messaging"), policyGroup); QRadioButton* polAuto = new QRadioButton(tr("Automatically start private messaging"), policyGroup); QRadioButton* polRequire = new QRadioButton(tr("Require private messaging"), policyGroup); m_endWhenOffline = new QCheckBox(tr("End session when contact goes offline"), this); m_policy->addButton(polDisable, OTR_POLICY_OFF); m_policy->addButton(polEnable, OTR_POLICY_ENABLED); m_policy->addButton(polAuto, OTR_POLICY_AUTO); m_policy->addButton(polRequire, OTR_POLICY_REQUIRE); policyLayout->addWidget(polDisable); policyLayout->addWidget(polEnable); policyLayout->addWidget(polAuto); policyLayout->addWidget(polRequire); policyGroup->setLayout(policyLayout); layout->addWidget(policyGroup); layout->addWidget(m_endWhenOffline); layout->addStretch(); setLayout(layout); int policyOption = m_optionHost->getPluginOption(OPTION_POLICY, DEFAULT_POLICY).toInt(); if ((policyOption < OTR_POLICY_OFF) || (policyOption > OTR_POLICY_REQUIRE)) { policyOption = static_cast(OTR_POLICY_ENABLED); } bool endWhenOfflineOption = m_optionHost->getPluginOption(OPTION_END_WHEN_OFFLINE, DEFAULT_END_WHEN_OFFLINE).toBool(); m_policy->button(policyOption)->setChecked(true); m_endWhenOffline->setChecked(endWhenOfflineOption); updateOptions(); connect(m_policy, SIGNAL(buttonClicked(int)), SLOT(updateOptions())); connect(m_endWhenOffline, SIGNAL(stateChanged(int)), SLOT(updateOptions())); } // --------------------------------------------------------------------------- void ConfigOtrWidget::updateOptions() { OtrPolicy policy = static_cast(m_policy->checkedId()); m_optionHost->setPluginOption(OPTION_POLICY, policy); m_optionHost->setPluginOption(OPTION_END_WHEN_OFFLINE, m_endWhenOffline->checkState() == Qt::Checked); m_otr->setPolicy(policy); } //============================================================================= FingerprintWidget::FingerprintWidget(OtrMessaging* otr, QWidget* parent) : QWidget(parent), m_otr(otr), m_table(new QTableView(this)), m_tableModel(new QStandardItemModel(this)), m_fingerprints() { QVBoxLayout* mainLayout = new QVBoxLayout(this); m_table->setShowGrid(true); m_table->setEditTriggers(0); m_table->setSelectionBehavior(QAbstractItemView::SelectRows); m_table->setContextMenuPolicy(Qt::CustomContextMenu); m_table->setSortingEnabled(true); connect(m_table, SIGNAL(customContextMenuRequested(const QPoint&)), SLOT(contextMenu(const QPoint&))); mainLayout->addWidget(m_table); QPushButton* deleteButton = new QPushButton(tr("Delete fingerprint"), this); QPushButton* verifyButton = new QPushButton(tr("Verify fingerprint"), this); connect(deleteButton,SIGNAL(clicked()),SLOT(deleteFingerprint())); connect(verifyButton,SIGNAL(clicked()),SLOT(verifyFingerprint())); QHBoxLayout* buttonLayout = new QHBoxLayout(); buttonLayout->addWidget(deleteButton); buttonLayout->addWidget(verifyButton); mainLayout->addLayout(buttonLayout); setLayout(mainLayout); updateData(); } //----------------------------------------------------------------------------- void FingerprintWidget::updateData() { int sortSection = m_table->horizontalHeader()->sortIndicatorSection(); Qt::SortOrder sortOrder = m_table->horizontalHeader()->sortIndicatorOrder(); m_tableModel->clear(); m_tableModel->setColumnCount(5); m_tableModel->setHorizontalHeaderLabels(QStringList() << tr("Account") << tr("User") << tr("Fingerprint") << tr("Verified") << tr("Status")); m_fingerprints = m_otr->getFingerprints(); QListIterator fingerprintIt(m_fingerprints); int fpIndex = 0; while(fingerprintIt.hasNext()) { QList row; Fingerprint fp = fingerprintIt.next(); QStandardItem* item = new QStandardItem(m_otr->humanAccount(fp.account)); item->setData(QVariant(fpIndex)); row.append(item); row.append(new QStandardItem(fp.username)); row.append(new QStandardItem(fp.fingerprintHuman)); row.append(new QStandardItem(fp.trust)); row.append(new QStandardItem(m_otr->getMessageStateString(fp.account, fp.username))); m_tableModel->appendRow(row); fpIndex++; } m_table->setModel(m_tableModel); m_table->sortByColumn(sortSection, sortOrder); m_table->resizeColumnsToContents(); } //----------------------------------------------------------------------------- //** slots ** void FingerprintWidget::deleteFingerprint() { if (!m_table->selectionModel()->hasSelection()) { return; } foreach(QModelIndex selectIndex, m_table->selectionModel()->selectedRows()) { int fpIndex = m_tableModel->item(selectIndex.row(), 0)->data().toInt(); QString msg(tr("Are you sure you want to delete the following fingerprint?") + "\n\n" + tr("Account: ") + m_otr->humanAccount(m_fingerprints[fpIndex].account) + "\n" + tr("User: ") + m_fingerprints[fpIndex].username + "\n" + tr("Fingerprint: ") + m_fingerprints[fpIndex].fingerprintHuman); QMessageBox mb(QMessageBox::Question, tr("Psi OTR"), msg, QMessageBox::Yes | QMessageBox::No, this, Qt::Dialog | Qt::MSWindowsFixedSizeDialogHint); if (mb.exec() == QMessageBox::Yes) { m_otr->deleteFingerprint(m_fingerprints[fpIndex]); } } updateData(); } //----------------------------------------------------------------------------- void FingerprintWidget::verifyFingerprint() { if (!m_table->selectionModel()->hasSelection()) { return; } foreach(QModelIndex selectIndex, m_table->selectionModel()->selectedRows()) { int fpIndex = m_tableModel->item(selectIndex.row(), 0)->data().toInt(); QString msg(tr("Have you verified that this is in fact the correct fingerprint?") + "\n\n" + tr("Account: ") + m_otr->humanAccount(m_fingerprints[fpIndex].account) + "\n" + tr("User: ") + m_fingerprints[fpIndex].username + "\n" + tr("Fingerprint: ") + m_fingerprints[fpIndex].fingerprintHuman); QMessageBox mb(QMessageBox::Question, tr("Psi OTR"), msg, QMessageBox::Yes | QMessageBox::No, this, Qt::Dialog | Qt::MSWindowsFixedSizeDialogHint); m_otr->verifyFingerprint(m_fingerprints[fpIndex], (mb.exec() == QMessageBox::Yes)); } updateData(); } //----------------------------------------------------------------------------- void FingerprintWidget::copyFingerprint() { if (!m_table->selectionModel()->hasSelection()) { return; } QString text; foreach(QModelIndex selectIndex, m_table->selectionModel()->selectedRows(1)) { int fpIndex = m_tableModel->item(selectIndex.row(), 0)->data().toInt(); if (!text.isEmpty()) { text += "\n"; } text += m_fingerprints[fpIndex].fingerprintHuman; } QClipboard* clipboard = QApplication::clipboard(); clipboard->setText(text); } //----------------------------------------------------------------------------- void FingerprintWidget::contextMenu(const QPoint& pos) { QModelIndex index = m_table->indexAt(pos); if (!index.isValid()) { return; } QMenu* menu = new QMenu(this); menu->addAction(QIcon::fromTheme("edit-delete"), tr("Delete"), this, SLOT(deleteFingerprint())); menu->addAction(QIcon(":/otrplugin/otr_unverified.png"), tr("Verify fingerprint"), this, SLOT(verifyFingerprint())); menu->addAction(QIcon::fromTheme("edit-copy"), tr("Copy fingerprint"), this, SLOT(copyFingerprint())); menu->exec(QCursor::pos()); } //============================================================================= PrivKeyWidget::PrivKeyWidget(AccountInfoAccessingHost* accountInfo, OtrMessaging* otr, QWidget* parent) : QWidget(parent), m_accountInfo(accountInfo), m_otr(otr), m_table(new QTableView(this)), m_tableModel(new QStandardItemModel(this)), m_keys() { QVBoxLayout* mainLayout = new QVBoxLayout(this); m_accountBox = new QComboBox(this); QString id; int accountIndex = 0; while ((id = m_accountInfo->getId(accountIndex)) != "-1") { m_accountBox->addItem(m_accountInfo->getName(accountIndex), QVariant(id)); accountIndex++; } QPushButton* generateButton = new QPushButton(tr("Generate new key"), this); connect(generateButton,SIGNAL(clicked()),SLOT(generateKey())); QHBoxLayout* generateLayout = new QHBoxLayout(); generateLayout->addWidget(m_accountBox); generateLayout->addWidget(generateButton); mainLayout->addLayout(generateLayout); mainLayout->addWidget(m_table); QPushButton* deleteButton = new QPushButton(tr("Delete key"), this); connect(deleteButton,SIGNAL(clicked()),SLOT(deleteKey())); QHBoxLayout* buttonLayout = new QHBoxLayout(); buttonLayout->addWidget(deleteButton); mainLayout->addLayout(buttonLayout); setLayout(mainLayout); m_table->setShowGrid(true); m_table->setEditTriggers(0); m_table->setSelectionBehavior(QAbstractItemView::SelectRows); m_table->setSortingEnabled(true); m_table->setContextMenuPolicy(Qt::CustomContextMenu); connect(m_table, SIGNAL(customContextMenuRequested(const QPoint&)), SLOT(contextMenu(const QPoint&))); updateData(); } //----------------------------------------------------------------------------- void PrivKeyWidget::updateData() { int sortSection = m_table->horizontalHeader()->sortIndicatorSection(); Qt::SortOrder sortOrder = m_table->horizontalHeader()->sortIndicatorOrder(); m_tableModel->clear(); m_tableModel->setColumnCount(2); m_tableModel->setHorizontalHeaderLabels(QStringList() << tr("Account") << tr("Fingerprint")); m_keys = m_otr->getPrivateKeys(); QHash::iterator keyIt; for (keyIt = m_keys.begin(); keyIt != m_keys.end(); ++keyIt) { QList row; QStandardItem* accItem = new QStandardItem(m_otr->humanAccount(keyIt.key())); accItem->setData(QVariant(keyIt.key())); row.append(accItem); row.append(new QStandardItem(keyIt.value())); m_tableModel->appendRow(row); } m_table->setModel(m_tableModel); m_table->sortByColumn(sortSection, sortOrder); m_table->resizeColumnsToContents(); } //----------------------------------------------------------------------------- void PrivKeyWidget::deleteKey() { if (!m_table->selectionModel()->hasSelection()) { return; } foreach(QModelIndex selectIndex, m_table->selectionModel()->selectedRows(1)) { QString fpr(m_tableModel->item(selectIndex.row(), 1)->text()); QString account(m_tableModel->item(selectIndex.row(), 0)->data().toString()); QString msg(tr("Are you sure you want to delete the following key?") + "\n\n" + tr("Account: ") + m_otr->humanAccount(account) + "\n" + tr("Fingerprint: ") + fpr); QMessageBox mb(QMessageBox::Question, tr("Psi OTR"), msg, QMessageBox::Yes | QMessageBox::No, this, Qt::Dialog | Qt::MSWindowsFixedSizeDialogHint); if (mb.exec() == QMessageBox::Yes) { m_otr->deleteKey(account); } } updateData(); } //----------------------------------------------------------------------------- void PrivKeyWidget::generateKey() { int accountIndex = m_accountBox->currentIndex(); if (accountIndex == -1) { return; } QString accountName(m_accountBox->currentText()); QString accountId(m_accountBox->itemData(accountIndex).toString()); if (m_keys.contains(accountId)) { QString msg(tr("Are you sure you want to overwrite the following key?") + "\n\n" + tr("Account: ") + accountName + "\n" + tr("Fingerprint: ") + m_keys.value(accountId)); QMessageBox mb(QMessageBox::Question, tr("Psi OTR"), msg, QMessageBox::Yes | QMessageBox::No, this, Qt::Dialog | Qt::MSWindowsFixedSizeDialogHint); if (mb.exec() == QMessageBox::No) { return; } } m_otr->generateKey(accountId); updateData(); } //----------------------------------------------------------------------------- void PrivKeyWidget::copyFingerprint() { if (!m_table->selectionModel()->hasSelection()) { return; } QString text; foreach(QModelIndex selectIndex, m_table->selectionModel()->selectedRows(1)) { if (!text.isEmpty()) { text += "\n"; } text += m_tableModel->item(selectIndex.row(), 1)->text(); } QClipboard* clipboard = QApplication::clipboard(); clipboard->setText(text); } //----------------------------------------------------------------------------- void PrivKeyWidget::contextMenu(const QPoint& pos) { QModelIndex index = m_table->indexAt(pos); if (!index.isValid()) { return; } QMenu* menu = new QMenu(this); menu->addAction(QIcon::fromTheme("edit-delete"), tr("Delete"), this, SLOT(deleteKey())); menu->addAction(QIcon::fromTheme("edit-copy"), tr("Copy fingerprint"), this, SLOT(copyFingerprint())); menu->exec(QCursor::pos()); } //----------------------------------------------------------------------------- } // namespace psiotr plugins-1.5/generic/otrplugin/src/psiotrconfig.h000066400000000000000000000077311336777360500221760ustar00rootroot00000000000000/* * psiotrconfig.h - Configuration dialogs * * Off-the-Record Messaging plugin for Psi+ * Copyright (C) 2007-2011 Timo Engel (timo-e@freenet.de) * 2011 Florian Fieber * * 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, see . * */ #ifndef PSIOTRCONFIG_H_ #define PSIOTRCONFIG_H_ #include "otrmessaging.h" #include #include class OptionAccessingHost; class AccountInfoAccessingHost; class QButtonGroup; class QComboBox; class QCheckBox; class QStandardItemModel; class QTableView; class QPoint; // --------------------------------------------------------------------------- namespace psiotr { // --------------------------------------------------------------------------- const QString OPTION_POLICY = "otr-policy"; const QVariant DEFAULT_POLICY = QVariant(OTR_POLICY_ENABLED); const QString OPTION_END_WHEN_OFFLINE = "end-session-when-offline"; const QVariant DEFAULT_END_WHEN_OFFLINE = QVariant(false); // --------------------------------------------------------------------------- /** * This dialog appears in the 'Plugins' section of the Psi configuration. */ class ConfigDialog : public QWidget { Q_OBJECT public: ConfigDialog(OtrMessaging* otr, OptionAccessingHost* optionHost, AccountInfoAccessingHost* accountInfo, QWidget* parent = 0); private: OtrMessaging* m_otr; OptionAccessingHost* m_optionHost; AccountInfoAccessingHost* m_accountInfo; }; // --------------------------------------------------------------------------- /** * Configure OTR policy. */ class ConfigOtrWidget : public QWidget { Q_OBJECT public: ConfigOtrWidget(OptionAccessingHost* optionHost, OtrMessaging* otr, QWidget* parent = 0); private: OptionAccessingHost* m_optionHost; OtrMessaging* m_otr; QButtonGroup* m_policy; QCheckBox* m_endWhenOffline; private slots: void updateOptions(); }; // --------------------------------------------------------------------------- /** * Show fingerprint of your contacts. */ class FingerprintWidget : public QWidget { Q_OBJECT public: FingerprintWidget(OtrMessaging* otr, QWidget* parent = 0); protected: void updateData(); private: OtrMessaging* m_otr; QTableView* m_table; QStandardItemModel* m_tableModel; QList m_fingerprints; private slots: void deleteFingerprint(); void verifyFingerprint(); void copyFingerprint(); void contextMenu(const QPoint& pos); }; // --------------------------------------------------------------------------- /** * Display a table with account and fingerprint of private key. */ class PrivKeyWidget : public QWidget { Q_OBJECT public: PrivKeyWidget(AccountInfoAccessingHost* accountInfo, OtrMessaging* otr, QWidget* parent); protected: void updateData(); private: AccountInfoAccessingHost* m_accountInfo; OtrMessaging* m_otr; QTableView* m_table; QStandardItemModel* m_tableModel; QHash m_keys; QComboBox* m_accountBox; private slots: void deleteKey(); void generateKey(); void copyFingerprint(); void contextMenu(const QPoint& pos); }; //----------------------------------------------------------------------------- } // namespace psiotr #endif plugins-1.5/generic/otrplugin/src/psiotrplugin.cpp000066400000000000000000000673461336777360500225720ustar00rootroot00000000000000/* * psiotrplugin.cpp * * Off-the-Record Messaging plugin for Psi+ * Copyright (C) 2007-2011 Timo Engel (timo-e@freenet.de) * 2011 Florian Fieber * * This program was originally written as part of a diplom thesis * advised by Prof. Dr. Ruediger Weis (PST Labor) * at the Technical University of Applied Sciences Berlin. * * 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, see . * */ #include "psiotrplugin.h" #include "psiotrclosure.h" #include "psiotrconfig.h" #include "htmltidy.h" #include "applicationinfoaccessinghost.h" #include "psiaccountcontrollinghost.h" #include "accountinfoaccessinghost.h" #include "contactinfoaccessinghost.h" #include "iconfactoryaccessinghost.h" #include #include #include namespace psiotr { // --------------------------------------------------------------------------- namespace { // --------------------------------------------------------------------------- /** * Removes the resource from a given JID. * Example: * removeResource("user@jabber.org/Home") * returns "user@jabber.org" */ QString removeResource(const QString& aJid) { QString addr(aJid); int pos = aJid.indexOf("/"); if (pos > -1) { addr.truncate(pos); } return addr; } // --------------------------------------------------------------------------- /** * Reverts Qt::escape() */ QString unescape(const QString& escaped) { QString plain(escaped); plain.replace("<", "<") .replace(">", ">") .replace(""", "\"") .replace("&", "&"); return plain; } // --------------------------------------------------------------------------- /** * Converts HTML to plaintext */ QString htmlToPlain(const QString& html) { QString plain(html); plain.replace(QRegExp(" ?\\n"), " ") .replace(QRegExp("]*)?/>"), "\n") .replace(QRegExp("]*)?>([^<]+)
"), "*\\1*") .replace(QRegExp("]*)?>([^<]+)
"), "/\\1/") .replace(QRegExp("]*)?>([^<]+)"), "_\\1_") .remove(QRegExp("<[^>]*>")); return plain; } // --------------------------------------------------------------------------- } // namespace // =========================================================================== PsiOtrPlugin::PsiOtrPlugin() : m_enabled(false), m_otrConnection(NULL), m_onlineUsers(), m_optionHost(NULL), m_senderHost(NULL), m_applicationInfo(NULL), m_accountHost(NULL), m_accountInfo(NULL), m_contactInfo(NULL), m_iconHost(NULL), m_psiEvent(NULL), m_messageBoxList() { } // --------------------------------------------------------------------------- PsiOtrPlugin::~PsiOtrPlugin() { } // --------------------------------------------------------------------------- QString PsiOtrPlugin::name() const { return "Off-the-Record Messaging Plugin"; } // --------------------------------------------------------------------------- QString PsiOtrPlugin::shortName() const { return "otr"; } // --------------------------------------------------------------------------- QString PsiOtrPlugin::version() const { return "1.0.3"; } // --------------------------------------------------------------------------- QWidget* PsiOtrPlugin::options() { if (!m_enabled) { return 0; } else { return new ConfigDialog(m_otrConnection, m_optionHost, m_accountInfo); } } // --------------------------------------------------------------------------- bool PsiOtrPlugin::enable() { QVariant policyOption = m_optionHost->getPluginOption(OPTION_POLICY, DEFAULT_POLICY); m_otrConnection = new OtrMessaging(this, static_cast(policyOption.toInt())); m_enabled = true; QFile f(":/otrplugin/otr_yes.png"); f.open(QIODevice::ReadOnly); m_iconHost->addIcon("otrplugin/otr_yes", f.readAll()); f.close(); f.setFileName(":/otrplugin/otr_no.png"); f.open(QIODevice::ReadOnly); m_iconHost->addIcon("otrplugin/otr_no", f.readAll()); f.close(); f.setFileName(":/otrplugin/otr_unverified.png"); f.open(QIODevice::ReadOnly); m_iconHost->addIcon("otrplugin/otr_unverified", f.readAll()); f.close(); return true; } // --------------------------------------------------------------------------- bool PsiOtrPlugin::disable() { foreach(QString account, m_onlineUsers.keys()) { foreach(QString contact, m_onlineUsers.value(account).keys()) { if (m_onlineUsers[account][contact]->encrypted()) { m_otrConnection->endSession(account, contact); } m_onlineUsers[account][contact]->disable(); delete m_onlineUsers[account][contact]; } m_onlineUsers[account].clear(); } m_onlineUsers.clear(); while (!m_messageBoxList.empty()) { qDeleteAll(m_messageBoxList.begin(), m_messageBoxList.end()); m_messageBoxList.clear(); } delete m_otrConnection; m_enabled = false; return true; } // --------------------------------------------------------------------------- void PsiOtrPlugin::applyOptions() { } // --------------------------------------------------------------------------- void PsiOtrPlugin::restoreOptions() { } QPixmap PsiOtrPlugin::icon() const { return QPixmap(":/otrplugin/otr_yes.png"); } //----------------------------------------------------------------------------- QString PsiOtrPlugin::pluginInfo() { return QString("%1
" "%2

" "%3" "
" "
%4
%5
" "
%6
%7
" "
%8
%9
" "
%10
%11
" "
" "%12") .arg(tr("Off-the-Record Messaging plugin for Psi+")) .arg(tr("Authors: %1") .arg("Timo Engel, Florian Fieber")) .arg(tr("Off-the-Record (OTR) Messaging allows you to have private " "conversations over instant messaging by providing:")) .arg(tr("Encryption")) .arg(tr("No one else can read your instant messages.")) .arg(tr("Authentication")) .arg(tr("You are assured the correspondent is who you think it is.")) .arg(tr("Deniability")) .arg(tr("The messages you send do not have digital signatures that " "are checkable by a third party. Anyone can forge messages " "after a conversation to make them look like they came from " "you. However, during a conversation, your correspondent is " "assured the messages he sees are authentic and unmodified.")) .arg(tr("Perfect forward secrecy")) .arg(tr("If you lose control of your private keys, no previous " "conversation is compromised.")) .arg(tr("For further information, see " "<http://www.cypherpunks.ca/otr/>.")); } //----------------------------------------------------------------------------- bool PsiOtrPlugin::processEvent(int accountIndex, QDomElement& e) { bool ignore = false; QDomElement messageElement = e.firstChildElement("message"); if (m_enabled && e.attribute("type") == "MessageEvent" && !messageElement.isNull() && messageElement.attribute("type") != "error" && messageElement.attribute("type") != "groupchat" && e.elementsByTagNameNS("urn:xmpp:carbons:2", "sent").isEmpty() && e.elementsByTagNameNS("urn:xmpp:carbons:2", "received").isEmpty()) { QString contact = getCorrectJid(accountIndex, messageElement.attribute("from")); QString account = m_accountInfo->getId(accountIndex); QDomElement htmlElement = messageElement.firstChildElement("html"); QDomElement plainBody = messageElement.firstChildElement("body"); QString cyphertext; if (!htmlElement.isNull()) { QTextStream textStream(&cyphertext); htmlElement.firstChildElement("body").save(textStream, 0); } else if (!plainBody.isNull()) { #ifdef HAVE_QT5 cyphertext = plainBody.firstChild().toText().nodeValue().toHtmlEscaped(); #else cyphertext = Qt::escape(plainBody.firstChild().toText().nodeValue()); #endif } else { return false; } QString decrypted; OtrMessageType messageType = m_otrConnection->decryptMessage( account, contact, cyphertext, decrypted); switch (messageType) { case OTR_MESSAGETYPE_NONE: break; case OTR_MESSAGETYPE_IGNORE: ignore = true; break; case OTR_MESSAGETYPE_OTR: QString bodyText; bool isHTML = !htmlElement.isNull() || Qt::mightBeRichText(decrypted); if (!isHTML) { bodyText = decrypted; } else { HtmlTidy htmlTidy("" + decrypted + ""); decrypted = htmlTidy.output(); bodyText = htmlToPlain(decrypted); // replace html body if (htmlElement.isNull()) { htmlElement = e.ownerDocument().createElement("html"); htmlElement.setAttribute("xmlns", "http://jabber.org/protocol/xhtml-im"); messageElement.appendChild(htmlElement); } else { htmlElement.removeChild(htmlElement.firstChildElement("body")); } QDomDocument document; int errorLine = 0, errorColumn = 0; QString errorText; if (document.setContent(decrypted, true, &errorText, &errorLine, &errorColumn)) { htmlElement.appendChild(document.documentElement()); } else { qWarning() << "---- parsing error:\n" << decrypted << "\n----\n" << errorText << " line:" << errorLine << " column:" << errorColumn; messageElement.removeChild(htmlElement); } } // replace plaintext body plainBody.removeChild(plainBody.firstChild()); plainBody.appendChild(e.ownerDocument().createTextNode(unescape(bodyText))); break; } } return ignore; } //----------------------------------------------------------------------------- bool PsiOtrPlugin::processMessage(int, const QString&, const QString&, const QString&) { return false; } //----------------------------------------------------------------------------- bool PsiOtrPlugin::processOutgoingMessage(int accountIndex, const QString& contact, QString& body, const QString& type, QString&) { if (!m_enabled || type == "groupchat") { return false; } QString account = m_accountInfo->getId(accountIndex); QString encrypted = m_otrConnection->encryptMessage( account, getCorrectJid(accountIndex, contact), #ifdef HAVE_QT5 body.toHtmlEscaped()); #else Qt::escape(body)); #endif //if there has been an error, drop the message if (encrypted.isEmpty()) { return true; } body = unescape(encrypted); return false; } // --------------------------------------------------------------------------- void PsiOtrPlugin::logout(int accountIndex) { if (!m_enabled) { return; } QString account = m_accountInfo->getId(accountIndex); if (m_onlineUsers.contains(account)) { foreach(QString contact, m_onlineUsers.value(account).keys()) { m_otrConnection->endSession(account, contact); m_onlineUsers[account][contact]->setIsLoggedIn(false); m_onlineUsers[account][contact]->updateMessageState(); } } } //----------------------------------------------------------------------------- void PsiOtrPlugin::setOptionAccessingHost(OptionAccessingHost* host) { m_optionHost = host; } //----------------------------------------------------------------------------- void PsiOtrPlugin::optionChanged(const QString&) { QVariant policyOption = m_optionHost->getPluginOption(OPTION_POLICY, DEFAULT_POLICY); m_otrConnection->setPolicy(static_cast(policyOption.toInt())); } //----------------------------------------------------------------------------- void PsiOtrPlugin::setStanzaSendingHost(StanzaSendingHost* host) { m_senderHost = host; } //----------------------------------------------------------------------------- void PsiOtrPlugin::setApplicationInfoAccessingHost(ApplicationInfoAccessingHost* host) { m_applicationInfo = host; } //----------------------------------------------------------------------------- void PsiOtrPlugin::setPsiAccountControllingHost(PsiAccountControllingHost* host) { m_accountHost = host; } //----------------------------------------------------------------------------- void PsiOtrPlugin::setAccountInfoAccessingHost(AccountInfoAccessingHost* host) { m_accountInfo = host; } //----------------------------------------------------------------------------- void PsiOtrPlugin::setContactInfoAccessingHost(ContactInfoAccessingHost* host) { m_contactInfo = host; } //----------------------------------------------------------------------------- void PsiOtrPlugin::setIconFactoryAccessingHost(IconFactoryAccessingHost* host) { m_iconHost = host; } //----------------------------------------------------------------------------- void PsiOtrPlugin::setEventCreatingHost(EventCreatingHost *host) { m_psiEvent = host; } //----------------------------------------------------------------------------- bool PsiOtrPlugin::incomingStanza(int accountIndex, const QDomElement& xml) { if (!m_enabled || xml.nodeName() != "presence") { return false; } QString account = m_accountInfo->getId(accountIndex); QString contact = getCorrectJid(accountIndex, xml.attribute("from")); QString type = xml.attribute("type", "available"); if (type == "available") { if (!m_onlineUsers.value(account).contains(contact)) { m_onlineUsers[account][contact] = new PsiOtrClosure(account, contact, m_otrConnection); } m_onlineUsers[account][contact]->setIsLoggedIn(true); } else if (type == "unavailable") { if (m_onlineUsers.contains(account) && m_onlineUsers.value(account).contains(contact)) { if (m_optionHost->getPluginOption(OPTION_END_WHEN_OFFLINE, DEFAULT_END_WHEN_OFFLINE).toBool()) { m_otrConnection->expireSession(account, contact); } m_onlineUsers[account][contact]->setIsLoggedIn(false); m_onlineUsers[account][contact]->updateMessageState(); } } return false; } //----------------------------------------------------------------------------- bool PsiOtrPlugin::outgoingStanza(int accountIndex, QDomElement& xml) { if (!m_enabled || xml.nodeName() != "message") { return false; } QString account = m_accountInfo->getId(accountIndex); QString contact = getCorrectJid(accountIndex, xml.attribute("to")); if (!m_onlineUsers.value(account).contains(contact)) { m_onlineUsers[account][contact] = new PsiOtrClosure(account, contact, m_otrConnection); } QDomElement htmlElement = xml.firstChildElement("html"); if (m_onlineUsers[account][contact]->encrypted() && !htmlElement.isNull()) { xml.removeChild(htmlElement); } if (m_onlineUsers[account][contact]->encrypted()) { if (xml.attribute("to").contains("/")) { // if not a bare jid htmlElement = xml.ownerDocument().createElementNS("urn:xmpp:hints" ,"no-copy"); xml.appendChild(htmlElement); } htmlElement = xml.ownerDocument().createElementNS("urn:xmpp:hints", "no-permanent-store"); xml.appendChild(htmlElement); htmlElement = xml.ownerDocument().createElementNS("urn:xmpp:carbons:2", "private"); xml.appendChild(htmlElement); } return false; } //----------------------------------------------------------------------------- QList PsiOtrPlugin::getButtonParam() { return QList(); } //----------------------------------------------------------------------------- QAction* PsiOtrPlugin::getAction(QObject* parent, int accountIndex, const QString& contactJid) { if (!m_enabled) { return 0; } QString contact = getCorrectJid(accountIndex, contactJid); QString account = m_accountInfo->getId(accountIndex); if (!m_onlineUsers.value(account).contains(contact)) { m_onlineUsers[account][contact] = new PsiOtrClosure(account, contact, m_otrConnection); } return m_onlineUsers[account][contact]->getChatDlgMenu(parent); } //----------------------------------------------------------------------------- QString PsiOtrPlugin::dataDir() { return m_applicationInfo->appCurrentProfileDir( ApplicationInfoAccessingHost::DataLocation); } //----------------------------------------------------------------------------- void PsiOtrPlugin::sendMessage(const QString& account, const QString& contact, const QString& message) { int accountIndex = getAccountIndexById(account); if (accountIndex != -1) { m_senderHost->sendMessage(accountIndex, contact, htmlToPlain(message), "", "chat"); } } //----------------------------------------------------------------------------- bool PsiOtrPlugin::isLoggedIn(const QString& account, const QString& contact) { if (m_onlineUsers.contains(account) && m_onlineUsers.value(account).contains(contact)) { return m_onlineUsers.value(account).value(contact)->isLoggedIn(); } return false; } //----------------------------------------------------------------------------- void PsiOtrPlugin::notifyUser(const QString& account, const QString& contact, const QString& message, const OtrNotifyType& type) { QMessageBox::Icon messageBoxIcon; if (type == OTR_NOTIFY_ERROR) { messageBoxIcon = QMessageBox::Critical; } else if (type == OTR_NOTIFY_WARNING) { messageBoxIcon = QMessageBox::Warning; } else { messageBoxIcon = QMessageBox::Information; } QMessageBox *messageBox = new QMessageBox(messageBoxIcon, tr("Psi OTR"), message, QMessageBox::Ok, NULL, Qt::Dialog | Qt::MSWindowsFixedSizeDialogHint); m_messageBoxList.enqueue(messageBox); m_psiEvent->createNewEvent(getAccountIndexById(account), contact, tr("OTR Plugin: event from %1").arg(contact), this, SLOT(eventActivated())); } //----------------------------------------------------------------------------- void PsiOtrPlugin::eventActivated() { if (!m_messageBoxList.empty()) { QMessageBox *messageBox = m_messageBoxList.dequeue(); if (messageBox) { messageBox->exec(); delete messageBox; } } } //----------------------------------------------------------------------------- bool PsiOtrPlugin::displayOtrMessage(const QString& account, const QString& contact, const QString& message) { return appendSysMsg(account, contact, message); } //----------------------------------------------------------------------------- void PsiOtrPlugin::stateChange(const QString& account, const QString& contact, OtrStateChange change) { if (!m_onlineUsers.value(account).contains(contact)) { m_onlineUsers[account][contact] = new PsiOtrClosure(account, contact, m_otrConnection); } m_onlineUsers[account][contact]->updateMessageState(); bool verified = m_otrConnection->isVerified(account, contact); bool encrypted = m_onlineUsers[account][contact]->encrypted(); QString msg; QString icon; switch (change) { case OTR_STATECHANGE_GOINGSECURE: msg = encrypted? tr("Attempting to refresh the private conversation") : tr("Attempting to start a private conversation"); break; case OTR_STATECHANGE_GONESECURE: msg = verified? tr("Private conversation started") : tr("Unverified conversation started"); icon = verified? "otrplugin/otr_yes" : "otrplugin/otr_unverified"; break; case OTR_STATECHANGE_GONEINSECURE: msg = tr("Private conversation lost"); icon = "otrplugin/otr_no"; break; case OTR_STATECHANGE_CLOSE: msg = tr("Private conversation closed"); icon = "otrplugin/otr_no"; break; case OTR_STATECHANGE_REMOTECLOSE: msg = tr("%1 has ended the private conversation with you; " "you should do the same.") .arg(humanContact(account, contact)); icon = "otrplugin/otr_no"; break; case OTR_STATECHANGE_STILLSECURE: msg = verified? tr("Private conversation refreshed") : tr("Unverified conversation refreshed"); icon = verified? "otrplugin/otr_yes" : "otrplugin/otr_unverified"; break; case OTR_STATECHANGE_TRUST: msg = verified? tr("Contact authenticated") : tr("Contact not authenticated"); icon = verified? "otrplugin/otr_yes" : "otrplugin/otr_unverified"; break; } appendSysMsg(account, contact, msg, icon); } //----------------------------------------------------------------------------- void PsiOtrPlugin::receivedSMP(const QString& account, const QString& contact, const QString& question) { if (m_onlineUsers.contains(account) && m_onlineUsers.value(account).contains(contact)) { m_onlineUsers[account][contact]->receivedSMP(question); } } //----------------------------------------------------------------------------- void PsiOtrPlugin::updateSMP(const QString& account, const QString& contact, int progress) { if (m_onlineUsers.contains(account) && m_onlineUsers.value(account).contains(contact)) { m_onlineUsers[account][contact]->updateSMP(progress); } } //----------------------------------------------------------------------------- void PsiOtrPlugin::stopMessages() { m_enabled = false; } //----------------------------------------------------------------------------- void PsiOtrPlugin::startMessages() { m_enabled = true; } //----------------------------------------------------------------------------- QString PsiOtrPlugin::humanAccount(const QString& accountId) { QString human(getAccountNameById(accountId)); return human.isEmpty()? accountId : human; } //----------------------------------------------------------------------------- QString PsiOtrPlugin::humanAccountPublic(const QString& accountId) { return getAccountJidById(accountId); } //----------------------------------------------------------------------------- QString PsiOtrPlugin::humanContact(const QString& accountId, const QString& contact) { return m_contactInfo->name(getAccountIndexById(accountId), contact); } //----------------------------------------------------------------------------- bool PsiOtrPlugin::appendSysMsg(const QString& account, const QString& contact, const QString& message, const QString& icon) { QString iconTag; if (!icon.isEmpty()) { iconTag = QString(" ").arg(icon); } return m_accountHost->appendSysMsg(getAccountIndexById(account), contact, iconTag + message); } // --------------------------------------------------------------------------- int PsiOtrPlugin::getAccountIndexById(const QString& accountId) { QString id; int accountIndex = 0; while (((id = m_accountInfo->getId(accountIndex)) != "-1") && (id != accountId)) { accountIndex++; } return (id == "-1")? -1 : accountIndex; } // --------------------------------------------------------------------------- QString PsiOtrPlugin::getAccountNameById(const QString& accountId) { return m_accountInfo->getName(getAccountIndexById(accountId)); } // --------------------------------------------------------------------------- QString PsiOtrPlugin::getAccountJidById(const QString& accountId) { return m_accountInfo->getJid(getAccountIndexById(accountId)); } // --------------------------------------------------------------------------- QString PsiOtrPlugin::getCorrectJid(int accountIndex, const QString& fullJid) { QString correctJid; if (m_contactInfo->isPrivate(accountIndex, fullJid)) { correctJid = fullJid; } else { correctJid = removeResource(fullJid); // If the contact is private but not (yet) in the roster, // it will not be known as private. // Therefore, check if the bare Jid is a conference. if (m_contactInfo->isConference(accountIndex, correctJid)) { correctJid = fullJid; } } return correctJid; } //----------------------------------------------------------------------------- } // namespace psiotr //----------------------------------------------------------------------------- #ifndef HAVE_QT5 Q_EXPORT_PLUGIN2(psiOtrPlugin, psiotr::PsiOtrPlugin) #endif //----------------------------------------------------------------------------- plugins-1.5/generic/otrplugin/src/psiotrplugin.h000066400000000000000000000203221336777360500222160ustar00rootroot00000000000000/* * psiotrplugin.h * * Off-the-Record Messaging plugin for Psi+ * Copyright (C) 2007-2011 Timo Engel (timo-e@freenet.de) * 2011 Florian Fieber * * This program was originally written as part of a diplom thesis * advised by Prof. Dr. Ruediger Weis (PST Labor) * at the Technical University of Applied Sciences Berlin. * * 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, see . * */ #ifndef PSIOTRPLUGIN_H_ #define PSIOTRPLUGIN_H_ #include #include #include #include "otrmessaging.h" #include "psiplugin.h" #include "plugininfoprovider.h" #include "eventfilter.h" #include "optionaccessinghost.h" #include "optionaccessor.h" #include "stanzasender.h" #include "stanzasendinghost.h" #include "applicationinfoaccessor.h" #include "psiaccountcontroller.h" #include "stanzafilter.h" #include "toolbariconaccessor.h" #include "accountinfoaccessor.h" #include "contactinfoaccessor.h" #include "iconfactoryaccessor.h" #include "eventcreatinghost.h" #include "eventcreator.h" class ApplicationInfoAccessingHost; class PsiAccountControllingHost; class AccountInfoAccessingHost; class ContactInfoAccessingHost; class IconFactoryAccessingHost; class QDomElement; class QString; class QAction; namespace psiotr { class PsiOtrClosure; //----------------------------------------------------------------------------- class PsiOtrPlugin : public QObject, public PsiPlugin, public PluginInfoProvider, public EventFilter, public EventCreator, public OptionAccessor, public StanzaSender, public ApplicationInfoAccessor, public PsiAccountController, public StanzaFilter, public ToolbarIconAccessor, public AccountInfoAccessor, public ContactInfoAccessor, public IconFactoryAccessor, public OtrCallback { Q_OBJECT #ifdef HAVE_QT5 Q_PLUGIN_METADATA(IID "com.psi-plus.PsiOtrPlugin") #endif Q_INTERFACES(PsiPlugin PluginInfoProvider EventFilter EventCreator OptionAccessor StanzaSender ApplicationInfoAccessor PsiAccountController StanzaFilter ToolbarIconAccessor AccountInfoAccessor ContactInfoAccessor IconFactoryAccessor) public: PsiOtrPlugin(); ~PsiOtrPlugin(); // PsiPlugin virtual QString name() const; virtual QString shortName() const; virtual QString version() const; virtual QWidget* options(); virtual bool enable(); virtual bool disable(); virtual void applyOptions(); virtual void restoreOptions(); virtual QPixmap icon() const; // PluginInfoProvider virtual QString pluginInfo(); // EventFilter virtual bool processEvent(int accountIndex, QDomElement& e); virtual bool processMessage(int accountIndex, const QString& contact, const QString& body, const QString& subject); virtual bool processOutgoingMessage(int accountIndex, const QString& contact, QString& body, const QString& type, QString& subject); virtual void logout(int accountIndex); // EventCreator virtual void setEventCreatingHost(EventCreatingHost *host); // OptionAccessor virtual void setOptionAccessingHost(OptionAccessingHost* host); virtual void optionChanged(const QString& option); // StanzaSender virtual void setStanzaSendingHost(StanzaSendingHost* host); // ApplicationInfoAccessor virtual void setApplicationInfoAccessingHost(ApplicationInfoAccessingHost* host); // PsiAccountController virtual void setPsiAccountControllingHost(PsiAccountControllingHost* host); // StanzaFilter virtual bool incomingStanza(int accountIndex, const QDomElement& xml); virtual bool outgoingStanza(int accountIndex, QDomElement& xml); // ToolbarIconAccessor virtual QList getButtonParam(); virtual QAction* getAction(QObject* parent, int accountIndex, const QString& contact); // AccountInfoAccessor virtual void setAccountInfoAccessingHost(AccountInfoAccessingHost* host); // ContactInfoAccessor virtual void setContactInfoAccessingHost(ContactInfoAccessingHost* host); // IconFactoryAccessingHost virtual void setIconFactoryAccessingHost(IconFactoryAccessingHost* host); // OtrCallback virtual QString dataDir(); virtual void sendMessage(const QString& account, const QString& contact, const QString& message); virtual bool isLoggedIn(const QString& account, const QString& contact); virtual void notifyUser(const QString& account, const QString& contact, const QString& message, const OtrNotifyType& type); virtual bool displayOtrMessage(const QString& account, const QString& contact, const QString& message); virtual void stateChange(const QString& account, const QString& contact, OtrStateChange change); virtual void receivedSMP(const QString& account, const QString& contact, const QString& question); virtual void updateSMP(const QString& account, const QString& contact, int progress); virtual void stopMessages(); virtual void startMessages(); virtual QString humanAccount(const QString& accountId); virtual QString humanAccountPublic(const QString& accountId); virtual QString humanContact(const QString& accountId, const QString& contact); /** * Displays a rich text system message for (account, contact) */ bool appendSysMsg(const QString& account, const QString& contact, const QString& message, const QString& icon = ""); // Helper methods /** * Returns the index of the account identified by accountId or -1 */ int getAccountIndexById(const QString& accountId); /** * Returns the name of the account identified by accountId or "" */ QString getAccountNameById(const QString& accountId); /** * Returns the Jid of the account identified by accountId or "-1" */ QString getAccountJidById(const QString& accountId); private slots: void eventActivated(); private: /** * Returns full Jid for private contacts, * bare Jid for non-private contacts. */ QString getCorrectJid(int accountIndex, const QString& fullJid); bool m_enabled; OtrMessaging* m_otrConnection; QHash > m_onlineUsers; OptionAccessingHost* m_optionHost; StanzaSendingHost* m_senderHost; ApplicationInfoAccessingHost* m_applicationInfo; PsiAccountControllingHost* m_accountHost; AccountInfoAccessingHost* m_accountInfo; ContactInfoAccessingHost* m_contactInfo; IconFactoryAccessingHost* m_iconHost; EventCreatingHost* m_psiEvent; QQueue m_messageBoxList; }; //----------------------------------------------------------------------------- } // namespace psiotr #endif plugins-1.5/generic/pepchangenotifyplugin/000077500000000000000000000000001336777360500210775ustar00rootroot00000000000000plugins-1.5/generic/pepchangenotifyplugin/CMakeLists.txt000066400000000000000000000025051336777360500236410ustar00rootroot00000000000000unset(_HDRS) unset(_UIS) unset(_SRCS) unset(_RSCS) unset(PLUGIN) set( PLUGIN pepchangenotifyplugin ) project(${PLUGIN}) cmake_minimum_required(VERSION 3.1.0) set( CMAKE_AUTOMOC TRUE ) IF( NOT WIN32 ) set( LIB_SUFFIX "" CACHE STRING "Define suffix of directory name (32/64)" ) set( PLUGINS_PATH "lib${LIB_SUFFIX}/psi-plus/plugins" CACHE STRING "Install suffix for plugins" ) ELSE() set( PLUGINS_PATH "psi-plus/plugins" CACHE STRING "Install suffix for plugins" ) ENDIF() add_definitions( -DQT_PLUGIN -DHAVE_QT5 ) include_directories( ${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ../../include . ) set( _SRCS ${PLUGIN}.cpp ) set( _UIS options.ui ) set( _RSCS resources.qrc ) find_package( Qt5 COMPONENTS Widgets Xml REQUIRED ) set(QT_DEPLIBS Qt5::Widgets Qt5::Xml ) qt5_wrap_ui(UIS ${_UIS}) qt5_add_resources(RSCS ${_RSCS}) add_library( ${PLUGIN} MODULE ${_SRCS} ${UIS} ${RSCS} ) target_link_libraries( ${PLUGIN} ${QT_DEPLIBS} ) if( UNIX AND NOT( APPLE OR CYGWIN ) ) install( TARGETS ${PLUGIN} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} ) endif() if( WIN32 ) install( TARGETS ${PLUGIN} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} ) endif() plugins-1.5/generic/pepchangenotifyplugin/changelog.txt000066400000000000000000000045301336777360500235710ustar00rootroot000000000000002013-08-13 v0.1.0 - taurus + Иконка плагина 2012-02-20 v0.0.9 * исправления для нового попап-интерфейса 2011-02-08 v0.0.8 * для проигрывания звука теперь используется новый плагинный интерфейс * настройки времени показа всплывающих уведомлений перенесены в основные настройки приложения 2011-01-28 v0.0.7 * исправлен алгоритм определения активностей и настроений 2011-01-27 v0.0.6 + добавлена возможность задать поконтактный интервал между показом всплывающих уведомлений для событий одного типа + добавлен звук по-умолчанию * различные улучшения и оптимизации 2011-01-17 v0.0.5 + добавлена возможность включать/отключать всплывающие уведомления, когда статус DND * некоторые исправления и улучшения 2011-01-12 v0.0.4 * исправлен обработчик исходящих станз для случая, когда плагин выключен 2010-12-23 v0.0.3 * косметические изменения опций плагина + для настроений и активностей во всплываеющем уведомлении показывается соответсвующая иконка * некоторые оптимизации кода + теперь пятисекундный таймаут применяется и для контактов, только что вышедших в онлайн 2010-12-22 v0.0.2 + теперь для одного и того же джида уведомления о событиях одного типа показываются раз в 5 секунд + уведомления о смене пепов начинают поступать через 30 секунд после выхода вашего аккаунта в онлайн + для каждого вида события - своя иконка в попапе 2010-12-21 v0.0.1 ! initial version plugins-1.5/generic/pepchangenotifyplugin/options.ui000066400000000000000000000100161336777360500231270ustar00rootroot00000000000000 Options 0 0 339 367 Form Per contact delay between the popup notifications of the same events Delay between popups 3 999 seconds Qt::Horizontal 40 20 Disable popups if status is DND Enable notifications for: Tune Mood Activity Geolocation Sound: Qt::Vertical 20 40 <a href="http://psi-plus.com/wiki/plugins#pep_change_notify_plugin">Wiki (Online)</a> true plugins-1.5/generic/pepchangenotifyplugin/pepchangenotify.png000066400000000000000000000007501336777360500247720ustar00rootroot00000000000000PNG  IHDRaIDATx^MKak;7iݹ,tG[&ڔR0Put+SHhJݕ 3r_(R̜sf" a@\MP偵XhRKj%%$K_n G'?#vmɋ 0x>xSwҀq%"0esl 8Ng!6aukvC~ _/.xK\,@ ) 1$l6/.8.Ib/$α;֗ijλ.z:]~7|-vIJ [#:=x6_;[k#q=%^21s,%ag?k2c?.'Ղ39.c #f`IENDB`plugins-1.5/generic/pepchangenotifyplugin/pepchangenotifyplugin.cpp000066400000000000000000000411611336777360500262100ustar00rootroot00000000000000/* * pepchangenotifyplugin.cpp - plugin * Copyright (C) 2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include #include #ifndef HAVE_QT5 #include #endif #include "psiplugin.h" #include "stanzafilter.h" #include "accountinfoaccessor.h" #include "accountinfoaccessinghost.h" #include "optionaccessor.h" #include "optionaccessinghost.h" #include "popupaccessor.h" #include "popupaccessinghost.h" #include "plugininfoprovider.h" #include "applicationinfoaccessinghost.h" #include "applicationinfoaccessor.h" #include "contactinfoaccessor.h" #include "contactinfoaccessinghost.h" #include "iconfactoryaccessinghost.h" #include "iconfactoryaccessor.h" #include "soundaccessinghost.h" #include "soundaccessor.h" #include "ui_options.h" #define cVer "0.1.0" #define constSoundFile "sndfl" #define constInterval "intrvl" #define constTune "tune" #define constMood "mood" #define constActivity "act" //#define constGeoloc "geo" #define constDisableDnd "dsbldnd" #define constContactDelay "contactdelay" #define POPUP_OPTION_NAME "PEP Change Notify Plugin" //delays in secconds const int connectDelay = 30; class PepPlugin: public QObject, public PsiPlugin, public StanzaFilter, public AccountInfoAccessor, public OptionAccessor, public PopupAccessor, public PluginInfoProvider, public SoundAccessor, public ApplicationInfoAccessor, public ContactInfoAccessor, public IconFactoryAccessor { Q_OBJECT #ifdef HAVE_QT5 Q_PLUGIN_METADATA(IID "com.psi-plus.PepPlugin") #endif Q_INTERFACES(PsiPlugin StanzaFilter AccountInfoAccessor OptionAccessor PopupAccessor SoundAccessor PluginInfoProvider ApplicationInfoAccessor ContactInfoAccessor IconFactoryAccessor) public: PepPlugin(); virtual QString name() const; virtual QString shortName() const; virtual QString version() const; virtual QWidget* options(); virtual bool enable(); virtual bool disable(); virtual void applyOptions(); virtual void restoreOptions(); virtual bool incomingStanza(int account, const QDomElement& xml); virtual bool outgoingStanza(int account, QDomElement& xml); virtual void setAccountInfoAccessingHost(AccountInfoAccessingHost* host); virtual void setOptionAccessingHost(OptionAccessingHost* host); virtual void optionChanged(const QString& /*option*/) {}; virtual void setPopupAccessingHost(PopupAccessingHost* host); virtual void setApplicationInfoAccessingHost(ApplicationInfoAccessingHost* host); virtual void setContactInfoAccessingHost(ContactInfoAccessingHost* host); virtual void setIconFactoryAccessingHost(IconFactoryAccessingHost* host); virtual void setSoundAccessingHost(SoundAccessingHost* host); virtual QString pluginInfo(); virtual QPixmap icon() const; private: bool enabled; OptionAccessingHost* psiOptions; AccountInfoAccessingHost *accInfoHost; PopupAccessingHost* popup; ApplicationInfoAccessingHost* appInfo; ContactInfoAccessingHost* contactInfo; IconFactoryAccessingHost* iconHost; SoundAccessingHost* sound_; QString soundFile; //int interval; int delay; bool showMood, showTune, showActivity;//, showGeoloc; bool disableDnd; int popupId; QPointer options_; Ui::Options ui_; struct ContactState { ContactState(const QString& j = QString()) { jid = j; } enum Event { EventTune, EventMood, EventActivity //,EventGeolocation }; QString jid; QMap events; bool operator==(const ContactState& s) { return jid == s.jid; } }; QList states_; QHash lastConnectionTime_; // QHash contactsOnlineTime_; // QList::iterator findContactStateIndex(const QString& jid); bool checkContactState(QList::iterator it, ContactState::Event e); bool checkContactStatus(const QString& jid); bool processJid(const QString& jid, ContactState::Event e); void playSound(const QString& soundFile); void showPopup(const QString& title, const QString& text, const QString& icon); QDomElement getFirstChildElement(const QDomElement& elem); private slots: void checkSound(); void getSound(); void doNotification(const QString& title, const QString& text, const QString& icon); }; #ifndef HAVE_QT5 Q_EXPORT_PLUGIN(PepPlugin); #endif PepPlugin::PepPlugin() : enabled(false) , psiOptions(0) , accInfoHost(0) , popup(0) , appInfo(0) , contactInfo(0) , iconHost(0) , sound_(0) , soundFile("sound/pepnotify.wav") //, interval(5) , delay(60) , showMood(false) , showTune(true) , showActivity(false) // , showGeoloc(false) , disableDnd(false) , popupId(0) { } QString PepPlugin::name() const { return "PEP Change Notify Plugin"; } QString PepPlugin::shortName() const { return "pepplugin"; } QString PepPlugin::version() const { return cVer; } bool PepPlugin::enable() { states_.clear(); lastConnectionTime_.clear(); contactsOnlineTime_.clear(); if(psiOptions) { enabled = true; soundFile = psiOptions->getPluginOption(constSoundFile, QVariant(soundFile)).toString(); showMood = psiOptions->getPluginOption(constMood, QVariant(showMood)).toBool(); showTune = psiOptions->getPluginOption(constTune, QVariant(showTune)).toBool(); showActivity = psiOptions->getPluginOption(constActivity, QVariant(showActivity)).toBool(); // showGeoloc = psiOptions->getPluginOption(constGeoloc, QVariant(showGeoloc)).toBool(); disableDnd = psiOptions->getPluginOption(constDisableDnd, QVariant(disableDnd)).toBool(); delay = psiOptions->getPluginOption(constContactDelay, QVariant(delay)).toInt(); int interval = psiOptions->getPluginOption(constInterval, QVariant(5000)).toInt()/1000; popupId = popup->registerOption(POPUP_OPTION_NAME, interval, "plugins.options."+shortName()+"."+constInterval); } return enabled; } bool PepPlugin::disable() { states_.clear(); lastConnectionTime_.clear(); contactsOnlineTime_.clear(); popup->unregisterOption(POPUP_OPTION_NAME); enabled = false; return true; } QWidget* PepPlugin::options() { if(!enabled) return 0; options_ = new QWidget(); ui_.setupUi(options_); ui_.cb_geoloc->setVisible(false); //FIXME ui_.pb_check->setIcon(iconHost->getIcon("psi/play")); ui_.pb_get->setIcon(iconHost->getIcon("psi/browse")); connect(ui_.pb_check, SIGNAL(clicked()), SLOT(checkSound())); connect(ui_.pb_get, SIGNAL(clicked()), SLOT(getSound())); restoreOptions(); return options_; } bool PepPlugin::incomingStanza(int account, const QDomElement& stanza) { if (enabled) { if(stanza.tagName() == "presence") { QString type = stanza.attribute("type"); QString jid = stanza.attribute("from").split("/").first().toLower(); if(type == "unavailable") { contactsOnlineTime_.remove(jid); } else if(!contactsOnlineTime_.contains(jid)) { contactsOnlineTime_.insert(jid, QTime::currentTime()); } return false; } if(stanza.tagName() == "message") { if(lastConnectionTime_.value(account).secsTo(QTime::currentTime()) < connectDelay) { return false; } if(disableDnd && accInfoHost->getStatus(account) == "dnd") { return false; } QString jid = stanza.attribute("from").split("/").first().toLower(); if(jid == accInfoHost->getJid(account).toLower()) return false; QDomElement event = stanza.firstChildElement("event"); if(!event.isNull() && event.attribute("xmlns").contains("http://jabber.org/protocol/pubsub")) { QDomElement items = event.firstChildElement("items"); if(items.isNull()) return false; QDomElement item = items.firstChildElement("item"); if(item.isNull()) return false; if(showTune) { QDomElement tune = item.firstChildElement("tune"); if(!tune.isNull() && tune.attribute("xmlns") == "http://jabber.org/protocol/tune") { if(!processJid(jid, ContactState::EventTune)) { return false; } QString artist = tune.firstChildElement("artist").text(); QString title = tune.firstChildElement("title").text(); if(!artist.isEmpty() || !title.isEmpty()) { QString str = tr("Now listening: "); if(artist.isEmpty()) { str += title; } else { str += artist; if(!title.isEmpty()) { str += " - " + title; } } QMetaObject::invokeMethod(this, "doNotification", Qt::QueuedConnection, Q_ARG(const QString&, contactInfo->name(account, jid)), Q_ARG(const QString&, str), Q_ARG(const QString&, "pep/tune")); } return false; } } if(showMood) { QDomElement mood = item.firstChildElement("mood"); if(!mood.isNull() && mood.attribute("xmlns") == "http://jabber.org/protocol/mood") { if(!processJid(jid, ContactState::EventMood)) { return false; } QString type = getFirstChildElement(mood).tagName(); if(!type.isEmpty()) { QString text = mood.firstChildElement("text").text(); QString str = tr("Mood changed to \"%1").arg(type); if(!text.isEmpty()) { str += ": " + text; } str += "\""; QMetaObject::invokeMethod(this, "doNotification", Qt::QueuedConnection, Q_ARG(const QString&, contactInfo->name(account, jid)), Q_ARG(const QString&, str), Q_ARG(const QString&, "mood/"+type)); } return false; } } if(showActivity) { QDomElement act = item.firstChildElement("activity"); if(!act.isNull() && act.attribute("xmlns") == "http://jabber.org/protocol/activity") { if(!processJid(jid, ContactState::EventActivity)) { return false; } QString icon; QString type, secType; QDomElement t = getFirstChildElement(act); if(!t.isNull()) { icon = type = t.tagName(); secType = getFirstChildElement(t).tagName(); if(!secType.isEmpty()) icon += "_"+secType; } if(!type.isEmpty()) { QString text = act.firstChildElement("text").text(); QString str = tr("Activity changed to \"%1").arg(type); if(!secType.isEmpty()) { str += " - " + secType; } if(!text.isEmpty()) { str += ": " + text; } str += "\""; QMetaObject::invokeMethod(this, "doNotification", Qt::QueuedConnection, Q_ARG(const QString&, contactInfo->name(account, jid)), Q_ARG(const QString&, str), Q_ARG(const QString&, "activities/"+icon)); } return false; } } } } } return false; } bool PepPlugin::outgoingStanza(int account, QDomElement &xml) { if(enabled) { if(xml.tagName() == "iq" && xml.attribute("type") == "set" && !xml.firstChildElement("session").isNull()) { lastConnectionTime_.insert(account, QTime::currentTime()); } } return false; } void PepPlugin::applyOptions() { if(!options_) return; soundFile = ui_.le_sound->text(); psiOptions->setPluginOption(constSoundFile, QVariant(soundFile)); // interval = ui_.sb_interval->value(); // psiOptions->setPluginOption(constInterval, QVariant(interval)); showActivity = ui_.cb_activity->isChecked(); psiOptions->setPluginOption(constActivity, QVariant(showActivity)); // showGeoloc = ui_.cb_geoloc->isChecked(); // psiOptions->setPluginOption(constGeoloc, QVariant(showGeoloc)); showMood = ui_.cb_mood->isChecked(); psiOptions->setPluginOption(constMood, QVariant(showMood)); showTune = ui_.cb_tune->isChecked(); psiOptions->setPluginOption(constTune, QVariant(showTune)); disableDnd = ui_.cb_disable_dnd->isChecked(); psiOptions->setPluginOption(constDisableDnd, QVariant(disableDnd)); delay = ui_.sb_delay->value(); psiOptions->setPluginOption(constContactDelay, QVariant(delay)); } void PepPlugin::restoreOptions() { if(!options_) return; ui_.le_sound->setText(soundFile); // ui_.sb_interval->setValue(interval); ui_.cb_activity->setChecked(showActivity); // ui_.cb_geoloc->setChecked(showGeoloc); ui_.cb_mood->setChecked(showMood); ui_.cb_tune->setChecked(showTune); ui_.cb_disable_dnd->setChecked(disableDnd); ui_.sb_delay->setValue(delay); } void PepPlugin::setAccountInfoAccessingHost(AccountInfoAccessingHost* host) { accInfoHost = host; } void PepPlugin::setOptionAccessingHost(OptionAccessingHost* host) { psiOptions = host; } void PepPlugin::setPopupAccessingHost(PopupAccessingHost* host) { popup = host; } void PepPlugin::setApplicationInfoAccessingHost(ApplicationInfoAccessingHost *host) { appInfo = host; } void PepPlugin::setContactInfoAccessingHost(ContactInfoAccessingHost *host) { contactInfo = host; } void PepPlugin::setIconFactoryAccessingHost(IconFactoryAccessingHost *host) { iconHost = host; } void PepPlugin::setSoundAccessingHost(SoundAccessingHost *host) { sound_ = host; } void PepPlugin::playSound(const QString& f) { sound_->playSound(f); } void PepPlugin::getSound() { QString fileName = QFileDialog::getOpenFileName(0,tr("Choose a sound file"),"", tr("Sound (*.wav)")); if(fileName.isEmpty()) return; ui_.le_sound->setText(fileName); } void PepPlugin::checkSound() { playSound(ui_.le_sound->text()); } void PepPlugin::showPopup(const QString &title, const QString &text, const QString& icon) { QVariant suppressDnd = psiOptions->getGlobalOption("options.ui.notifications.passive-popups.suppress-while-dnd"); psiOptions->setGlobalOption("options.ui.notifications.passive-popups.suppress-while-dnd", disableDnd); int interval = popup->popupDuration(POPUP_OPTION_NAME); if(interval) { #ifdef HAVE_QT5 popup->initPopup(text.toHtmlEscaped(), title.toHtmlEscaped(), icon, popupId); #else popup->initPopup(Qt::escape(text), Qt::escape(title), icon, popupId); #endif } psiOptions->setGlobalOption("options.ui.notifications.passive-popups.suppress-while-dnd", suppressDnd); } void PepPlugin::doNotification(const QString &title, const QString &text, const QString &icon) { showPopup(title, text, icon); if(psiOptions->getGlobalOption("options.ui.notifications.sounds.enable").toBool()) { playSound(soundFile); } } QList::iterator PepPlugin::findContactStateIndex(const QString &jid) { QList::iterator it = states_.begin(); ContactState s(jid); for(; it != states_.end(); ++it) { if(s == *it) { break; } } if(it == states_.end()) { it = states_.insert(--it, s); } return it; } bool PepPlugin::checkContactState(QList::iterator it, ContactState::Event e) { QTime time = QTime::currentTime(); if((*it).events.contains(e)) { QTime oldTime = (*it).events.value(e); if(oldTime.secsTo(time) < delay) { return false; } } (*it).events.insert(e, time); return true; } bool PepPlugin::checkContactStatus(const QString& jid) { if(!contactsOnlineTime_.contains(jid)) {//такое может произойти, если плагин включили, когда аккаунт уже был в онлайне return true; //а вообще, ивенты от контактов не должны приходить раньше презенсов. } //если такое произойдет - таймаут не сработает QTime contactTime = contactsOnlineTime_.value(jid); return (contactTime.secsTo(QTime::currentTime()) < delay) ? false : true; } bool PepPlugin::processJid(const QString &jid, ContactState::Event e) { if(!checkContactStatus(jid)) { return false; } QList::iterator it = findContactStateIndex(jid); if(!checkContactState(it, e)) { return false; } return true; } QDomElement PepPlugin::getFirstChildElement(const QDomElement &elem) { QDomElement newElem; QDomNode node = elem.firstChild(); while(!node.isNull()) { if(!node.isElement()) { node = node.nextSibling(); continue; } newElem = node.toElement(); break; } return newElem; } QString PepPlugin::pluginInfo() { return tr("Author: ") + "Dealer_WeARE\n" + tr("Email: ") + "wadealer@gmail.com\n\n" + tr("This plugin shows popup notifications when users from your roster changes their mood, tune or activity."); } QPixmap PepPlugin::icon() const { return QPixmap(":/icons/pepchangenotify.png"); } #include "pepchangenotifyplugin.moc" plugins-1.5/generic/pepchangenotifyplugin/pepchangenotifyplugin.pro000066400000000000000000000002761336777360500262300ustar00rootroot00000000000000isEmpty(PSISDK) { include(../../psiplugin.pri) } else { include($$PSISDK/plugins/psiplugin.pri) } SOURCES += pepchangenotifyplugin.cpp FORMS += options.ui RESOURCES += resources.qrc plugins-1.5/generic/pepchangenotifyplugin/resources.qrc000066400000000000000000000001471336777360500236220ustar00rootroot00000000000000 pepchangenotify.png plugins-1.5/generic/qipxstatusesplugin/000077500000000000000000000000001336777360500204715ustar00rootroot00000000000000plugins-1.5/generic/qipxstatusesplugin/CMakeLists.txt000066400000000000000000000024211336777360500232300ustar00rootroot00000000000000unset(_HDRS) unset(_UIS) unset(_SRCS) unset(_RSCS) unset(PLUGIN) set( PLUGIN qipxstatusesplugin ) project(${PLUGIN}) cmake_minimum_required(VERSION 3.1.0) set( CMAKE_AUTOMOC TRUE ) IF( NOT WIN32 ) set( LIB_SUFFIX "" CACHE STRING "Define suffix of directory name (32/64)" ) set( PLUGINS_PATH "lib${LIB_SUFFIX}/psi-plus/plugins" CACHE STRING "Install suffix for plugins" ) ELSE() set( PLUGINS_PATH "psi-plus/plugins" CACHE STRING "Install suffix for plugins" ) ENDIF() add_definitions( -DQT_PLUGIN -DHAVE_QT5 ) include_directories( ${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ../../include . ) set( _SRCS ${PLUGIN}.cpp ) set( _RSCS resources.qrc ) find_package( Qt5 COMPONENTS Widgets Xml REQUIRED ) set(QT_DEPLIBS Qt5::Widgets Qt5::Xml ) qt5_add_resources(RSCS ${_RSCS}) add_library( ${PLUGIN} MODULE ${_SRCS} ${UIS} ${RSCS} ) target_link_libraries( ${PLUGIN} ${QT_DEPLIBS} ) if( UNIX AND NOT( APPLE OR CYGWIN ) ) install( TARGETS ${PLUGIN} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} ) endif() if( WIN32 ) install( TARGETS ${PLUGIN} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} ) endif() plugins-1.5/generic/qipxstatusesplugin/changelog.txt000066400000000000000000000013501336777360500231600ustar00rootroot000000000000002013-08-13 v0.0.8 - taurus + Иконка плагина 2010-09-11 v0.0.7 * обновлена ссылка на wiki ( http://psi-plus.com/wiki/plugins#qip_x-statuses_plugin ) 2010-05-17 v0.0.6 + добавлена информация о плагине 2010-05-04 v0.0.5 * исправлена ссылка на wiki 2010-03-06 v0.0.4 + добавлена ссылка на wiki 2010-03-31 v0.0.3 * исправлено определение некоторых статусов 2010-03-30 v0.0.1 ! initial version Данный плагин предназначен для отображения х-статусов контактов, использующих в качестве jabber-клиента QIP Infium plugins-1.5/generic/qipxstatusesplugin/qipxstatuses.png000066400000000000000000000010511336777360500237510ustar00rootroot00000000000000PNG  IHDRaIDATxc`@Q%uhrHKWh Xhj4M?eb03rk74' d2QE;ea 3DȳJ=w.۷0L 3`?>go4e| p<|79 &1dϓNWX&\t{'gaUóEp{W?~1%/ds_v vGnq{FQ vPűH7  kXLHP]j8A>0 g鱲uoPZIv @ P!HHqIU'8@Ax݆arИpŚ#3`.ٹk۶ߴymT|iA$&p*L ĠX9-nTIIENDB`plugins-1.5/generic/qipxstatusesplugin/qipxstatusesplugin.cpp000066400000000000000000000272661336777360500252060ustar00rootroot00000000000000/* * qipxstatusesplugin.cpp - plugin * Copyright (C) 2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include #include #include #include #include #include #include "psiplugin.h" #include "stanzafilter.h" #include "contactstateaccessor.h" #include "contactstateaccessinghost.h" #include "plugininfoprovider.h" #define cVer "0.0.8" class QipXStatuses: public QObject, public PsiPlugin, public StanzaFilter, public ContactStateAccessor, public PluginInfoProvider { Q_OBJECT #ifdef HAVE_QT5 Q_PLUGIN_METADATA(IID "com.psi-plus.QipXStatuses") #endif Q_INTERFACES(PsiPlugin StanzaFilter ContactStateAccessor PluginInfoProvider) public: QipXStatuses(); virtual QString name() const; virtual QString shortName() const; virtual QString version() const; virtual QWidget* options(); virtual bool enable(); virtual bool disable(); virtual void applyOptions() {} virtual void restoreOptions(){} virtual bool incomingStanza(int account, const QDomElement& xml); virtual bool outgoingStanza(int account, QDomElement& xml); virtual void setContactStateAccessingHost(ContactStateAccessingHost* host); virtual QString pluginInfo(); virtual QPixmap icon() const; private: bool enabled; ContactStateAccessingHost *contactState; QDomElement activityToXml(QString type, QString specificType, QString text); QDomElement MoodToXml(QString type, QString text); }; #ifndef HAVE_QT5 Q_EXPORT_PLUGIN(QipXStatuses); #endif QipXStatuses::QipXStatuses() { enabled = false; contactState = 0; } QString QipXStatuses::name() const { return "Qip X-Statuses Plugin"; } QString QipXStatuses::shortName() const { return "qipxstatuses"; } QString QipXStatuses::version() const { return cVer; } bool QipXStatuses::enable() { enabled = true; return enabled; } bool QipXStatuses::disable() { enabled = false; return true; } QWidget* QipXStatuses::options() { if(!enabled) return 0; QWidget *options = new QWidget; QVBoxLayout *layout = new QVBoxLayout(options); QLabel *wiki = new QLabel; wiki->setText(tr("Wiki (Online)")); wiki->setOpenExternalLinks(true); layout->addWidget(wiki); layout->addStretch(); return options; } bool QipXStatuses::incomingStanza(int account, const QDomElement& stanza) { if (enabled) { if(stanza.tagName() == "presence") { bool xStat = false; QDomElement emptyElem; QString from = stanza.attribute("from").split("/").first(); QDomNodeList xElemList = stanza.elementsByTagName ("x"); QDomElement xElem; for(int i = xElemList.size(); i > 0;) { xElem = xElemList.at(--i).toElement(); if(xElem.attribute("xmlns") == "http://qip.ru/x-status") { xStat = true; QString mood = ""; QString act = ""; QString specAct = ""; QString title = ""; title = xElem.firstChildElement("title").text(); int id = xElem.attribute("id").toInt(); switch(id) { case 1: mood = "angry"; break; case 2: act = "grooming"; specAct = "taking_a_bath"; break; case 3: mood = "tired"; break; case 4: act = "relaxing"; specAct = "partying"; break; case 5: act = "drinking"; specAct = "having_a_beer"; break; case 6: act = "inactive"; specAct = "thinking"; break; case 7: act = "eating"; break; case 8: act = "relaxing"; specAct = "watching_tv"; break; case 9: act = "relaxing"; specAct = "socializing"; break; case 10: act = "drinking"; specAct = "having_coffee"; break; case 12: act = "having_appointment"; break; case 13: act = "relaxing"; specAct = "watching_a_movie"; break; case 14: mood = "happy"; break; case 15: act = "talking"; specAct = "on_the_phone"; break; case 16: act = "relaxing"; specAct = "gaming"; break; case 17: act = "working"; specAct = "studying"; break; case 18: act = "relaxing"; specAct = "shopping"; break; case 19: mood = "sick"; break; case 20: act = "inactive"; specAct = "sleeping"; break; case 21: act = "exercising"; specAct = "swimming"; break; case 22: act = "relaxing"; specAct = "reading"; break; case 23: act = "working"; break; case 24: act = "working"; specAct = "coding"; break; case 25: act = "relaxing"; specAct = "going_out"; break; case 26: act = "talking"; specAct = "on_video_phone"; break; case 27: act = "talking"; specAct = "on_the_phone"; break; case 28: act = "inactive"; specAct = "sleeping"; break; case 29: act = "grooming"; break; case 30: mood = "undefined"; break; case 31: act = "doing_chores"; break; case 32: mood = "in_love"; break; case 33: mood = "curious"; break; case 34: mood = "in_love"; break; case 35: act = "working"; specAct = "writing"; break; } if(id != 11) { if(!mood.isEmpty()) contactState->setMood(account, from, MoodToXml(mood, title)); else contactState->setMood(account, from, emptyElem); if(!act.isEmpty()) contactState->setActivity(account, from, activityToXml(act, specAct, title)); else contactState->setActivity(account, from, emptyElem); contactState->setTune(account, from, ""); } else { contactState->setTune(account, from, title); contactState->setActivity(account, from, emptyElem); contactState->setMood(account, from, emptyElem); } break; } } if(!xStat) { QDomElement cElem = stanza.firstChildElement("c"); if(!cElem.isNull() && cElem.attribute("xmlns") == "http://jabber.org/protocol/caps" && cElem.attribute("node") == "http://qip.ru/caps") { contactState->setMood(account, from, emptyElem); contactState->setActivity(account, from, emptyElem); contactState->setTune(account, from, ""); } } } } return false; } bool QipXStatuses::outgoingStanza(int /*account*/, QDomElement& /*xml*/) { return false; } void QipXStatuses::setContactStateAccessingHost(ContactStateAccessingHost* host) { contactState = host; } QDomElement QipXStatuses::activityToXml(QString type, QString specificType, QString text) { QDomDocument doc; QDomElement activity = doc.createElement("activity"); activity.setAttribute("xmlns", "http://jabber.org/protocol/activity"); if (!type.isEmpty()) { QDomElement el = doc.createElement(type); if (!specificType.isEmpty()) { QDomElement elChild = doc.createElement(specificType); el.appendChild(elChild); } activity.appendChild(el); } if (!text.isEmpty()) { QDomElement el = doc.createElement("text"); QDomText t = doc.createTextNode(text); el.appendChild(t); activity.appendChild(el); } return activity; } QDomElement QipXStatuses::MoodToXml(QString type, QString text) { QDomDocument doc; QDomElement mood = doc.createElement("mood"); mood.setAttribute("xmlns", "http://jabber.org/protocol/mood"); if (!type.isEmpty()) { QDomElement el = doc.createElement(type); mood.appendChild(el); } if (!text.isEmpty()) { QDomElement el = doc.createElement("text"); QDomText t = doc.createTextNode(text); el.appendChild(t); mood.appendChild(el); } return mood; } QString QipXStatuses::pluginInfo() { return tr("Author: ") + "Dealer_WeARE\n" + tr("Email: ") + "wadealer@gmail.com\n\n" + trUtf8("This plugin is designed to display x-statuses of contacts using the QIP Infium jabber client."); } QPixmap QipXStatuses::icon() const { return QPixmap(":/icons/qipxstatuses.png"); } #include "qipxstatusesplugin.moc" plugins-1.5/generic/qipxstatusesplugin/qipxstatusesplugin.pro000066400000000000000000000002471336777360500252120ustar00rootroot00000000000000isEmpty(PSISDK) { include(../../psiplugin.pri) } else { include($$PSISDK/plugins/psiplugin.pri) } SOURCES += qipxstatusesplugin.cpp RESOURCES += resources.qrc plugins-1.5/generic/qipxstatusesplugin/resources.qrc000066400000000000000000000001441336777360500232110ustar00rootroot00000000000000 qipxstatuses.png plugins-1.5/generic/screenshotplugin/000077500000000000000000000000001336777360500200715ustar00rootroot00000000000000plugins-1.5/generic/screenshotplugin/CMakeLists.txt000066400000000000000000000053451336777360500226400ustar00rootroot00000000000000unset(_HDRS) unset(_UIS) unset(_SRCS) unset(_RSCS) unset(PLUGIN) set( PLUGIN screenshotplugin ) project(${PLUGIN}) cmake_minimum_required(VERSION 3.1.0) set( CMAKE_AUTOMOC TRUE ) IF( NOT WIN32 ) set( LIB_SUFFIX "" CACHE STRING "Define suffix of directory name (32/64)" ) set( PLUGINS_PATH "lib${LIB_SUFFIX}/psi-plus/plugins" CACHE STRING "Install suffix for plugins" ) ELSE() set( PLUGINS_PATH "psi-plus/plugins" CACHE STRING "Install suffix for plugins" ) ENDIF() add_definitions( -DQT_PLUGIN -DHAVE_QT5 ) include_directories( ${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ../../include qxt/core qxt/gui . ) if( UNIX AND NOT( APPLE OR CYGWIN ) ) find_package( X11 REQUIRED ) add_definitions( -DX11 ) set( qxt_X11_SRCS qxt/gui/qxtwindowsystem_x11.cpp ) set( qxt_X11_HDRS qxt/gui/x11info.h ) endif() if( APPLE ) set( qxt_mac_SRCS qxt/gui/qxtwindowsystem_mac.cpp ) set( qxt_mac_HRDS qxt/gui/qxtwindowsystem_mac.h ) endif() if( WIN32 ) add_definitions( -DQ_WS_WIN ) set( qxt_win_SRCS qxt/gui/qxtwindowsystem_win.cpp ) endif() set ( _HDRS screenshot.h server.h editserverdlg.h screenshotoptions.h toolbar.h pixmapwidget.h options.h optionsdlg.h optionswidget.h screenshoticonset.h controller.h defines.h proxysettingsdlg.h qxt/core/qxtglobal.h qxt/gui/qxtwindowsystem.h ${qxt_X11_HDRS} ${qxt_mac_HRDS} ) set ( _SRCS ${PLUGIN}.cpp screenshot.cpp server.cpp editserverdlg.cpp screenshotoptions.cpp toolbar.cpp pixmapwidget.cpp options.cpp optionsdlg.cpp optionswidget.cpp screenshoticonset.cpp controller.cpp proxysettingsdlg.cpp qxt/core/qxtglobal.cpp qxt/gui/qxtwindowsystem.cpp ${qxt_X11_SRCS} ${qxt_mac_SRCS} ${qxt_win_SRCS} ) set ( _UIS optionswidget.ui editserverdlg.ui screenshot.ui screenshotoptions.ui optionsdlg.ui proxysettingsdlg.ui ) set ( _RSCS ${PLUGIN}.qrc ) find_package( Qt5 COMPONENTS Widgets Xml Network PrintSupport REQUIRED ) set(QT_DEPLIBS Qt5::Widgets Qt5::Xml Qt5::Network Qt5::PrintSupport ) if( UNIX AND NOT( APPLE OR CYGWIN ) ) find_package( Qt5 COMPONENTS X11Extras REQUIRED ) set(QT_DEPLIBS ${QT_DEPLIBS} Qt5::X11Extras ) endif() qt5_wrap_ui(UIS ${_UIS}) qt5_add_resources(RSCS ${_RSCS}) add_library( ${PLUGIN} MODULE ${_SRCS} ${UIS} ${RSCS} ) if( UNIX AND NOT( APPLE OR CYGWIN ) ) target_link_libraries( ${PLUGIN} ${X11_LIBRARIES} ${QT_DEPLIBS} ) install( TARGETS ${PLUGIN} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} ) endif() if( WIN32 ) target_link_libraries( ${PLUGIN} ${QT_DEPLIBS} ) install( TARGETS ${PLUGIN} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} ) endif() plugins-1.5/generic/screenshotplugin/changelog.txt000066400000000000000000000345251336777360500225720ustar00rootroot000000000000002016-04-07 v0.6.6 - удалены нерабочие сервера 2013-08-13 v0.6.5 - taurus + Иконка плагина 2012-03-19 v0.6.4 + радиус размытия сохраняется в настройках + добавлена возможность захвата активного окна + добавлена возможность вставить изображение из буфера обмена * некоторые исправления 2012-03-16 v0.6.3 + добавлена возможность размытия выделенного участка (пункт в контекстном меню) + при выделении происходит автоматический скролл картинки - из списка по-умолчанию удален сервер http://imageshack.us/ 2011-11-11 v0.6.2 * некоторые исправления 2011-11-10 v0.6.1 + в опции добавлена подсказка о том, что порядок серверов можно задать драг-н-дропом + в информацию о плагине добавлена ссылка на настройки авторизации для некоторых хостингов + добавлена возможность выбора действия по-умолчанию + добавлена кнопка "копировать ссылку в буфер обмена" 2011-07-08 v0.6.0 * цвет по-умолчанию для карандаша изменен на черный + добавлена статусная панель, в которой отображается информация о размера изображения 2011-05-30 v0.5.9 * различные исправления и оптимизации 2011-05-25 v0.5.8 * небольшие улучшения алгоритма загрузки + добавлено несколько новых хостингов 2011-05-24 v0.5.7 * некоторые исправления в алгоритме загрузки * возвращен серве imagedhack + добавлен сервер img.flashtux.org 2011-05-12 v0.5.6 * исправления для диалога выбора цветов 2011-05-04 v0.5.5 - удалены настройки прокси из главного окна скриншота 2011-04-22 v0.5.4 + при обновлении плагина на новую версию будут обновляться настройки предустановленных серверов - удален сервер imageshack * различные исправления 2011-04-20 v0.5.3 + некоторые косметические улучшения в диалогах + сохраняется геометрия окна * некоторые исправления 2011-04-19 v0.5.1 + добавлено главное меню + добавлена история загрузок + доработан режим скриншота выделенной области * большое количество изменений кода, возможно, новые баги :) * исправления для режима рисования текста 2011-04-12 v0.4.7 + теперь кнопка обрезки неактивна, если не включен режим выделения + теперь выводится корректное сообщение об ошибке при сбое загрузки скриншота + добавлена возможность изменять выделенную область (ресайз за углы выделения) * множество различных улучшений кода 2011-04-08 v0.4.6 * перед печатью производится масштабирование больших изображений + добавлена возможность рисовать прямые линии удерживая клавишу Shift + теперь при открытии изображения используется последний каталог * исправлено одновременное редактирование нескольких серверов 2011-04-05 v0.4.5 * исправлены регулярные выражения для сервисов Pix.Academ.org и ImageShack.us * исправлен хоткей по умолчанию на Ctrl+Shift+p * главное окно показывается максимизированным + запоминается последний каталог для записи + добавлена возможность распечатать скриншот + если не получается получить ссылку на скриншот, то показывается ссылка на возвращаемую страницу + при закрытии главного окна если есть изменения будет выведен вопрос * различные исправления 2010-12-03 v0.4.4 + плагин теперь использует настройки прокси со страницы настроек приложения + для каждого сервера можно задать, использует ли он прокси или нет (необходимо для локальных FTP серверов) 2010-09-11 v0.4.3 * обновлена ссылка на wiki ( http://psi-plus.com/wiki/plugins#screenshot_plugin ) 2010-07-28 v0.4.2 + двойной щелчок по выделенной области приводит к обрезке + добавлены сочетания клавиш CTRL+O - открытие картинки с локального диска CTRL+N - новый скриншот + при вставке текста фокус сразу переводится на поле ввода + если главное окно было максимизировано, то его геометрия не меняется при обрезке + расчет геометрии производится точнее, что позволяет избежать появления полос прокрутки * увеличена стабильность работы приложения 2010-07-26 v0.4.1 + добавлены сочетания клавиш CTRL+X - обрезать изображение, CTRL+S - сохранить изображение на диск, CTRL+U - загрузить изображение на сервер * исправлено падение приложения при попытке сделать повторный скриншот, если открыт диалог выбора цвета + на кнопке выбора цвета отображается текущий цвет * теперь диалог выбора шрифта вызывается из окна ввода текста + запоминаются настройки цвета, шрифта и толщины линии 2010-07-22 v0.4.0 + добавлена возможность при изменении настроек прокси-сервера для одного из серверов применить изменения и для всех остальных серверов + добавлена возможность копировать в буфер выделенный фрагмент изображения 2010-07-13 v0.3.9 * исправлен диалог ввода текста * исправлено изменение размеров главного окна при нажатии кнопок Undo, Сut и Rotate 2010-07-12 v0.3.8 * выделение теперь сбрасывается после нажатия кнопки Cut * исправлено срабатывание пункта Cut контекстного меню * некоторые исправления в расположении кнопок и во всплывающих подсказках 2010-07-12 v0.3.7 + добавлена возможность упорядочить сервера посредством перетаскивания элементов + при обрезке картинки главное окно изменяет свой размер в соответствие с новым размером изображения * исправлен текст некоторых всплывающих подсказок * изменены курсоры + добавлен хостинг Kachalka.com + добавлена возможность вращать изображение 2010-07-10 Dealer_WeARE v0.3.6 * немного изменён дизайн опций плагина * изменён дизайн главного окна + добавлена возможность из главного окна открыть изображение, сохранённое на диске * кнопка Undo активна, только если есть, что отменять * при простом клике по изображению не сбивается область выделения * исправлено отсутствие возможности нарисовать точку * при нажатии кнопки Undo выбранная область сбрасывается * выделение и рисование работает только при нажатии левой кнопки мыши + добавлена возможность обрезать выделенную область с помощью контекстного меню + добавлено сочетание клавиш Ctrl+z для кнопки Undo 2010-07-09 Dealer_WeARE v0.3.5 * изменены иконки * исправлено сохранение обработанного изображения - удалена возможность выбрать для сохранения формат *gif 2010-07-08 Dealer_WeARE v0.3.4 * по хоткею снова сразу получаем скриншот * цвет линии выделения красный * теперь для задания формата изображения используется выпадающий список * некоторые исправления 2010-07-07 Dealer_WeARE v0.3.3 + добавлен простейший графический редактор для обработки скриншота 2010-07-06 Dealer_WeARE v0.3.2 * возможность указать область для захвата доступна только под X + добавлена возможность отменить загрузку * различные исправления 2010-07-05 Dealer_WeARE v0.3.1 * исправлено падение приложения при попытке редактирования или удаления сервера в случае, когда ни один сервер не выбран + добавлена возможность сделать новый скриншот из главного окна скриншота + добавлена возможность задать интервал перед созданием нового скриншота + добавлена возможность указать область захвата 2010-07-02 Dealer_WeARE v0.3.0 * переписана большая часть кода плагина + добавлена конопка "Свернуть" в окне скриншота + добавлена возможность хранить список серверов + добавлена возможность удобно редактировать сервера + добавлена поддержка прокси + добавлена возможность загрузки изображений на популярные хостинги + добавлено отображение прямой ссылки на загруженное изображение + добавлена возможность с помощью пункта меню аккаунта открыть существующее изображение и загрузить его на сервер Отдельная благодарность выражается товарищу Boiler за его плагин ImagePub plugin (qutIM) Часть его кода была использована для реализации поддержки HTTP серверов 2010-05-17 Dealer_WeARE v0.2.4 + добавлена информация о плагине 2010-05-04 zet v0.2.3 * исправлена ссылка на wiki 2009-12-25 C.H. v0.2.2 * fixed disable method, thanks to liuch_at_mail.ru 2009-12-23 zet v0.2.1 + added changelog 2009-12-23 Dealer_WeARE v0.2.0 * updated screenshotplugin to v0.2.0 (separate forms for login and password, link to wiki project) Revision: 1437 Author: ivan.borzenkov * all plugins dir ends on 'plugin' Revision: 1115 Author: givan101 * more translatable Revision: 798 Author: rion4ik * fixed small typo in include path Revision: 797 Author: rion4ik * screenshot plugin: shortcuts rewritten Revision: 621 Author: ptitkov + added disconnect short to destructor, thanks to VampiRUS Revision: 594 Author: rion4ik * started work on icons for everything in chatlog Revision: 577 Author: ptitkov + added upload button. if no url inputed upload button will be hide Revision: 576 Author: ptitkov * changed widget to dialog main class. added Esc shortcut for close window Revision: 575 Author: ptitkov + added file name format to options Revision: 567 Author: vladimir.shelukhin * screenshotplugin: changed date/time format for uploading files Revision: 565 Author: ptitkov * fixed reading default message Revision: 562 Author: ptitkov * fixed ftp errors Revision: 561 Author: ptitkov + added ftp upload, if url is empty picture will be save to local disk Revision: 560 Author: ptitkov * fixed reading shortcut Revision: 559 Author: ptitkov + added url and shortCut options Revision: 458 Author: ptitkov + added CONFIG += release Revision: 457 Author: ptitkov * fixed enable-disable plugin Revision: 445 Author: ptitkov + added screenshot plugin. special for zet :) plugins-1.5/generic/screenshotplugin/controller.cpp000066400000000000000000000073561336777360500227730ustar00rootroot00000000000000/* * controller.cpp - plugin * Copyright (C) 2011 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "controller.h" #include "screenshot.h" #include "server.h" #include "options.h" #include "screenshoticonset.h" #include "defines.h" #include "applicationinfoaccessinghost.h" static const QString pixacadem = "Pix.Academ.info&split&http://pix.academ.info/&split&&split&&split&action=upload_image&split&image&split&&split&true"; static const QStringList staticHostsList = QStringList() /*<< imageShack*/ << pixacadem << smages; static bool isListContainsServer(const QString& server, const QStringList& servers) { foreach(QString serv, servers) { if(serv.split(Server::splitString()).first() == server.split(Server::splitString()).first()) return true; } return false; } static void updateServer(QStringList *const servers, const QString& serv) { QStringList::iterator it = servers->begin(); while(++it != servers->end()) { const QStringList tmpOld = (*it).split(Server::splitString()); const QStringList tmpNew = serv.split(Server::splitString()); if(tmpOld.first() == tmpNew.first()) { *it = serv; } } } Controller::Controller(ApplicationInfoAccessingHost* appInfo) : QObject() , appInfo_(appInfo) { Options* o = Options::instance(); QVariant vServers = o->getOption(constServerList); if(!vServers.isValid()) { //приложение запущено впервые o->setOption(constShortCut, QVariant("Alt+Shift+p")); o->setOption(constFormat, QVariant("png")); o->setOption(constFileName, QVariant("pic-yyyyMMdd-hhmmss")); o->setOption(constDelay, QVariant(0)); o->setOption(constVersionOption, cVersion); o->setOption(constDefaultAction, QVariant(Desktop)); } QStringList servers = vServers.toStringList(); foreach(const QString& host, staticHostsList) { if(!isListContainsServer(host, servers)) servers.append(host); } if(o->getOption(constVersionOption).toString() != cVersion) { // foreach(const QString& host, staticHostsList) { // updateServer(&servers, host); // } //updateServer(&servers, ompldr); doUpdate(); o->setOption(constVersionOption, cVersion); } o->setOption(constServerList, servers); //сохраняем обновленный список серверов } Controller::~Controller() { if (screenshot) { delete screenshot; } Options::reset(); ScreenshotIconset::reset(); } void Controller::onShortCutActivated() { if(!screenshot) { screenshot = new Screenshot(); screenshot->setProxy(appInfo_->getProxyFor(constName)); } screenshot->action(Options::instance()->getOption(constDefaultAction).toInt()); } void Controller::openImage() { if(!screenshot) { screenshot = new Screenshot(); screenshot->setProxy(appInfo_->getProxyFor(constName)); } screenshot->openImage(); } void Controller::doUpdate() { // do some updates } plugins-1.5/generic/screenshotplugin/controller.h000066400000000000000000000023231336777360500224250ustar00rootroot00000000000000/* * controller.h - plugin * Copyright (C) 2011 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef CONTROLLER_H #define CONTROLLER_H #include class Screenshot; class ApplicationInfoAccessingHost; class Controller : public QObject { Q_OBJECT public: Controller(ApplicationInfoAccessingHost* appInfo); ~Controller(); public slots: void onShortCutActivated(); void openImage(); private: void doUpdate(); QPointer screenshot; ApplicationInfoAccessingHost* appInfo_; }; #endif // CONTROLLER_H plugins-1.5/generic/screenshotplugin/defines.h000066400000000000000000000027301336777360500216610ustar00rootroot00000000000000/* * defines.h - plugin * Copyright (C) 2011 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef DEFINES_H #define DEFINES_H #define cVersion "0.6.6" #define constName "Screenshot Plugin" #define constVersionOption "version" #define constLastFolder "lastfolder" #define constHistory "history" #define constShortCut "shortCut" #define constFormat "format" #define constFileName "fileName" #define constServerList "serverlist" #define constDelay "delay" #define constWindowState "geometry.state" #define constWindowX "geometry.x" #define constWindowY "geometry.y" #define constWindowWidth "geometry.width" #define constWindowHeight "geometry.height" #define constDefaultAction "default-action" #define constRadius "radius" enum DefaultAction { Desktop, Area, Window }; #endif // DEFINES_H plugins-1.5/generic/screenshotplugin/editserverdlg.cpp000066400000000000000000000053361336777360500234470ustar00rootroot00000000000000/* * editserverdlg.cpp - plugin * Copyright (C) 2009-2011 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "editserverdlg.h" #include "server.h" EditServerDlg::EditServerDlg(QWidget *parent) : QDialog(parent) { setAttribute(Qt::WA_DeleteOnClose); setModal(false); ui_.setupUi(this); connect(ui_.buttonBox, SIGNAL(accepted()), SLOT(onOkPressed())); } void EditServerDlg::onOkPressed() { QStringList l = QStringList() << ui_.le_name->text() << ui_.le_url->text() << ui_.le_user->text() << ui_.le_pass->text(); l << ui_.le_post_data->text() << ui_.le_file_input->text() << ui_.le_regexp->text(); l << (ui_.cb_proxy->isChecked() ? "true" : "false"); const QString str = l.join(Server::splitString()); if(server_) { server_->setFromString(str); server_->setText(server_->displayName()); } emit okPressed(str); close(); } void EditServerDlg::setSettings(const QString& settings) { QStringList l = settings.split(Server::splitString()); if(l.size() == 11) { processOldSettingString(l); return; } if(!l.isEmpty()) ui_.le_name->setText(l.takeFirst()); if(!l.isEmpty()) ui_.le_url->setText(l.takeFirst()); if(!l.isEmpty()) ui_.le_user->setText(l.takeFirst()); if(!l.isEmpty()) ui_.le_pass->setText(l.takeFirst()); if(!l.isEmpty()) ui_.le_post_data->setText(l.takeFirst()); if(!l.isEmpty()) ui_.le_file_input->setText(l.takeFirst()); if(!l.isEmpty()) ui_.le_regexp->setText(l.takeFirst()); if(!l.isEmpty()) ui_.cb_proxy->setChecked(l.takeFirst() == "true"); } void EditServerDlg::processOldSettingString(QStringList l) { ui_.le_name->setText(l.takeFirst()); ui_.le_url->setText(l.takeFirst()); ui_.le_user->setText(l.takeFirst()); ui_.le_pass->setText(l.takeFirst()); //remove old useless proxy settings l.takeFirst(); l.takeFirst(); l.takeFirst(); l.takeFirst(); ui_.le_post_data->setText(l.takeFirst()); ui_.le_file_input->setText(l.takeFirst()); ui_.le_regexp->setText(l.takeFirst()); } void EditServerDlg::setServer(Server *const s) { server_ = s; setSettings(s->settingsToString()); } plugins-1.5/generic/screenshotplugin/editserverdlg.h000066400000000000000000000024501336777360500231060ustar00rootroot00000000000000/* * editserverdlg.h - plugin * Copyright (C) 2009-2011 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef EDITSERVERDLG_H #define EDITSERVERDLG_H #include #include "ui_editserverdlg.h" class Server; class EditServerDlg : public QDialog { Q_OBJECT public: EditServerDlg(QWidget *parent = 0); void setServer(Server *const s); signals: void okPressed(const QString&); private: Ui::EditServerDlg ui_; void processOldSettingString(QStringList l); void setSettings(const QString& settings); private slots: void onOkPressed(); private: QPointer server_; }; #endif // EDITSERVERDLG_H plugins-1.5/generic/screenshotplugin/editserverdlg.ui000066400000000000000000000140071336777360500232750ustar00rootroot00000000000000 EditServerDlg 0 0 256 359 0 0 Server Settings Name: 150 0 Url: 150 0 User Name*: 150 0 Password*: 150 0 QLineEdit::PasswordEchoOnEdit PostData**: 150 0 File Input**: 150 0 RegExp**: 150 0 Andale Mono 8 *for FTP servers only Andale Mono 8 **for HTTP servers only Use proxy server true Qt::Vertical 0 0 Qt::Horizontal 40 20 QDialogButtonBox::Cancel|QDialogButtonBox::Ok false buttonBox rejected() EditServerDlg close() 191 432 144 227 plugins-1.5/generic/screenshotplugin/icons/000077500000000000000000000000001336777360500212045ustar00rootroot00000000000000plugins-1.5/generic/screenshotplugin/icons/copy.png000066400000000000000000000016331336777360500226670ustar00rootroot00000000000000PNG  IHDR(-SPLTE    $ ! !! +$&2!&5&D+C(D,D"/K$4E9CP0Jdgvڀ,;SRNXjD|D62 ( 8`~vPOoCvs 8 ]|aɄ[ z/Nİ*tuXİ*QT.;kDbՀ̱ <ݏy#~=庠q]}fĝZtlT3R%~>#w -;06m7wU\&IENDB`plugins-1.5/generic/screenshotplugin/icons/frame.png000066400000000000000000000010421336777360500230010ustar00rootroot00000000000000PNG  IHDR'fPLTE)ooo1114;AQQ-NNNYYYdddMCc  /A @-!!! `$$$W_).',2($^ 2,1||"y435<:9;8=-x >9@/| A;DCBDGn: ONM!Tx#Ux,Vw%X|\WS9]v'fdccLf4lToBtAv9yA{|z}FM^FK]olbqslٵ΋֌ձtRNSnWIDATxڝ AD'ٸ=@9PP^߷9]?C|jO>1A$ZEb!B?|Ey8MĿڨˌ;ܖh4=jJH$b1L??E 9x25qt5\,/G{56+ݩyy.ePWZP\;A G-5VW5eYFΣ4 Qۄ`IjGO ֕YP0T7Jl`vFVcP`AaQlcyyiqXQ "Kk]0W9wlq}\\fn ]&-'yIqs+ YVԙ(c&o-L&|7C,JJDh?Wq+7/dךٮZa0?.?cUyg;%e{*%K[N؛+x(#Bt~UWy,7XMG#Vm[}JtLlcpfp8Nxu{;fd-.2S ,V8c]C]Oȯ[LtP@DžNǪ >9)Ț2;scCߤ^9F=pMǁI=BgTre Аl6RhMtJ?>2<oO}CY<*`G"(XM #5IENDB`plugins-1.5/generic/screenshotplugin/icons/paste.png000066400000000000000000000003671336777360500230340ustar00rootroot00000000000000PNG  IHDR(-S?PLTEAAGFHL?AD%%%nUY_nx n?@CJNSY]c"tRNSdIDATx^]I DQϪ& ߲EJsB ·eY{:P ,|iΖ3Zsd S'DqPQ(b&l"aIENDB`plugins-1.5/generic/screenshotplugin/icons/print.png000066400000000000000000000012761336777360500230540ustar00rootroot00000000000000PNG  IHDRabKGDsIDATx}OHTQ7 KMdV)."sa2iU m Z$-6Q Z K*0ZLtY=uyoAcs~ߏ#j:~u\:tF Ab( ~,W7\/FGr (<~/O?n}yW˨4UЊ/?,fj>- к} wږJ[-7f6 HmD:;3tC@>OQƀ҂V\HSB#ăM|>?D,TRcP(yŁ!:򴧧'9pP @#"@K"rɥ7pf @hkH?sss,>m۶eEQYlqa۶!ຮXaR(pX[[kd2JP(`A<J0 }! Cr_*~jT*8jr*.:;; |ߏWVVT6qv6"eaa8<ϻ?11a<@E Cr|8_UUhSE(eqvU`I2s9F(LOd20 yʥ2J>`F8L|~ BTNc|X/Cc~~&Trq\W~uUUL?FKc=Yk[28T/j0,BX\4%PTAj֊sX~%ŦP.r29h, j5^|sHis(i汿lˆG[(!dIOTy v Lh@hP,nbY\!,Pƫw)Bm;# K0~H5oyDt`s,~c 92?$5ѮnkY@-t`<.z8 cN6,Ayyo[{|r[ЀVfDIENDB`plugins-1.5/generic/screenshotplugin/icons/undo.png000066400000000000000000000011411336777360500226540ustar00rootroot00000000000000PNG  IHDRasRGBbKGD pHYs  ~tIME E|IDAT8ՒkSa6&1F(XtWi@ AQDp m vjq1|u(hEg<w<kɺ¢$e u#t({7 I}2Q> 1a{xH)3qN [,B5+=Vݚ~&P׿F^pٱ5GPkz]])KrcQSd܋29D_ݷM;}z{vc./z4ׁ 1 5d¶F6L<qF@dtb0ߟ8]Оy׾Q&besbjS^}]U&c~UV/޳LIENDB`plugins-1.5/generic/screenshotplugin/options.cpp000066400000000000000000000030501336777360500222660ustar00rootroot00000000000000/* * options.cpp - plugin * Copyright (C) 2011 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "options.h" #include "optionaccessinghost.h" Options* Options::instance_ = 0; Options* Options::instance() { if(!instance_) { instance_ = new Options(); } return instance_; } Options::Options() : QObject(0) , psiOptions(0) { } Options::~Options() { } void Options::reset() { delete instance_; instance_ = 0; } QVariant Options::getOption(const QString& name, const QVariant& defValue) { QVariant val = defValue; if(psiOptions) { val = psiOptions->getPluginOption(name, val); } return val; } void Options::setOption(const QString& name, const QVariant& value) { if(psiOptions) { psiOptions->setPluginOption(name, value); } } //for Psi plugin only void Options::setPsiOptions(OptionAccessingHost* _psiOptions) { psiOptions = _psiOptions; } plugins-1.5/generic/screenshotplugin/options.h000066400000000000000000000025411336777360500217370ustar00rootroot00000000000000/* * options.h - plugin * Copyright (C) 2011 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef OPTIONS_H #define OPTIONS_H #include //for Psi plugin only class OptionAccessingHost; class Options : public QObject { Q_OBJECT public: static Options* instance(); static void reset(); ~Options(); QVariant getOption(const QString& name, const QVariant& defValue = QVariant::Invalid); void setOption(const QString& name, const QVariant& value); //for Psi plugin only void setPsiOptions(OptionAccessingHost* psiOptions); private: Options(); static Options* instance_; //for Psi plugin only OptionAccessingHost* psiOptions; }; #endif // OPTIONS_H plugins-1.5/generic/screenshotplugin/optionsdlg.cpp000066400000000000000000000020671336777360500227640ustar00rootroot00000000000000/* * optionsdlg.cpp - plugin * Copyright (C) 2011 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "optionsdlg.h" OptionsDlg::OptionsDlg(QWidget* p) : QDialog(p) { ui_.setupUi(this); ui_.options->restoreOptions(); // ui_.options->ui_.lb_wiki->setVisible(false); // from psi+ plugin } void OptionsDlg::accept() { ui_.options->applyOptions(); QDialog::accept(); } plugins-1.5/generic/screenshotplugin/optionsdlg.h000066400000000000000000000020201336777360500224160ustar00rootroot00000000000000/* * optionsdlg.h - plugin * Copyright (C) 2011 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef OPTIONSDLG_H #define OPTIONSDLG_H #include "ui_optionsdlg.h" class OptionsDlg : public QDialog { Q_OBJECT public: OptionsDlg(QWidget* p = 0); public slots: void accept(); private: Ui::OptionsDlg ui_; }; #endif // OPTIONSDLG_H plugins-1.5/generic/screenshotplugin/optionsdlg.ui000066400000000000000000000044361336777360500226210ustar00rootroot00000000000000 OptionsDlg 0 0 500 300 Settings Qt::Vertical 20 40 Qt::Horizontal 40 20 QDialogButtonBox::Cancel|QDialogButtonBox::Ok OptionsWidget QWidget
optionswidget.h
1
buttonBox rejected() OptionsDlg reject() 202 42 186 34 buttonBox accepted() OptionsDlg accept() 268 42 186 34
plugins-1.5/generic/screenshotplugin/optionswidget.cpp000066400000000000000000000151451336777360500235020ustar00rootroot00000000000000/* * optionswidget.cpp - plugin * Copyright (C) 2011 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include #include #include "optionswidget.h" #include "editserverdlg.h" #include "server.h" #include "options.h" #include "defines.h" //-------------------------------------------------------- //---GrepShortcutKeyDialog from libpsi with some changes-- //-------------------------------------------------------- class GrepShortcutKeyDialog : public QDialog { Q_OBJECT public: GrepShortcutKeyDialog(QWidget* p = 0) : QDialog(p) , gotKey(false) { setAttribute(Qt::WA_DeleteOnClose); setModal(true); setWindowTitle(tr("New Shortcut")); QHBoxLayout *l = new QHBoxLayout(this); le = new QLineEdit(); l->addWidget(le); QPushButton *cancelButton = new QPushButton(tr("Cancel")); l->addWidget(cancelButton); connect(cancelButton, SIGNAL(clicked()), SLOT(close())); displayPressedKeys(QKeySequence()); adjustSize(); setFixedSize(size()); } void show() { QDialog::show(); grabKeyboard(); } protected: void closeEvent(QCloseEvent *event) { releaseKeyboard(); event->accept(); } void keyPressEvent(QKeyEvent* event) { displayPressedKeys(getKeySequence(event)); if (!isValid(event->key()) || gotKey) return; gotKey = true; emit newShortcutKey(getKeySequence(event)); close(); } void keyReleaseEvent(QKeyEvent* event) { displayPressedKeys(getKeySequence(event)); } signals: void newShortcutKey(const QKeySequence& key); private: void displayPressedKeys(const QKeySequence& keys) { QString str = keys.toString(QKeySequence::NativeText); if (str.isEmpty()) str = tr("Set Keys"); le->setText(str); } QKeySequence getKeySequence(QKeyEvent* event) const { return QKeySequence((isValid(event->key()) ? event->key() : 0) + (event->modifiers() & ~Qt::KeypadModifier)); } bool isValid(int key) const { switch (key) { case 0: case Qt::Key_unknown: return false; } return !isModifier(key); } bool isModifier(int key) const { switch (key) { case Qt::Key_Shift: case Qt::Key_Control: case Qt::Key_Meta: case Qt::Key_Alt: case Qt::Key_AltGr: case Qt::Key_Super_L: case Qt::Key_Super_R: case Qt::Key_Menu: return true; } return false; } bool gotKey; QLineEdit* le; }; //--------------------------------------------------- //-------------------OptionsWidget------------------- //--------------------------------------------------- OptionsWidget::OptionsWidget(QWidget* p) : QWidget(p) { ui_.setupUi(this); ui_.cb_hack->setVisible(false); Options* o = Options::instance(); shortCut = o->getOption(constShortCut, QVariant(shortCut)).toString(); format = o->getOption(constFormat, QVariant(format)).toString(); fileName = o->getOption(constFileName, QVariant(fileName)).toString(); servers = o->getOption(constServerList).toStringList(); defaultAction = o->getOption(constDefaultAction, QVariant(Desktop)).toInt(); connect(ui_.pb_add, SIGNAL(clicked()), this, SLOT(addServer())); connect(ui_.pb_del, SIGNAL(clicked()), this, SLOT(delServer())); connect(ui_.pb_edit, SIGNAL(clicked()), this, SLOT(editServer())); connect(ui_.lw_servers, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(editServer())); connect(ui_.lw_servers, SIGNAL(currentRowChanged(int)), this, SLOT(applyButtonActivate())); connect(ui_.pb_modify, SIGNAL(clicked()), this, SLOT(requstNewShortcut())); } void OptionsWidget::addServer() { EditServerDlg *esd = new EditServerDlg(this); connect(esd, SIGNAL(okPressed(QString)), this, SLOT(addNewServer(QString))); esd->show(); } void OptionsWidget::delServer() { Server *s = (Server*)ui_.lw_servers->currentItem(); if(!s) return; ui_.lw_servers->removeItemWidget(s); delete(s); applyButtonActivate(); } void OptionsWidget::editServer() { Server *s = (Server*)ui_.lw_servers->currentItem(); if(!s) return; EditServerDlg *esd = new EditServerDlg(this); connect(esd, SIGNAL(okPressed(QString)), this, SLOT(applyButtonActivate())); esd->setServer(s); esd->show(); } void OptionsWidget::addNewServer(const QString& settings) { Server *s = new Server(ui_.lw_servers); s->setFromString(settings); s->setText(s->displayName()); applyButtonActivate(); } void OptionsWidget::applyButtonActivate() { ui_.cb_hack->toggle(); } void OptionsWidget::applyOptions() { Options* o = Options::instance(); shortCut = ui_.le_shortcut->text(); o->setOption(constShortCut, QVariant(shortCut)); format = ui_.cb_format->currentText(); o->setOption(constFormat, QVariant(format)); fileName = ui_.le_filename->text(); o->setOption(constFileName, QVariant(fileName)); servers.clear(); for(int i = 0; i < ui_.lw_servers->count(); i++) { Server *s = (Server *)ui_.lw_servers->item(i); servers.append(s->settingsToString()); } o->setOption(constServerList, QVariant(servers)); if(ui_.rb_desktop->isChecked()) defaultAction = Desktop; else if(ui_.rb_window->isChecked()) defaultAction = Window; else defaultAction = Area; o->setOption(constDefaultAction, defaultAction); } void OptionsWidget::restoreOptions() { QStringList l = QStringList() << "jpg" << "png"; ui_.cb_format->addItems(l); int index = ui_.cb_format->findText(format); if(index != -1) ui_.cb_format->setCurrentIndex(index); ui_.le_filename->setText(fileName); ui_.le_shortcut->setText(shortCut); foreach(QString settings, servers) { Server *s = new Server(ui_.lw_servers); s->setFromString(settings); s->setText(s->displayName()); } ui_.rb_desktop->setChecked(defaultAction == Desktop); ui_.rb_area->setChecked(defaultAction == Area); ui_.rb_window->setChecked(defaultAction == Window); } void OptionsWidget::requstNewShortcut() { GrepShortcutKeyDialog *gs = new GrepShortcutKeyDialog(this); connect(gs, SIGNAL(newShortcutKey(QKeySequence)), this, SLOT(onNewShortcut(QKeySequence))); gs->show(); } void OptionsWidget::onNewShortcut(const QKeySequence& ks) { ui_.le_shortcut->setText(ks.toString(QKeySequence::NativeText)); } #include "optionswidget.moc" plugins-1.5/generic/screenshotplugin/optionswidget.h000066400000000000000000000025501336777360500231430ustar00rootroot00000000000000/* * optionswidget.h - plugin * Copyright (C) 2011 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef OPTIONSWIDGET_H #define OPTIONSWIDGET_H #include "ui_optionswidget.h" class OptionsWidget : public QWidget { Q_OBJECT public: OptionsWidget(QWidget* p = 0); void applyOptions(); void restoreOptions(); private slots: void addServer(); void delServer(); void editServer(); void addNewServer(const QString&); void applyButtonActivate(); void requstNewShortcut(); void onNewShortcut(const QKeySequence&); private: QString shortCut; QString format; QString fileName; QStringList servers; int defaultAction; Ui::OptionsWidget ui_; }; #endif // OPTIONSWIDGET_H plugins-1.5/generic/screenshotplugin/optionswidget.ui000066400000000000000000000143621336777360500233350ustar00rootroot00000000000000 OptionsWidget 0 0 549 394 Form Shortcut: true Format: File Name: Modify hotkey Modify Default action Capture the desktop Capture active window Select capture area Servers: Qt::Horizontal 40 20 true true QAbstractItemView::DragDrop Qt::MoveAction Sans Serif 8 *to specify the order of servers, use the drag-n-drop Add new server Add Delete current server Delete Edit current server Edit Qt::Vertical 0 0 Qt::Horizontal 13 13 <a href="http://psi-plus.com/wiki/plugins#screenshot_plugin">Wiki (Online)</a> true plugins-1.5/generic/screenshotplugin/pixmapwidget.cpp000066400000000000000000000354601336777360500233070ustar00rootroot00000000000000/* * pixmapwidget.cpp - plugin * Copyright (C) 2009-2011 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "pixmapwidget.h" #include "options.h" #include "defines.h" #include "screenshoticonset.h" #define ACCURACY 5 //------------------------------ //---GetTextDlg----------------- //------------------------------ class GetTextDlg : public QDialog { Q_OBJECT public: GetTextDlg(QWidget *parent) : QDialog(parent) { setWindowTitle(tr("Enter text")); QVBoxLayout *l = new QVBoxLayout(this); QHBoxLayout *boxLayout = new QHBoxLayout; QPushButton *selectFont = new QPushButton(tr("Select Font")); selectFont->setIcon(style()->standardIcon(QStyle::SP_MessageBoxQuestion)); QDialogButtonBox *box = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, this); boxLayout->addWidget(selectFont); boxLayout->addStretch(); boxLayout->addWidget(box); te = new QTextEdit(); l->addWidget(te); l->addLayout(boxLayout); connect(box, SIGNAL(accepted()), SLOT(okPressed())); connect(box, SIGNAL(rejected()), SLOT(close())); connect(selectFont, SIGNAL(released()),SIGNAL(selectFont())); adjustSize(); setFixedSize(size()); te->setFocus(); } signals: void text(const QString&); void selectFont(); private slots: void okPressed() { emit text(te->toPlainText()); close(); } private: QTextEdit *te; }; //------------------------------ //---SelectionRect-------------- //------------------------------ SelectionRect::SelectionRect() : QRect() { } SelectionRect::SelectionRect(int left, int top, int w, int h) : QRect(left, top, w, h) { } void SelectionRect::clear() { setTop(-1); setLeft(-1); setHeight(-1); setWidth(-1); } SelectionRect::CornerType SelectionRect::cornerUnderMouse(const QPoint& pos) const { if(!isValid()) { return NoCorner; } if(qAbs(topLeft().x() - pos.x()) < ACCURACY && qAbs(topLeft().y() - pos.y()) < ACCURACY) { return TopLeft; } else if(qAbs(topRight().x() - pos.x()) < ACCURACY && qAbs(topRight().y() - pos.y()) < ACCURACY) { return TopRight; } else if(qAbs(bottomLeft().x() - pos.x()) < ACCURACY && qAbs(bottomLeft().y() - pos.y()) < ACCURACY) { return BottomLeft; } else if(qAbs(bottomRight().x() - pos.x()) < ACCURACY && qAbs(bottomRight().y() - pos.y()) < ACCURACY) { return BottomRight; } return NoCorner; } //-------------------------------------------- //---------------PixmapWidget----------------- //-------------------------------------------- PixmapWidget::PixmapWidget(QWidget *parent) : QWidget(parent) , bar_(0) , type_(ToolBar::ButtonNoButton) , p1(QPoint(-1, -1)) , p2(QPoint(-1, -1)) , selectionRect(new SelectionRect(-1,-1,-1,-1)) , currentCursor(QCursor(Qt::CrossCursor)) , cornerType(SelectionRect::NoCorner) , smoothLineType_(None) { draftPen.setColor(Qt::red); draftPen.setStyle(Qt::DashLine); draftPen.setWidth(1); setMouseTracking(true); } PixmapWidget::~PixmapWidget() { delete selectionRect; } void PixmapWidget::init(int lineWidth, const QString &color, const QString &font) { color_ = QColor(color); font_.fromString(font); pen.setColor(color_); pen.setStyle(Qt::SolidLine); pen.setWidth(lineWidth); bar_->setColorForColorButton(color_); bar_->setLineWidth(lineWidth); } void PixmapWidget::setToolBar(ToolBar *bar) { bar_ = bar; connect(bar_,SIGNAL(buttonClicked(ToolBar::ButtonType)), this, SLOT(buttonClicked(ToolBar::ButtonType))); connect(bar_,SIGNAL(checkedButtonChanged(ToolBar::ButtonType)),this, SLOT(checkedButtonChanged(ToolBar::ButtonType))); connect(bar_,SIGNAL(newWidth(int)),this,SLOT(newWidth(int))); bar_->checkButton(ToolBar::ButtonSelect); Options* o = Options::instance(); init(o->getOption(constPenWidth, 2).toInt(), o->getOption(constColor, "#000000").toString(), o->getOption(constFont, "Sans Serif,18,-1,5,50,0,0,0,0,0").toString()); } void PixmapWidget::buttonClicked(ToolBar::ButtonType t) { switch(t) { case ToolBar::ButtonCut: cut(); return; case ToolBar::ButtonRotate: rotate(); return; case ToolBar::ButtonColor: selectColor(); return; case ToolBar::ButtonUndo: undo(); return; case ToolBar::ButtonCopy: copy(); return; case ToolBar::ButtonInsert: insert(); break; default: break; } selectionRect->clear(); update(); } void PixmapWidget::newWidth(int w) { pen.setWidth(w); settingsChanged(constPenWidth, QVariant(w)); } void PixmapWidget::setPixmap(const QPixmap& pix) { mainPixmap = QPixmap(); mainPixmap = pix; setFixedSize(mainPixmap.size()); selectionRect->clear(); update(); } void PixmapWidget::cut() { if(selectionRect->x() == -1) return; saveUndoPixmap(); setPixmap(mainPixmap.copy((QRect)*selectionRect)); emit adjusted(); } static QImage blurred(const QImage& image, const QRect& rect, int radius, bool alphaOnly = false) { int tab[] = { 14, 10, 8, 6, 5, 5, 4, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2 }; int alpha = (radius < 1) ? 16 : (radius > 17) ? 1 : tab[radius-1]; QImage result = image.convertToFormat(QImage::Format_ARGB32_Premultiplied); int r1 = rect.top(); int r2 = rect.bottom(); int c1 = rect.left(); int c2 = rect.right(); int bpl = result.bytesPerLine(); int rgba[4]; unsigned char* p; int i1 = 0; int i2 = 3; if (alphaOnly) i1 = i2 = (QSysInfo::ByteOrder == QSysInfo::BigEndian ? 0 : 3); for (int col = c1; col <= c2; col++) { p = result.scanLine(r1) + col * 4; for (int i = i1; i <= i2; i++) rgba[i] = p[i] << 4; p += bpl; for (int j = r1; j < r2; j++, p += bpl) for (int i = i1; i <= i2; i++) p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4; } for (int row = r1; row <= r2; row++) { p = result.scanLine(row) + c1 * 4; for (int i = i1; i <= i2; i++) rgba[i] = p[i] << 4; p += 4; for (int j = c1; j < c2; j++, p += 4) for (int i = i1; i <= i2; i++) p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4; } for (int col = c1; col <= c2; col++) { p = result.scanLine(r2) + col * 4; for (int i = i1; i <= i2; i++) rgba[i] = p[i] << 4; p -= bpl; for (int j = r1; j < r2; j++, p -= bpl) for (int i = i1; i <= i2; i++) p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4; } for (int row = r1; row <= r2; row++) { p = result.scanLine(row) + c2 * 4; for (int i = i1; i <= i2; i++) rgba[i] = p[i] << 4; p -= 4; for (int j = c1; j < c2; j++, p -= 4) for (int i = i1; i <= i2; i++) p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4; } return result; } void PixmapWidget::blur() { if(selectionRect->x() == -1) return; saveUndoPixmap(); bool ok = false; int radius = Options::instance()->getOption(constRadius, 5).toInt(); radius = QInputDialog::getInt(this, tr("Input radius"), tr("Radius"), radius, 1, 100, 1, &ok); if(!ok) return; Options::instance()->setOption(constRadius, radius); QImage im = mainPixmap.toImage(); mainPixmap = QPixmap::fromImage(blurred(im, *selectionRect, radius)); update(); } void PixmapWidget::insert() { const QPixmap pix = qApp->clipboard()->pixmap(); if(!pix.isNull()) { saveUndoPixmap(); setPixmap(pix); emit adjusted(); } } void PixmapWidget::copy() { QClipboard *clipboard = QApplication::clipboard(); QPixmap pix; if(selectionRect->width() != -1) { pix = mainPixmap.copy((QRect)*selectionRect); } else { pix = mainPixmap; } clipboard->setPixmap(pix); } void PixmapWidget::rotate() { saveUndoPixmap(); QTransform t; setPixmap(mainPixmap.transformed(t.rotate(90), Qt::SmoothTransformation)); emit adjusted(); } void PixmapWidget::paintEvent(QPaintEvent *) { QPainter p(this); p.setClipRect(rect()); p.drawPixmap(QPoint(0, 0), mainPixmap/*.scaled(size(), Qt::KeepAspectRatio, Qt::SmoothTransformation)*/); if((type_ == ToolBar::ButtonSelect || type_ == ToolBar::ButtonText)) { p.setPen(draftPen); if(p2.x() != -1) { int w = (p2.x() - p1.x()); int h = (p2.y() - p1.y()); p.drawRect(p1.x(), p1.y(), w, h); } else { p.drawRect(selectionRect->x(), selectionRect->y(), selectionRect->width(), selectionRect->height()); } } } void PixmapWidget::mousePressEvent(QMouseEvent *e) { if(e->buttons() == Qt::LeftButton) { if(cornerType == SelectionRect::NoCorner) { p1 = e->pos(); p2 = QPoint(-1, -1); if(type_ == ToolBar::ButtonPen) { smoothLineType_ = None; setAttribute(Qt::WA_OpaquePaintEvent, true); p2 = p1; saveUndoPixmap(); paintToPixmap(); } } else if(cornerType == SelectionRect::TopLeft) { p1 = selectionRect->bottomRight(); p2 = selectionRect->topLeft(); } else if(cornerType == SelectionRect::TopRight) { p1 = selectionRect->bottomLeft(); p2 = selectionRect->topRight(); } else if(cornerType == SelectionRect::BottomLeft) { p1 = selectionRect->topRight(); p2 = selectionRect->bottomLeft(); } else if(cornerType == SelectionRect::BottomRight) { p1 = selectionRect->topLeft(); p2 = selectionRect->bottomRight(); } cornerType = SelectionRect::NoCorner; } else if(e->buttons() == Qt::RightButton && selectionRect->contains(e->pos())) { QMenu m; m.addAction(tr("Cut"), this, SLOT(cut())); m.addAction(tr("Copy"), this, SLOT(copy())); m.addAction(tr("Blur"), this, SLOT(blur())); m.exec(e->globalPos()); } e->accept(); } void PixmapWidget::mouseDoubleClickEvent(QMouseEvent *e) { if(selectionRect->contains(e->pos()) && e->buttons() == Qt::LeftButton) cut(); e->accept(); } void PixmapWidget::mouseReleaseEvent(QMouseEvent *e) { if(e->button() != Qt::LeftButton) { e->accept(); return; } if(type_ == ToolBar::ButtonPen) { setAttribute(Qt::WA_OpaquePaintEvent, false); paintToPixmap(); } else if(type_ == ToolBar::ButtonText) { selectionRect->setCoords(qMin(p1.x(), p2.x()), qMin(p1.y(), p2.y()), qMax(p1.x(), p2.x()), qMax(p1.y(), p2.y())); GetTextDlg gtd(this); connect(>d, SIGNAL(text(QString)), SLOT(paintToPixmap(QString))); connect(>d, SIGNAL(selectFont()), SLOT(selectFont())); gtd.exec(); } else if(type_ == ToolBar::ButtonSelect && p1 != e->pos() && p1.x() != -1) { selectionRect->setCoords(qMin(p1.x(), p2.x()), qMin(p1.y(), p2.y()), qMax(p1.x(), p2.x()), qMax(p1.y(), p2.y())); int rw = selectionRect->width(); int rh = selectionRect->height(); if(selectionRect->x()+rw > width()) { selectionRect->setWidth(rw - (selectionRect->x()+rw - width() + 1)); } if(selectionRect->y()+rh > height()) { selectionRect->setHeight(rh - (selectionRect->y()+rh - height() + 1)); } if(selectionRect->x() < 1) selectionRect->setX(1); if(selectionRect->y() < 1) selectionRect->setY(1); } p1 = QPoint(-1, -1); p2 = QPoint(-1, -1); e->accept(); update(); } void PixmapWidget::mouseMoveEvent(QMouseEvent *e) { if(e->buttons() == Qt::LeftButton) { if(type_ == ToolBar::ButtonPen) { p1 = p2; p2 = e->pos(); if(e->modifiers() == Qt::ShiftModifier) { if(smoothLineType_ == None) { if(qAbs(p1.x() - p2.x()) > qAbs(p1.y() - p2.y())) { smoothLineType_ = Horizontal; } else { smoothLineType_ = Vertical; } } switch(smoothLineType_) { case Horizontal: p2.setY(p1.y()); break; case Vertical: p2.setX(p1.x()); break; case None: break; } } paintToPixmap(); } else if(type_ == ToolBar::ButtonSelect || type_ == ToolBar::ButtonText) { if(cornerType == SelectionRect::NoCorner) { if(e->pos().x() >= 0 && e->pos().y() >= 0) { p2 = e->pos(); } } update(); } } else if(e->buttons() == Qt::NoButton) { static bool cursorModified = false; cornerType = selectionRect->cornerUnderMouse(e->pos()); if(cornerType == SelectionRect::TopLeft || cornerType == SelectionRect::BottomRight) { setCursor(QCursor(Qt::SizeFDiagCursor)); cursorModified = true; } else if(cornerType == SelectionRect::TopRight || cornerType == SelectionRect::BottomLeft) { setCursor(QCursor(Qt::SizeBDiagCursor)); cursorModified = true; } else if(cursorModified) { setCursor(currentCursor); cursorModified = false; } } e->accept(); } void PixmapWidget::paintToPixmap(QString text) { QPainter painter; painter.begin(&mainPixmap); painter.setRenderHint(QPainter::Antialiasing); painter.setPen(pen); if(type_ == ToolBar::ButtonPen) { if(p1.x() != -1 && p2.x() != -1) { if(p1 != p2) painter.drawLine(p1, p2); else painter.drawPoint(p1); } } else if(type_ == ToolBar::ButtonText && !text.isEmpty() && selectionRect->x() != -1) { saveUndoPixmap(); painter.setFont(font_); painter.drawText((QRect)*selectionRect, text); selectionRect->clear(); } painter.end(); update(); } void PixmapWidget::selectColor() { QColorDialog cd; cd.setCurrentColor(color_); if(cd.exec() == QDialog::Accepted) { color_ = cd.currentColor(); pen.setColor(color_); bar_->setColorForColorButton(color_); settingsChanged(constColor, QVariant(color_.name())); } } void PixmapWidget::selectFont() { bool *ok = 0; font_ = QFontDialog::getFont(ok, font_, this); settingsChanged(constFont, QVariant(font_.toString())); } void PixmapWidget::undo() { if(!undoList_.isEmpty()) { setPixmap(undoList_.takeLast()); emit adjusted(); } bool hasUndo = !undoList_.isEmpty(); if(!hasUndo) { bar_->enableButton(hasUndo, ToolBar::ButtonUndo); emit modified(hasUndo); } } void PixmapWidget::saveUndoPixmap() { undoList_.append(mainPixmap); bar_->enableButton(true, ToolBar::ButtonUndo); emit modified(true); } void PixmapWidget::checkedButtonChanged(ToolBar::ButtonType type) { switch(type) { case(ToolBar::ButtonPen): { QIcon ico = ScreenshotIconset::instance()->getIcon("psi/draw"); currentCursor = QCursor(ico.pixmap(ico.availableSizes().first()), 2,15); break; } case(ToolBar::ButtonSelect): case(ToolBar::ButtonText): currentCursor = QCursor(Qt::CrossCursor); break; default: currentCursor = QCursor(Qt::ArrowCursor); break; } setCursor(currentCursor); selectionRect->clear(); type_ = type; cornerType = SelectionRect::NoCorner; update(); } #include "pixmapwidget.moc" plugins-1.5/generic/screenshotplugin/pixmapwidget.h000066400000000000000000000050721336777360500227500ustar00rootroot00000000000000/* * pixmapwidget.h - plugin * Copyright (C) 2009-2011 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef PIXMAPWIDGET_H #define PIXMAPWIDGET_H #include #include #include #include "toolbar.h" #define constPenWidth "penwidth" #define constColor "color" #define constFont "font" class SelectionRect : public QRect { public: SelectionRect(); SelectionRect(int left, int top, int w, int h); void clear(); enum CornerType { NoCorner, TopLeft, BottomLeft, TopRight, BottomRight }; CornerType cornerUnderMouse(const QPoint& pos) const; }; class PixmapWidget : public QWidget { Q_OBJECT public: PixmapWidget(QWidget *parent); ~PixmapWidget(); void setToolBar(ToolBar *bar); void setPixmap(const QPixmap& pix); QPixmap getPixmap() const { return mainPixmap; } private slots: void checkedButtonChanged(ToolBar::ButtonType type); void paintToPixmap(QString text = ""); void newWidth(int w); void buttonClicked(ToolBar::ButtonType); void cut(); void copy(); void selectFont(); void blur(); void insert(); protected: void mousePressEvent(QMouseEvent *e); void mouseDoubleClickEvent(QMouseEvent *e); void mouseReleaseEvent(QMouseEvent *e); void mouseMoveEvent(QMouseEvent *e); void paintEvent(QPaintEvent *); private: void saveUndoPixmap(); void selectColor(); void undo(); void rotate(); void init(int lineWidth, const QString& color, const QString& font); signals: void adjusted(); void settingsChanged(const QString&, const QVariant&); void modified(bool); private: ToolBar *bar_; QColor color_; QList undoList_; QPixmap mainPixmap; ToolBar::ButtonType type_; QPoint p1; QPoint p2; QPen pen; QPen draftPen; QFont font_; SelectionRect* selectionRect; QCursor currentCursor; SelectionRect::CornerType cornerType; enum SmoothLineType { None, Horizontal, Vertical }; SmoothLineType smoothLineType_; }; #endif // PIXMAPWIDGET_H plugins-1.5/generic/screenshotplugin/proxysettingsdlg.cpp000066400000000000000000000033161336777360500242310ustar00rootroot00000000000000/* * proxysettingsdlg.cpp - plugin * Copyright (C) 2011 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "proxysettingsdlg.h" #include "ui_proxysettingsdlg.h" ProxySettingsDlg::ProxySettingsDlg(QWidget *parent) : QDialog(parent) , ui(new Ui::ProxySettingsDlg) { ui->setupUi(this); ui->cb_type->addItems(QStringList() << "HTTP" << "SOCKS5"); ui->cb_type->setCurrentIndex(0); } ProxySettingsDlg::~ProxySettingsDlg() { delete ui; } void ProxySettingsDlg::setProxySettings(const Proxy &p) { proxy_ = p; ui->le_host->setText(p.host); ui->le_pass->setText(p.pass); ui->le_port->setText(QString::number(p.port)); ui->le_user->setText(p.user); if(p.type == "socks") { ui->cb_type->setCurrentIndex(1); } } void ProxySettingsDlg::accept() { if(ui->cb_type->currentText() == "HTTP") { proxy_.type = "http"; } else { proxy_.type = "socks"; } proxy_.host = ui->le_host->text(); proxy_.port = ui->le_port->text().toInt(); proxy_.user = ui->le_user->text(); proxy_.pass = ui->le_pass->text(); QDialog::accept(); } plugins-1.5/generic/screenshotplugin/proxysettingsdlg.h000066400000000000000000000024311336777360500236730ustar00rootroot00000000000000/* * proxysettingsdlg.h - plugin * Copyright (C) 2011 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef PROXYSETTINGS_H #define PROXYSETTINGS_H #include //for psi+ pluign only #include "applicationinfoaccessinghost.h" namespace Ui { class ProxySettingsDlg; } class ProxySettingsDlg : public QDialog { Q_OBJECT public: ProxySettingsDlg(QWidget *parent = 0); ~ProxySettingsDlg(); void setProxySettings(const Proxy& p); Proxy getSettings() const { return proxy_; }; public slots: void accept(); private: Ui::ProxySettingsDlg *ui; Proxy proxy_; }; #endif // PROXYSETTINGS_H plugins-1.5/generic/screenshotplugin/proxysettingsdlg.ui000066400000000000000000000101331336777360500240570ustar00rootroot00000000000000 ProxySettingsDlg 0 0 400 200 0 0 400 200 400 200 Proxy Server Settings Type: Qt::Horizontal 40 20 Host: Port: 99999; User: Password: QLineEdit::Password Qt::Vertical 20 38 Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok buttonBox accepted() ProxySettingsDlg accept() 248 254 157 274 buttonBox rejected() ProxySettingsDlg reject() 316 260 286 274 plugins-1.5/generic/screenshotplugin/qxt/000077500000000000000000000000001336777360500207055ustar00rootroot00000000000000plugins-1.5/generic/screenshotplugin/qxt/LICENSE000066400000000000000000000114201336777360500217100ustar00rootroot00000000000000Qt Extension Library Copyright (C) 2007 Qxt Foundation ------------------- Disclaimer ------------------------------------------------ Until the Qxt Foundation is legally established, copyright for the source code falls back to the original contributor. For information about the status of the Qxt Foundation, or about the copyright status of any part of Qxt, contact the Qxt project maintainers at Once the Qxt Foundation has been legally established, all contributors must transfer all copyright interest to the Qxt Foundation before their submissions will be added to the project. ------------------- License --------------------------------------------------- This library is free software; you can redistribute it and/or modify it under the terms of the Common Public License, version 1.0, as published by IBM or under the terms of the GNU Lesser General Public License, version 2.1, as published by the Free Software Foundation This file is provided "AS IS", without WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. You should have received a copy of the CPL along with this file. See the LICENSE file and the cpl1.0.txt file included with the source distribution for more information. If you did not receive a copy of the license, contact the Qxt Foundation. You should have received a copy of the LGPL along with this file. See the LICENSE file and the lgpl-2.1.txt file included with the source distribution for more information. If you did not receive a copy of the license, contact the Qxt Foundation. Parts of Qxt depend on Qt 4 and/or other libraries that have their own licenses. Qxt is independent of these licenses; however, use of these other libraries is subject to their respective license agreements. ------------------- Intent ---------------------------------------------------- The following section describes the opinions and intent of the Qxt Foundation with regards to the licensing and use of the Qxt source code and library. In the event that the CPL is found to be illegal or invalid, or if any application or clause of the license is subjected to question or abuse, this section is a general statement of the desired interpretation. This section has no legal standing and the statements made here are strictly subject to the text of the CPL; that is, if this section and the CPL are in disagreement, the text of the CPL takes precedence. In no way does this intent grant you any additional rights or impose any additional restrictions. If you have questions about licensing, contact the maintainers. Qxt is built and supported by open-source enthusiasts. - Please respect the open-source background of the contributors. The code is provided for everyone's use; you may not restrict the rights of anyone to use it. - No individual may claim ownership of any part of the code. It belongs to the community. - You may modify the source code to suit your needs, but these changes must be made free. If you distribute a modified form of Qxt, you must also distribute the entire source code of the modified form. - Digital Rights Management (DRM) puts unfair, unfree restrictions on users and developers. It is the opposite of Free Software. We can't stop you from using it, but please don't use the Qxt name for software restricted by DRM. - Please respect the time and effort put into the project by the developers. - If you find Qxt useful, it would be appreciated if you would include text in your application (for instance, in the About dialog) giving acknowledgement to Qxt. - If you make modifications to the source code, you must not call the modified version "Qxt." It's okay to include "Qxt" in the name, but anyone who receives the modified version needs to know that it's not the same as the version distributed by the Qxt Foundation. - We want everyone to be able to use Qxt without restrictions. - If you distribute Qxt in compiled binary form, please ensure that everyone who receives it can get the source code used to create it. - You are free to use Qxt in closed-source applications as long as you distribute Qxt in an open-source fashion. This does not require you to make your entire application open-source. - The Qxt Foundation is a non-profit, non-political organization. - Please don't use the Qxt name in any political or semi-political propaganda or publication. We don't like it. - Qxt is distributed "as-is," with no warranty. - If it makes your program crash, your computer blow up, or tiny demons fly out of your nose, please don't sue us. plugins-1.5/generic/screenshotplugin/qxt/core/000077500000000000000000000000001336777360500216355ustar00rootroot00000000000000plugins-1.5/generic/screenshotplugin/qxt/core/qxtglobal.cpp000066400000000000000000000206671336777360500243510ustar00rootroot00000000000000 /**************************************************************************** ** Copyright (c) 2006 - 2011, the LibQxt project. ** See the Qxt AUTHORS file for a list of authors and copyright holders. ** All rights reserved. ** ** Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in the ** documentation and/or other materials provided with the distribution. ** * Neither the name of the LibQxt project nor the ** names of its contributors may be used to endorse or promote products ** derived from this software without specific prior written permission. ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ** DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY ** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ** ** *****************************************************************************/ #include "qxtglobal.h" /*! \headerfile \title Global Qxt Declarations \inmodule QxtCore \brief The header provides basic declarations and is included by all other Qxt headers. */ /*! \macro QXT_VERSION \relates This macro expands a numeric value of the form 0xMMNNPP (MM = major, NN = minor, PP = patch) that specifies Qxt's version number. For example, if you compile your application against Qxt 0.4.0, the QXT_VERSION macro will expand to 0x000400. You can use QXT_VERSION to use the latest Qt features where available. For example: \code #if QXT_VERSION >= 0x000400 qxtTabWidget->setTabMovementMode(QxtTabWidget::InPlaceMovement); #endif \endcode \sa QXT_VERSION_STR, qxtVersion() */ /*! \macro QXT_VERSION_STR \relates This macro expands to a string that specifies Qxt's version number (for example, "0.4.0"). This is the version against which the application is compiled. \sa qxtVersion(), QXT_VERSION */ /*! \relates Returns the version number of Qxt at run-time as a string (for example, "0.4.0"). This may be a different version than the version the application was compiled against. \sa QXT_VERSION_STR */ const char * qxtVersion() { return QXT_VERSION_STR; } /*! \headerfile \title The Qxt private implementation \inmodule QxtCore \brief The header provides tools for hiding details of a class. Application code generally doesn't have to be concerned about hiding its implementation details, but when writing library code it is important to maintain a constant interface, both source and binary. Maintaining a constant source interface is easy enough, but keeping the binary interface constant means moving implementation details into a private class. The PIMPL, or d-pointer, idiom is a common method of implementing this separation. QxtPimpl offers a convenient way to connect the public and private sides of your class. \section1 Getting Started Before you declare the public class, you need to make a forward declaration of the private class. The private class must have the same name as the public class, followed by the word Private. For example, a class named MyTest would declare the private class with: \code class MyTestPrivate; \endcode \section1 The Public Class Generally, you shouldn't keep any data members in the public class without a good reason. Functions that are part of the public interface should be declared in the public class, and functions that need to be available to subclasses (for calling or overriding) should be in the protected section of the public class. To connect the private class to the public class, include the QXT_DECLARE_PRIVATE macro in the private section of the public class. In the example above, the private class is connected as follows: \code private: QXT_DECLARE_PRIVATE(MyTest) \endcode Additionally, you must include the QXT_INIT_PRIVATE macro in the public class's constructor. Continuing with the MyTest example, your constructor might look like this: \code MyTest::MyTest() { // initialization QXT_INIT_PRIVATE(MyTest); } \endcode \section1 The Private Class As mentioned above, data members should usually be kept in the private class. This allows the memory layout of the private class to change without breaking binary compatibility for the public class. Functions that exist only as implementation details, or functions that need access to private data members, should be implemented here. To define the private class, inherit from the template QxtPrivate class, and include the QXT_DECLARE_PUBLIC macro in its public section. The template parameter should be the name of the public class. For example: \code class MyTestPrivate : public QxtPrivate { public: MyTestPrivate(); QXT_DECLARE_PUBLIC(MyTest) }; \endcode \section1 Accessing Private Members Use the qxt_d() function (actually a function-like object) from functions in the public class to access the private class. Similarly, functions in the private class can invoke functions in the public class by using the qxt_p() function (this one's actually a function). For example, assume that MyTest has methods named getFoobar and doBaz(), and MyTestPrivate has a member named foobar and a method named doQuux(). The code might resemble this example: \code int MyTest::getFoobar() { return qxt_d().foobar; } void MyTestPrivate::doQuux() { qxt_p().doBaz(foobar); } \endcode */ /*! * \macro QXT_DECLARE_PRIVATE(PUB) * \relates * Declares that a public class has a related private class. * * This shuold be put in the private section of the public class. The * parameter \a PUB must be the name of the public class. */ /*! * \macro QXT_DECLARE_PUBLIC(PUB) * \relates * Declares that a private class has a related public class named \a PUB. * * This may be put anywhere in the declaration of the private class. The parameter is the name of the public class. */ /*! * \macro QXT_INIT_PRIVATE(PUB) * \relates * Initializes resources owned by the private class. * * This should be called from the public class's constructor, * before qxt_d() is used for the first time. The parameter \a PUB must be * the name of the public class. */ /*! * \macro QXT_D(PUB) * \relates * Returns a reference in the current scope named "d" to the private class * associated with the public class \a PUB. * * This function is only available in a class using QXT_DECLARE_PRIVATE(). */ /*! * \macro QXT_P(PUB) * \relates * Creates a reference in the current scope named "q" to the public class * named \a PUB. * * This macro only works in a class using QXT_DECLARE_PUBLIC(). */ /*! * \fn QxtPrivate& PUB::qxt_d() * \relates * Returns a reference to the private class. * * This function is only available in a class using \a QXT_DECLARE_PRIVATE. */ /*! * \fn const QxtPrivate& PUB::qxt_d() const * \relates * Returns a const reference to the private class. * * This function is only available in a class using \a QXT_DECLARE_PRIVATE. * This overload will be automatically used in const functions. */ /*! * \fn PUB& QxtPrivate::qxt_p() * \relates * Returns a reference to the public class. * * This function is only available in a class using QXT_DECLARE_PUBLIC(). */ /*! * \fn const PUB& QxtPrivate::qxt_p() const * \relates * Returns a const reference to the public class. * * This function is only available in a class using QXT_DECLARE_PUBLIC(). * This overload will be automatically used in const functions. */ plugins-1.5/generic/screenshotplugin/qxt/core/qxtglobal.h000066400000000000000000000155131336777360500240100ustar00rootroot00000000000000 /**************************************************************************** ** Copyright (c) 2006 - 2011, the LibQxt project. ** See the Qxt AUTHORS file for a list of authors and copyright holders. ** All rights reserved. ** ** Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in the ** documentation and/or other materials provided with the distribution. ** * Neither the name of the LibQxt project nor the ** names of its contributors may be used to endorse or promote products ** derived from this software without specific prior written permission. ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ** DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY ** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ** ** *****************************************************************************/ #ifndef QXTGLOBAL_H #define QXTGLOBAL_H #include #define QXT_VERSION 0x000700 #define QXT_VERSION_STR "0.7.0" //--------------------------global macros------------------------------ #ifndef QXT_NO_MACROS #endif // QXT_NO_MACROS //--------------------------export macros------------------------------ #define QXT_DLLEXPORT DO_NOT_USE_THIS_ANYMORE #if !defined(QXT_STATIC) && !defined(QXT_DOXYGEN_RUN) # if defined(BUILD_QXT_CORE) # define QXT_CORE_EXPORT Q_DECL_EXPORT # else # define QXT_CORE_EXPORT Q_DECL_IMPORT # endif #else # define QXT_CORE_EXPORT #endif // BUILD_QXT_CORE #if !defined(QXT_STATIC) && !defined(QXT_DOXYGEN_RUN) # if defined(BUILD_QXT_GUI) # define QXT_GUI_EXPORT Q_DECL_EXPORT # else # define QXT_GUI_EXPORT Q_DECL_IMPORT # endif #else # define QXT_GUI_EXPORT #endif // BUILD_QXT_GUI #if !defined(QXT_STATIC) && !defined(QXT_DOXYGEN_RUN) # if defined(BUILD_QXT_NETWORK) # define QXT_NETWORK_EXPORT Q_DECL_EXPORT # else # define QXT_NETWORK_EXPORT Q_DECL_IMPORT # endif #else # define QXT_NETWORK_EXPORT #endif // BUILD_QXT_NETWORK #if !defined(QXT_STATIC) && !defined(QXT_DOXYGEN_RUN) # if defined(BUILD_QXT_SQL) # define QXT_SQL_EXPORT Q_DECL_EXPORT # else # define QXT_SQL_EXPORT Q_DECL_IMPORT # endif #else # define QXT_SQL_EXPORT #endif // BUILD_QXT_SQL #if !defined(QXT_STATIC) && !defined(QXT_DOXYGEN_RUN) # if defined(BUILD_QXT_WEB) # define QXT_WEB_EXPORT Q_DECL_EXPORT # else # define QXT_WEB_EXPORT Q_DECL_IMPORT # endif #else # define QXT_WEB_EXPORT #endif // BUILD_QXT_WEB #if !defined(QXT_STATIC) && !defined(QXT_DOXYGEN_RUN) # if defined(BUILD_QXT_BERKELEY) # define QXT_BERKELEY_EXPORT Q_DECL_EXPORT # else # define QXT_BERKELEY_EXPORT Q_DECL_IMPORT # endif #else # define QXT_BERKELEY_EXPORT #endif // BUILD_QXT_BERKELEY #if !defined(QXT_STATIC) && !defined(QXT_DOXYGEN_RUN) # if defined(BUILD_QXT_ZEROCONF) # define QXT_ZEROCONF_EXPORT Q_DECL_EXPORT # else # define QXT_ZEROCONF_EXPORT Q_DECL_IMPORT # endif #else # define QXT_ZEROCONF_EXPORT #endif // QXT_ZEROCONF_EXPORT #if defined(BUILD_QXT_CORE) || defined(BUILD_QXT_GUI) || defined(BUILD_QXT_SQL) || defined(BUILD_QXT_NETWORK) || defined(BUILD_QXT_WEB) || defined(BUILD_QXT_BERKELEY) || defined(BUILD_QXT_ZEROCONF) # define BUILD_QXT #endif QXT_CORE_EXPORT const char* qxtVersion(); #ifndef QT_BEGIN_NAMESPACE #define QT_BEGIN_NAMESPACE #endif #ifndef QT_END_NAMESPACE #define QT_END_NAMESPACE #endif #ifndef QT_FORWARD_DECLARE_CLASS #define QT_FORWARD_DECLARE_CLASS(Class) class Class; #endif /**************************************************************************** ** This file is derived from code bearing the following notice: ** The sole author of this file, Adam Higerd, has explicitly disclaimed all ** copyright interest and protection for the content within. This file has ** been placed in the public domain according to United States copyright ** statute and case law. In jurisdictions where this public domain dedication ** is not legally recognized, anyone who receives a copy of this file is ** permitted to use, modify, duplicate, and redistribute this file, in whole ** or in part, with no restrictions or conditions. In these jurisdictions, ** this file shall be copyright (C) 2006-2008 by Adam Higerd. ****************************************************************************/ #define QXT_DECLARE_PRIVATE(PUB) friend class PUB##Private; QxtPrivateInterface qxt_d; #define QXT_DECLARE_PUBLIC(PUB) friend class PUB; #define QXT_INIT_PRIVATE(PUB) qxt_d.setPublic(this); #define QXT_D(PUB) PUB##Private& d = qxt_d() #define QXT_P(PUB) PUB& p = qxt_p() template class QxtPrivate { public: virtual ~QxtPrivate() {} inline void QXT_setPublic(PUB* pub) { qxt_p_ptr = pub; } protected: inline PUB& qxt_p() { return *qxt_p_ptr; } inline const PUB& qxt_p() const { return *qxt_p_ptr; } inline PUB* qxt_ptr() { return qxt_p_ptr; } inline const PUB* qxt_ptr() const { return qxt_p_ptr; } private: PUB* qxt_p_ptr; }; template class QxtPrivateInterface { friend class QxtPrivate; public: QxtPrivateInterface() { pvt = new PVT; } ~QxtPrivateInterface() { delete pvt; } inline void setPublic(PUB* pub) { pvt->QXT_setPublic(pub); } inline PVT& operator()() { return *static_cast(pvt); } inline const PVT& operator()() const { return *static_cast(pvt); } inline PVT * operator->() { return static_cast(pvt); } inline const PVT * operator->() const { return static_cast(pvt); } private: QxtPrivateInterface(const QxtPrivateInterface&) { } QxtPrivateInterface& operator=(const QxtPrivateInterface&) { } QxtPrivate* pvt; }; #endif // QXT_GLOBAL plugins-1.5/generic/screenshotplugin/qxt/gui/000077500000000000000000000000001336777360500214715ustar00rootroot00000000000000plugins-1.5/generic/screenshotplugin/qxt/gui/qxtwindowsystem.cpp000066400000000000000000000115321336777360500255100ustar00rootroot00000000000000#include "qxtwindowsystem.h" /**************************************************************************** ** Copyright (c) 2006 - 2011, the LibQxt project. ** See the Qxt AUTHORS file for a list of authors and copyright holders. ** All rights reserved. ** ** Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in the ** documentation and/or other materials provided with the distribution. ** * Neither the name of the LibQxt project nor the ** names of its contributors may be used to endorse or promote products ** derived from this software without specific prior written permission. ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ** DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY ** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ** ** *****************************************************************************/ #include /*! \class QxtWindowSystem \inmodule QxtWidgets \brief The QxtWindowSystem class provides means for accessing native windows. \bold {Note:} The underlying window system might or might not allow one to alter states of windows belonging to other processes. \warning QxtWindowSystem is portable in principle, but be careful while using it since you are probably about to do something non-portable. \section1 Advanced example usage: \code class NativeWindow : public QWidget { public: NativeWindow(WId wid) { QWidget::create(wid, false, false); // window, initializeWindow, destroyOldWindow } ~NativeWindow() { QWidget::destroy(false, false); // destroyWindow, destroySubWindows } }; \endcode \code WindowList windows = QxtWindowSystem::windows(); QStringList titles = QxtWindowSystem::windowTitles(); bool ok = false; QString title = QInputDialog::getItem(0, "Choose Window", "Choose a window to be hid:", titles, 0, false, &ok); if (ok) { int index = titles.indexOf(title); if (index != -1) { NativeWindow window(windows.at(index)); window.hide(); } } \endcode \bold {Note:} Currently supported platforms are \bold X11 and \bold Windows. */ /*! \fn QxtWindowSystem::windows() Returns the list of native window system identifiers. \sa QApplication::topLevelWidgets(), windowTitles() */ /*! \fn QxtWindowSystem::activeWindow() Returns the native window system identifier of the active window if any. \sa QApplication::activeWindow() */ /*! \fn QxtWindowSystem::findWindow(const QString& title) Returns the native window system identifier of the window if any with given \a title. Example usage: \code WId wid = QxtWindowSystem::findWindow("Mail - Kontact"); QPixmap screenshot = QPixmap::grabWindow(wid); \endcode \sa QWidget::find() */ /*! \fn QxtWindowSystem::windowAt(const QPoint& pos) Returns the native window system identifier of the window if any at \a pos. \sa QApplication::widgetAt() */ /*! \fn QxtWindowSystem::windowTitle(WId window) Returns the title of the native \a window. \sa QWidget::windowTitle(), windowTitles() */ /*! \fn QxtWindowSystem::windowTitles() Returns a list of native window titles. \sa QWidget::windowTitle(), windowTitle(), windows() */ /*! \fn QxtWindowSystem::windowGeometry(WId window) Returns the geometry of the native \a window. \sa QWidget::frameGeometry() */ /*! \fn QxtWindowSystem::idleTime() Returns the system "idle time" ie. the time since last user input in milliseconds. */ QStringList QxtWindowSystem::windowTitles() { WindowList windows = QxtWindowSystem::windows(); QStringList titles; foreach(WId window, windows) titles += QxtWindowSystem::windowTitle(window); return titles; } plugins-1.5/generic/screenshotplugin/qxt/gui/qxtwindowsystem.h000066400000000000000000000045261336777360500251620ustar00rootroot00000000000000#ifndef QXTWINDOWSYSTEM_H /**************************************************************************** ** Copyright (c) 2006 - 2011, the LibQxt project. ** See the Qxt AUTHORS file for a list of authors and copyright holders. ** All rights reserved. ** ** Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in the ** documentation and/or other materials provided with the distribution. ** * Neither the name of the LibQxt project nor the ** names of its contributors may be used to endorse or promote products ** derived from this software without specific prior written permission. ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ** DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY ** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ** ** *****************************************************************************/ #define QXTWINDOWSYSTEM_H #include #include "qxtglobal.h" typedef QList WindowList; class /*QXT_GUI_EXPORT*/ QxtWindowSystem { public: static WindowList windows(); static WId activeWindow(); static WId findWindow(const QString& title); static WId windowAt(const QPoint& pos); static QString windowTitle(WId window); static QStringList windowTitles(); static QRect windowGeometry(WId window); static uint idleTime(); }; #endif // QXTWINDOWSYSTEM_H plugins-1.5/generic/screenshotplugin/qxt/gui/qxtwindowsystem_mac.cpp000066400000000000000000000105551336777360500263340ustar00rootroot00000000000000#ifndef QXTWINDOWSYSTEM_MAC_CPP #define QXTWINDOWSYSTEM_MAC_CPP #include "qxtwindowsystem.h" #include "qxtwindowsystem_mac.h" // WId to return when error #define WINDOW_NOT_FOUND (WId)(0) WindowList qxt_getWindowsForPSN(ProcessSerialNumber *psn) { static CGSConnection connection = _CGSDefaultConnection(); WindowList wlist; if (!psn) return wlist; CGError err(noErr); // get onnection for given process psn CGSConnection procConnection; err = CGSGetConnectionIDForPSN(connection, psn, &procConnection); if (err != noErr) return wlist; /* get number of windows open by given process in Mac OS X an application may have multiple windows, which generally represent documents. It is also possible that there is no window even though there is an application, it can simply not have any documents open. */ int windowCount(0); err = CGSGetOnScreenWindowCount(connection, procConnection, &windowCount); // if there are no windows open by this application, skip if (err != noErr || windowCount == 0) return wlist; // get list of windows int windowList[windowCount]; int outCount(0); err = CGSGetOnScreenWindowList(connection, procConnection, windowCount, windowList, &outCount); if (err != noErr || outCount == 0) return wlist; for (int i=0; i 0) return wlist.at(0); return WINDOW_NOT_FOUND; } QString QxtWindowSystem::windowTitle(WId /*window*/) { /* CGSValue windowTitle; CGError err(noErr); static CGSConnection connection = _CGSDefaultConnection(); // This code is so dirty I had to wash my hands after writing it. // most of CoreGraphics private definitions ask for CGSValue as key but since // converting strings to/from CGSValue was dropped in 10.5, I use CFString, which // apparently also works. // FIXME: Not public API function. Can't compile with OS X 10.8 // err = CGSGetWindowProperty(connection, window, (CGSValue)CFSTR("kCGSWindowTitle"), &windowTitle); if (err != noErr) return QString(); // this is UTF8 encoded return QCFString::toQString((CFStringRef)windowTitle);*/ return QString(); } QRect QxtWindowSystem::windowGeometry(WId /*window*/) {/* CGRect rect; static CGSConnection connection = _CGSDefaultConnection(); CGError err = CGSGetWindowBounds(connection, window, &rect); if (err != noErr) return QRect(); return QRect(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);*/ return QRect(); } /* This method is the only one that is not a complete hack from Quartz Event Services http://developer.apple.com/library/mac/#documentation/Carbon/Reference/QuartzEventServicesRef/Reference/reference.html */ uint QxtWindowSystem::idleTime() { // CGEventSourceSecondsSinceLastEventType returns time in seconds as a double // also has extremely long name double idle = 0;//1000 * ::CGEventSourceSecondsSinceLastEventType(kCGEventSourceStateCombinedSessionState, kCGAnyInputEventType); return (uint)idle; } // these are copied from X11 implementation WId QxtWindowSystem::findWindow(const QString& /*title*/) { WId result = 0; /*WindowList list = windows(); foreach(const WId &wid, list) { if (windowTitle(wid) == title) { result = wid; break; } }*/ return result; } WId QxtWindowSystem::windowAt(const QPoint& /*pos*/) { WId result = 0; /*WindowList list = windows(); for (int i = list.size() - 1; i >= 0; --i) { WId wid = list.at(i); if (windowGeometry(wid).contains(pos)) { result = wid; break; } }*/ return result; } #endif // QXTWINDOWSYSTEM_MAC_CPP plugins-1.5/generic/screenshotplugin/qxt/gui/qxtwindowsystem_mac.h000066400000000000000000000130241336777360500257730ustar00rootroot00000000000000 /**************************************************************************** ** Copyright (c) 2006 - 2011, the LibQxt project. ** See the Qxt AUTHORS file for a list of authors and copyright holders. ** All rights reserved. ** ** Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in the ** documentation and/or other materials provided with the distribution. ** * Neither the name of the LibQxt project nor the ** names of its contributors may be used to endorse or promote products ** derived from this software without specific prior written permission. ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ** DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY ** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ** ** *****************************************************************************/ /**************************************************************************** ** ** Copyright (C) Marcin Jakubowski #define CGSConnectionID CGSConnection #define CGSWindowID CGSWindow #define CGSDefaultConnection _CGSDefaultConnection() #ifdef __cplusplus extern "C" { #endif typedef int CGSConnection; typedef int CGSWindow; typedef int CGSWorkspace; typedef void* CGSValue; /* Get the default connection for the current process. */ extern CGSConnection _CGSDefaultConnection(void); /* /MJakubowski/ Get connection for given PSN */ extern CGError CGSGetConnectionIDForPSN(const CGSConnection connection, ProcessSerialNumber * psn, CGSConnection * targetConnection); // Get on-screen window counts and lists. extern CGError CGSGetOnScreenWindowCount(const CGSConnection cid, CGSConnection targetCID, int* outCount); extern CGError CGSGetOnScreenWindowList(const CGSConnection cid, CGSConnection targetCID, int count, int* list, int* outCount); // Position extern CGError CGSGetWindowBounds(CGSConnection cid, CGSWindowID wid, CGRect *outBounds); extern CGError CGSGetScreenRectForWindow(const CGSConnection cid, CGSWindow wid, CGRect *outRect); // Properties extern CGError CGSGetWindowProperty(const CGSConnection cid, CGSWindow wid, CGSValue key, CGSValue *outValue); #ifdef __cplusplus } #endif /* QCFString from Qt */ #include template class QCFType { public: inline QCFType(const T &t = 0) : type(t) {} inline QCFType(const QCFType &helper) : type(helper.type) { if (type) CFRetain(type); } inline ~QCFType() { if (type) CFRelease(type); } inline operator T() { return type; } inline QCFType operator =(const QCFType &helper) { if (helper.type) CFRetain(helper.type); CFTypeRef type2 = type; type = helper.type; if (type2) CFRelease(type2); return *this; } inline T *operator&() { return &type; } static QCFType constructFromGet(const T &t) { CFRetain(t); return QCFType(t); } protected: T type; }; class QCFString : public QCFType { public: inline QCFString(const QString &str) : QCFType(0), string(str) {} inline QCFString(const CFStringRef cfstr = 0) : QCFType(cfstr) {} inline QCFString(const QCFType &other) : QCFType(other) {} operator QString() const; operator CFStringRef() const; static QString toQString(CFStringRef cfstr); static CFStringRef toCFStringRef(const QString &str); private: QString string; }; #endif // QXTWINDOWSYSTEM_MAC_H plugins-1.5/generic/screenshotplugin/qxt/gui/qxtwindowsystem_win.cpp000066400000000000000000000100001336777360500263520ustar00rootroot00000000000000#include "qxtwindowsystem.h" /**************************************************************************** ** Copyright (c) 2006 - 2011, the LibQxt project. ** See the Qxt AUTHORS file for a list of authors and copyright holders. ** All rights reserved. ** ** Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in the ** documentation and/or other materials provided with the distribution. ** * Neither the name of the LibQxt project nor the ** names of its contributors may be used to endorse or promote products ** derived from this software without specific prior written permission. ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ** DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY ** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ** ** *****************************************************************************/ #ifndef _WIN32_WINNT #define _WIN32_WINNT 0x0500 #endif #include #include // QT_WA static WindowList qxt_Windows; BOOL CALLBACK qxt_EnumWindowsProc(HWND hwnd, LPARAM lParam) { Q_UNUSED(lParam); if (::IsWindowVisible(hwnd)) qxt_Windows += (WId)hwnd; return true; } WindowList QxtWindowSystem::windows() { qxt_Windows.clear(); HDESK hdesk = ::OpenInputDesktop(0, false, DESKTOP_READOBJECTS); ::EnumDesktopWindows(hdesk, qxt_EnumWindowsProc, 0); ::CloseDesktop(hdesk); return qxt_Windows; } WId QxtWindowSystem::activeWindow() { return (WId)::GetForegroundWindow(); } WId QxtWindowSystem::findWindow(const QString& title) { #if QT_VERSION < QT_VERSION_CHECK(5,0,0) QT_WA({ return (WId)::FindWindow(NULL, (TCHAR*)title.utf16()); }, { return (WId)::FindWindowA(NULL, title.toLocal8Bit()); }); #else return (WId)::FindWindow(NULL, (TCHAR*)title.utf16()); #endif } WId QxtWindowSystem::windowAt(const QPoint& pos) { POINT pt; pt.x = pos.x(); pt.y = pos.y(); return (WId)::WindowFromPoint(pt); } QString QxtWindowSystem::windowTitle(WId window) { QString title; int len = ::GetWindowTextLength((HWND)window); if (len >= 0) { TCHAR* buf = new TCHAR[len+1]; len = ::GetWindowText((HWND)window, buf, len+1); #if QT_VERSION < QT_VERSION_CHECK(5,0,0) QT_WA({ title = QString::fromUtf16((const ushort*)buf, len); }, { title = QString::fromLocal8Bit((const char*)buf, len); }); #else title = QString::fromUtf16((const ushort*)buf, len); #endif delete[] buf; } return title; } QRect QxtWindowSystem::windowGeometry(WId window) { RECT rc; QRect rect; if (::GetWindowRect((HWND)window, &rc)) { rect.setTop(rc.top); rect.setBottom(rc.bottom); rect.setLeft(rc.left); rect.setRight(rc.right); } return rect; } uint QxtWindowSystem::idleTime() { uint idle = -1; LASTINPUTINFO info; info.cbSize = sizeof(LASTINPUTINFO); if (::GetLastInputInfo(&info)) idle = ::GetTickCount() - info.dwTime; return idle; } plugins-1.5/generic/screenshotplugin/qxt/gui/qxtwindowsystem_x11.cpp000066400000000000000000000151011336777360500261750ustar00rootroot00000000000000#include "qxtwindowsystem.h" /**************************************************************************** ** Copyright (c) 2006 - 2011, the LibQxt project. ** See the Qxt AUTHORS file for a list of authors and copyright holders. ** All rights reserved. ** ** Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in the ** documentation and/or other materials provided with the distribution. ** * Neither the name of the LibQxt project nor the ** names of its contributors may be used to endorse or promote products ** derived from this software without specific prior written permission. ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ** DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY ** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ** ** *****************************************************************************/ #include #include #include static WindowList qxt_getWindows(Atom prop) { WindowList res; Atom type = 0; int format = 0; uchar* data = 0; ulong count, after; Display* display = QX11Info::display(); Window window = QX11Info::appRootWindow(); if (XGetWindowProperty(display, window, prop, 0, 1024 * sizeof(Window) / 4, False, AnyPropertyType, &type, &format, &count, &after, &data) == Success) { Window* list = reinterpret_cast(data); for (uint i = 0; i < count; ++i) res += list[i]; if (data) XFree(data); } return res; } WindowList QxtWindowSystem::windows() { static Atom net_clients = 0; if (!net_clients) net_clients = XInternAtom(QX11Info::display(), "_NET_CLIENT_LIST_STACKING", True); return qxt_getWindows(net_clients); } WId QxtWindowSystem::activeWindow() { static Atom net_active = 0; if (!net_active) net_active = XInternAtom(QX11Info::display(), "_NET_ACTIVE_WINDOW", True); return qxt_getWindows(net_active).value(0); } WId QxtWindowSystem::findWindow(const QString& title) { Window result = 0; WindowList list = windows(); foreach (const Window &wid, list) { if (windowTitle(wid) == title) { result = wid; break; } } return result; } WId QxtWindowSystem::windowAt(const QPoint& pos) { Window result = 0; WindowList list = windows(); for (int i = list.size() - 1; i >= 0; --i) { WId wid = list.at(i); if (windowGeometry(wid).contains(pos)) { result = wid; break; } } return result; } QString QxtWindowSystem::windowTitle(WId window) { QString name; char* str = 0; if (XFetchName(QX11Info::display(), window, &str)) name = QString::fromLatin1(str); if (str) XFree(str); return name; } QRect QxtWindowSystem::windowGeometry(WId window) { int x, y; uint width, height, border, depth; Window root, child; Display* display = QX11Info::display(); XGetGeometry(display, window, &root, &x, &y, &width, &height, &border, &depth); XTranslateCoordinates(display, window, root, x, y, &x, &y, &child); static Atom net_frame = 0; if (!net_frame) net_frame = XInternAtom(QX11Info::display(), "_NET_FRAME_EXTENTS", True); QRect rect(x, y, width, height); Atom type = 0; int format = 0; uchar* data = 0; ulong count, after; if (XGetWindowProperty(display, window, net_frame, 0, 4, False, AnyPropertyType, &type, &format, &count, &after, &data) == Success) { // _NET_FRAME_EXTENTS, left, right, top, bottom, CARDINAL[4]/32 if (count == 4) { long* extents = reinterpret_cast(data); rect.adjust(-extents[0], -extents[2], extents[1], extents[3]); } if (data) XFree(data); } return rect; } typedef struct { Window window; /* screen saver window - may not exist */ int state; /* ScreenSaverOff, ScreenSaverOn, ScreenSaverDisabled*/ int kind; /* ScreenSaverBlanked, ...Internal, ...External */ unsigned long til_or_since; /* time til or since screen saver */ unsigned long idle; /* total time since last user input */ unsigned long eventMask; /* currently selected events for this client */ } XScreenSaverInfo; typedef XScreenSaverInfo* (*XScreenSaverAllocInfo)(); typedef Status (*XScreenSaverQueryInfo)(Display* display, Drawable drawable, XScreenSaverInfo* info); static XScreenSaverAllocInfo _xScreenSaverAllocInfo = 0; static XScreenSaverQueryInfo _xScreenSaverQueryInfo = 0; uint QxtWindowSystem::idleTime() { static bool xssResolved = false; if (!xssResolved) { QLibrary xssLib(QLatin1String("Xss"), 1); if (xssLib.load()) { _xScreenSaverAllocInfo = (XScreenSaverAllocInfo) xssLib.resolve("XScreenSaverAllocInfo"); _xScreenSaverQueryInfo = (XScreenSaverQueryInfo) xssLib.resolve("XScreenSaverQueryInfo"); xssResolved = true; } } uint idle = 0; if (xssResolved) { XScreenSaverInfo* info = _xScreenSaverAllocInfo(); const int screen = QX11Info::appScreen(); unsigned long rootWindow = (unsigned long)QX11Info::appRootWindow(screen); _xScreenSaverQueryInfo(QX11Info::display(), (Drawable) rootWindow, info); idle = info->idle; if (info) XFree(info); } return idle; } plugins-1.5/generic/screenshotplugin/qxt/gui/x11info.cpp000066400000000000000000000033511336777360500234640ustar00rootroot00000000000000/* * Copyright (C) 2013 Sergey Ilinykh (rion) * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include "x11info.h" #ifdef HAVE_QT5 # include # include # include #else # include #endif Display* X11Info::display() { #ifdef HAVE_QT5 if (!_display) { _display = XOpenDisplay(NULL); } return _display; #else return QX11Info::display(); #endif } unsigned long X11Info::appRootWindow(int screen) { #ifdef HAVE_QT5 return screen == -1? XDefaultRootWindow(display()) : XRootWindowOfScreen(XScreenOfDisplay(display(), screen)); #else return QX11Info::appRootWindow(screen); #endif } int X11Info::appScreen() { #ifdef HAVE_QT5 #error X11Info::appScreen not implemented for Qt5! You must skip this plugin. #else return QX11Info::appScreen(); #endif } #ifdef HAVE_QT5 xcb_connection_t *X11Info::xcbConnection() { if (!_xcb) { _xcb = xcb_connect(NULL, &_xcbPreferredScreen); Q_ASSERT(_xcb); } return _xcb; } xcb_connection_t* X11Info::_xcb = 0; #endif Display* X11Info::_display = 0; int X11Info::_xcbPreferredScreen = 0; plugins-1.5/generic/screenshotplugin/qxt/gui/x11info.h000066400000000000000000000024611336777360500231320ustar00rootroot00000000000000/* * Copyright (C) 2013 Sergey Ilinykh (rion) * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef X11INFO_H #define X11INFO_H typedef struct _XDisplay Display; #ifdef HAVE_QT5 typedef struct xcb_connection_t xcb_connection_t; #endif class X11Info { static Display *_display; #ifdef HAVE_QT5 static xcb_connection_t *_xcb; #endif static int _xcbPreferredScreen; public: static Display* display(); static unsigned long appRootWindow(int screen = -1); static int appScreen(); #ifdef HAVE_QT5 static xcb_connection_t* xcbConnection(); static inline int xcbPreferredScreen() { return _xcbPreferredScreen; } #endif }; #endif // X11INFO_H plugins-1.5/generic/screenshotplugin/screenshot.cpp000066400000000000000000000575321336777360500227660ustar00rootroot00000000000000/* * screenshot.cpp - plugin * Copyright (C) 2009-2011 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "screenshot.h" #include "server.h" #include "screenshotoptions.h" #include "options.h" #include "screenshoticonset.h" #include "optionsdlg.h" #include "proxysettingsdlg.h" #include "defines.h" #include "qxtwindowsystem.h" #define PROTOCOL_FTP "ftp" #define PROTOCOL_HTTP "http" #define MAX_HISTORY_SIZE 10 //---------------------------------------------- //-----------HistoryDlg------------------------- //---------------------------------------------- class HistoryDlg : public QDialog { Q_OBJECT public: HistoryDlg(const QStringList& list, QWidget* p = 0) : QDialog(p, Qt::Window) { setAttribute(Qt::WA_DeleteOnClose); setModal(false); setWindowModality(Qt::NonModal); setWindowTitle(tr("History")); QVBoxLayout *l = new QVBoxLayout(this); lw = new QListWidget(this); lw->addItems(list); l->addWidget(lw); QHBoxLayout *bl = new QHBoxLayout(); QPushButton *copyButton = new QPushButton(tr("Copy")); copyButton->setToolTip(tr("Copy link to the clipboard")); copyButton->setIcon(style()->standardIcon(QStyle::SP_DialogOpenButton)); QPushButton *openButton = new QPushButton(tr("Open")); openButton->setToolTip(tr("Open link in browser")); openButton->setIcon(style()->standardIcon(QStyle::SP_BrowserReload)); QPushButton *closeButton = new QPushButton(tr("Close")); closeButton->setToolTip(tr("Close history")); closeButton->setIcon(style()->standardIcon(QStyle::SP_DialogCloseButton)); bl->addWidget(copyButton); bl->addWidget(openButton); bl->addStretch(); bl->addWidget(closeButton); l->addLayout(bl); connect(closeButton, SIGNAL(clicked()), SLOT(close())); connect(copyButton, SIGNAL(clicked()), SLOT(copy())); connect(openButton, SIGNAL(clicked()), SLOT(itemActivated())); connect(lw, SIGNAL(activated(QModelIndex)), SLOT(itemActivated())); resize(500, 300); show(); } private slots: void itemActivated() { QListWidgetItem *lwi = lw->currentItem(); if(lwi) { QDesktopServices::openUrl(QUrl(lwi->text())); } } void copy() { QListWidgetItem *lwi = lw->currentItem(); if(lwi) { qApp->clipboard()->setText(lwi->text()); } } private: QListWidget* lw; }; //---------------------------------------------- //-----------GrabAreaWidget------------------------- //---------------------------------------------- class GrabAreaWidget : public QDialog { Q_OBJECT public: GrabAreaWidget() : QDialog() , startPoint(QPoint(-1, -1)) , endPoint(QPoint(-1, -1)) { setAttribute(Qt::WA_TranslucentBackground, true); setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint); setWindowTitle(tr("Select area")); setWindowState(Qt::WindowFullScreen); setCursor(Qt::CrossCursor); resize(QApplication::desktop()->size()); } ~GrabAreaWidget() { } QRect getRect() const { QRect r; if(endPoint.x() != -1) { r = QRect(qMin(startPoint.x(), endPoint.x()), qMin(startPoint.y(), endPoint.y()), qAbs(startPoint.x() - endPoint.x()), qAbs(startPoint.y() - endPoint.y())); } return r; } protected: void mousePressEvent(QMouseEvent *e) { if(e->button() == Qt::LeftButton) { startPoint = e->pos(); } else { QDialog::reject(); } } void mouseMoveEvent(QMouseEvent *e) { if(e->buttons() & Qt::LeftButton) { endPoint = e->pos(); update(); } } void mouseReleaseEvent(QMouseEvent *e) { if(!(e->buttons() & Qt::LeftButton)) { endPoint = e->pos(); QDialog::accept(); } } void paintEvent(QPaintEvent *) { QPainter painter(this); QColor c("#f0f0f0"); c.setAlpha(80); QRect r = getRect(); if(r.isValid()) { QPainterPath path; path.addRect(0, 0, width(), r.top()); path.addRect(r.right(), r.top(), rect().width() - r.right(), r.height()-1); path.addRect(0, r.bottom(), width(), height() - r.bottom()); path.addRect(0, r.top(), r.left(), r.height()-1); painter.fillPath(path, c); QPen pen(Qt::gray); pen.setWidth(1); painter.setPen(pen); painter.drawRect(r); } else { painter.fillRect(rect(), c); } } private: QPoint startPoint, endPoint; }; //---------------------------------------------- //-----------Screenshot------------------------- //---------------------------------------------- Screenshot::Screenshot() : QMainWindow() , modified(false) , lastFolder(QDir::home().absolutePath()) , grabAreaWidget_(0) , so_(0) { setAttribute(Qt::WA_DeleteOnClose); ui_.setupUi(this); updateWidgets(false); ui_.urlFrame->setVisible(false); refreshSettings(); history_ = Options::instance()->getOption(constHistory).toStringList(); ui_.lb_pixmap->setToolBar(ui_.tb_bar); ScreenshotIconset* icoHost = ScreenshotIconset::instance(); ui_.pb_upload->setIcon(icoHost->getIcon("psi/upload")); ui_.pb_cancel->setIcon(icoHost->getIcon("psi/cancel")); ui_.pb_open->setIcon(icoHost->getIcon("psi/browse")); ui_.pb_save->setIcon(icoHost->getIcon("psi/download")); ui_.pb_print->setIcon(icoHost->getIcon("psi/print")); ui_.pb_new_screenshot->setIcon(icoHost->getIcon("screenshotplugin/screenshot")); ui_.tb_copyUrl->setIcon(icoHost->getIcon("psi/copy")); ui_.pb_save->setShortcut(QKeySequence("Ctrl+s")); ui_.pb_upload->setShortcut(QKeySequence("Ctrl+u")); ui_.pb_open->setShortcut(QKeySequence("Ctrl+o")); ui_.pb_print->setShortcut(QKeySequence("Ctrl+p")); ui_.pb_new_screenshot->setShortcut(QKeySequence("Ctrl+n")); connectMenu(); setupStatusBar(); connect(ui_.pb_save, SIGNAL(clicked()), this, SLOT(saveScreenshot())); connect(ui_.pb_upload, SIGNAL(clicked()), this, SLOT(uploadScreenshot())); connect(ui_.pb_print, SIGNAL(clicked()), this, SLOT(printScreenshot())); connect(ui_.pb_new_screenshot, SIGNAL(clicked()), this, SLOT(newScreenshot())); connect(ui_.pb_cancel,SIGNAL(clicked()),this,SLOT(cancelUpload())); connect(ui_.pb_open, SIGNAL(clicked()), this, SLOT(openImage())); connect(ui_.lb_pixmap, SIGNAL(adjusted()), this, SLOT(pixmapAdjusted())); connect(ui_.lb_pixmap, SIGNAL(settingsChanged(QString,QVariant)), SLOT(settingsChanged(QString, QVariant))); connect(ui_.lb_pixmap, SIGNAL(modified(bool)), this, SLOT(setModified(bool))); connect(ui_.tb_copyUrl, SIGNAL(clicked()), this, SLOT(copyUrl())); setWindowIcon(icoHost->getIcon("screenshotplugin/screenshot")); ui_.lb_pixmap->installEventFilter(this); } Screenshot::~Screenshot() { qDeleteAll(servers); servers.clear(); saveGeometry(); delete grabAreaWidget_; delete so_; } void Screenshot::connectMenu() { connect(ui_.actionAbout_Qt, SIGNAL(triggered()), SLOT(aboutQt())); connect(ui_.actionHome_page, SIGNAL(triggered()), SLOT(doHomePage())); connect(ui_.actionExit, SIGNAL(triggered()), SLOT(close())); connect(ui_.actionHistory, SIGNAL(triggered()), SLOT(doHistory())); connect(ui_.actionNew_Screenshot, SIGNAL(triggered()), SLOT(newScreenshot())); connect(ui_.actionOpen_Image, SIGNAL(triggered()), SLOT(openImage())); connect(ui_.actionOptions, SIGNAL(triggered()), SLOT(doOptions())); connect(ui_.actionPrint, SIGNAL(triggered()), SLOT(printScreenshot())); //connect(ui_.actionProxy_Settings, SIGNAL(triggered()), SLOT(doProxySettings())); connect(ui_.actionSave, SIGNAL(triggered()), SLOT(saveScreenshot())); connect(ui_.actionUpload, SIGNAL(triggered()), SLOT(uploadScreenshot())); } void Screenshot::action(int action) { switch(action) { case Area: captureArea(0); break; case Window: captureWindow(0); break; case Desktop: default: shootScreen(); break; } } void Screenshot::setupStatusBar() { QStatusBar *sb = statusBar(); sbLbSize = new QLabel; sbLbSize->setAlignment(Qt::AlignRight); sbLbSize->setTextInteractionFlags(Qt::TextSelectableByKeyboard | Qt::TextSelectableByMouse); sb->addPermanentWidget(sbLbSize); } void Screenshot::updateStatusBar() { const QSize s = ui_.lb_pixmap->getPixmap().size(); QBuffer buffer; buffer.open( QBuffer::ReadWrite ); ui_.lb_pixmap->getPixmap().save( &buffer , format.toLatin1() ); const qint64 size = buffer.size(); sbLbSize->setText(tr("Size: %1x%2px; %3 bytes").arg(s.width()).arg(s.height()).arg(size)); // sbLbSize->setMaximumWidth( QFontMetrics( sbLbSize->font() ).width( sbLbSize->text() ) + 10 ); } void Screenshot::aboutQt() { qApp->aboutQt(); } void Screenshot::doHomePage() { QDesktopServices::openUrl(QUrl("http://psi-plus.com/wiki/plugins#screenshot_plugin")); } void Screenshot::updateWidgets(bool vis) { ui_.progressBar->setVisible(vis); ui_.pb_cancel->setVisible(vis); ui_.cb_servers->setEnabled(!vis); ui_.pb_upload->setEnabled(!vis); } void Screenshot::setServersList(const QStringList& l) { ui_.cb_servers->clear(); qDeleteAll(servers); servers.clear(); ui_.cb_servers->setEnabled(false); ui_.pb_upload->setEnabled(false); foreach(QString settings, l) { if(settings.isEmpty()) { continue; } Server *s = new Server(); s->setFromString(settings); servers.append(s); ui_.cb_servers->addItem(s->displayName()); } if(servers.size() > 0) { ui_.cb_servers->setEnabled(true); ui_.pb_upload->setEnabled(true); } } void Screenshot::setProxy(const Proxy& p) { proxy_ = p; } void Screenshot::openImage() { QString fileName = QFileDialog::getOpenFileName(0,tr("Open Image"), lastFolder,tr("Images (*.png *.gif *.jpg *.jpeg *.ico)")); if(!fileName.isEmpty()) { setImagePath(fileName); QFileInfo fi(fileName); lastFolder = fi.absoluteDir().path(); settingsChanged(constLastFolder, lastFolder); updateScreenshotLabel(); bringToFront(); setModified(false); } } void Screenshot::setImagePath(const QString& path) { originalPixmap = QPixmap(path); updateScreenshotLabel(); } void Screenshot::updateScreenshotLabel() { ui_.lb_pixmap->setPixmap(originalPixmap); updateStatusBar(); } void Screenshot::pixmapAdjusted() { updateStatusBar(); if(windowState() == Qt::WindowMaximized) return; QSize s = ui_.lb_pixmap->size(); if(s.height() > 600 || s.width() > 800) resize(800,600); else { ui_.scrollArea->setMinimumSize(s + QSize(15,20)); //хак, для красивого уменьшения размера главного окна adjustSize(); QTimer::singleShot(100, this, SLOT(fixSizes())); // необходимо время, чтобы ресайзить главное окно } } void Screenshot::fixSizes() { ui_.scrollArea->setMinimumSize(0,0); } void Screenshot::setModified(bool m) { modified = m; } void Screenshot::printScreenshot() { QPrinter p; QPrintDialog *pd = new QPrintDialog(&p, this); if(pd->exec() == QDialog::Accepted && p.isValid()) { QPainter painter; painter.begin(&p); QPixmap pix = ui_.lb_pixmap->getPixmap(); const QSize size = p.pageRect().size(); if(pix.size().height() > size.height() || pix.size().width() > size.width()) { pix = pix.scaled(size, Qt::KeepAspectRatio, Qt::SmoothTransformation); } painter.drawPixmap(0, 0, pix); painter.end(); } delete pd; } void Screenshot::cancelUpload() { if(manager) { manager->disconnect(); manager->deleteLater(); } updateWidgets(false); } void Screenshot::bringToFront() { Options* o = Options::instance(); int x = o->getOption(constWindowX, 0).toInt(); int y = o->getOption(constWindowY, 0).toInt(); int h = o->getOption(constWindowHeight, 600).toInt(); int w = o->getOption(constWindowWidth, 800).toInt(); bool max = o->getOption(constWindowState, true).toBool(); resize(w, h); move(x, y); if(max) showMaximized(); else showNormal(); raise(); activateWindow(); } void Screenshot::newScreenshot() { so_ = new ScreenshotOptions(Options::instance()->getOption(constDelay).toInt()); connect(so_, SIGNAL(captureArea(int)), SLOT(captureArea(int))); connect(so_, SIGNAL(captureWindow(int)), this, SLOT(captureWindow(int))); connect(so_, SIGNAL(captureDesktop(int)), SLOT(captureDesktop(int))); connect(so_, SIGNAL(screenshotCanceled()), SLOT(screenshotCanceled())); saveGeometry(); ui_.pb_new_screenshot->setEnabled(false); setWindowState(Qt::WindowMinimized); so_->show(); so_->raise(); so_->activateWindow(); } void Screenshot::screenshotCanceled() { ui_.pb_new_screenshot->setEnabled(true); if(!isHidden()) bringToFront(); } void Screenshot::refreshWindow() { ui_.pb_new_screenshot->setEnabled(true); ui_.urlFrame->setVisible(false); updateScreenshotLabel(); bringToFront(); setModified(false); } void Screenshot::captureArea(int delay) { grabAreaWidget_ = new GrabAreaWidget(); if(grabAreaWidget_->exec() == QDialog::Accepted) { QTimer::singleShot(delay*1000, this, SLOT(shootArea())); } else { delete grabAreaWidget_; grabAreaWidget_ = 0; qApp->desktop()->repaint(); refreshWindow(); } } void Screenshot::shootArea() { if(!grabAreaWidget_) { return; } const QRect rect = grabAreaWidget_->getRect(); if(rect.isValid()) { qApp->desktop()->repaint(); qApp->beep(); originalPixmap = QPixmap::grabWindow(QApplication::desktop()->winId(), rect.x(), rect.y(), rect.width(), rect.height()); } delete grabAreaWidget_; grabAreaWidget_ = 0; refreshWindow(); } void Screenshot::captureWindow(int delay) { QTimer::singleShot(delay*1000, this, SLOT(shootWindow())); } void Screenshot::shootWindow() { qApp->beep(); originalPixmap = QPixmap::grabWindow(QxtWindowSystem::activeWindow()); refreshWindow(); } void Screenshot::captureDesktop(int delay) { QTimer::singleShot(delay*1000, this, SLOT(shootScreen())); } void Screenshot::shootScreen() { qApp->beep(); originalPixmap = QPixmap::grabWindow(QApplication::desktop()->winId()); refreshWindow(); } void Screenshot::saveScreenshot() { ui_.pb_save->setEnabled(false); originalPixmap = ui_.lb_pixmap->getPixmap(); QString initialPath = lastFolder + tr("/%1.").arg(QDateTime::currentDateTime().toString(fileNameFormat)) + format; QString fileName = QFileDialog::getSaveFileName(this, tr("Save As"), initialPath, tr("%1 Files (*.%2);;All Files (*)") .arg(format.toUpper()) .arg(format)); if (!fileName.isEmpty()) { originalPixmap.save(fileName, format.toLatin1()); QFileInfo fi(fileName); lastFolder = fi.absoluteDir().path(); settingsChanged(constLastFolder, lastFolder); } ui_.pb_save->setEnabled(true); modified = false; } void Screenshot::copyUrl() { QString url = ui_.lb_url->text(); if(!url.isEmpty()) { QRegExp re("([^<]+)"); if(re.indexIn(url) != -1) { url = re.cap(1); qApp->clipboard()->setText(url); } } } void Screenshot::dataTransferProgress(qint64 done, qint64 total) { ui_.progressBar->setMaximum(total); ui_.progressBar->setValue(done); } void Screenshot::uploadScreenshot() { if(!ui_.cb_servers->isEnabled()) return; int index = ui_.cb_servers->currentIndex(); if(index == -1 || servers.size() <= index) return; Server *s = servers.at(index); if(!s) return; QString scheme = QUrl(s->url()).scheme(); ui_.pb_upload->setEnabled(false); ui_.pb_cancel->setVisible(true); ui_.cb_servers->setEnabled(false); originalPixmap = ui_.lb_pixmap->getPixmap(); if (scheme.toLower() == QLatin1String(PROTOCOL_FTP)) { uploadFtp(); } else if (scheme.toLower() == QLatin1String(PROTOCOL_HTTP)) { uploadHttp(); } else cancelUpload(); } void Screenshot::uploadFtp() { ba.clear(); QBuffer buffer( &ba ); buffer.open( QBuffer::ReadWrite ); originalPixmap.save( &buffer , format.toLatin1() ); QString fileName = tr("%1.").arg(QDateTime::currentDateTime().toString(fileNameFormat)) + format; QFileInfo fi(fileName); fileName = fi.fileName(); Server *s = servers.at(ui_.cb_servers->currentIndex()); if(!s) cancelUpload(); QUrl u; u.setPort(21); u.setUrl(s->url(), QUrl::TolerantMode); u.setUserName(s->userName()); u.setPassword(s->password()); if(manager) { delete manager; } manager = new QNetworkAccessManager(this); if(s->useProxy() && !proxy_.host.isEmpty()) { QNetworkProxy p = QNetworkProxy(QNetworkProxy::HttpCachingProxy, proxy_.host, proxy_.port, proxy_.user, proxy_.pass); if(proxy_.type == "socks") p.setType(QNetworkProxy::Socks5Proxy); manager->setProxy(p); } QString path = u.path(); if(path.right(1) != "/") path += "/"; u.setPath(path+fileName); ui_.progressBar->setValue(0); ui_.progressBar->show(); ui_.urlFrame->setVisible(false); QNetworkReply *reply = manager->put(QNetworkRequest(u), ba); connect(reply, SIGNAL(uploadProgress(qint64 , qint64)), this, SLOT(dataTransferProgress(qint64 , qint64))); //connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(replyError(QNetworkReply::NetworkError))); connect(reply, SIGNAL(finished()), this, SLOT(ftpReplyFinished())); modified = false; } void Screenshot::uploadHttp() { ba.clear(); QString boundary = "AaB03x"; QString filename = tr("%1.").arg(QDateTime::currentDateTime().toString(fileNameFormat)) + format; Server *s = servers.at(ui_.cb_servers->currentIndex()); if(!s) cancelUpload(); if (s->servPostdata().length()>0) { foreach (QString poststr, s->servPostdata().split("&")) { QStringList postpair = poststr.split("="); if(postpair.count() < 2) continue; ba.append("--" + boundary + "\r\n"); ba.append("Content-Disposition: form-data; name=\"" + postpair[0] + "\"\r\n"); ba.append("\r\n" + postpair[1] + "\r\n"); } } ba.append("--" + boundary + "\r\n"); ba.append("Content-Disposition: form-data; name=\"" + s->servFileinput() + "\"; filename=\"" + filename.toUtf8() + "\"\r\n"); ba.append("Content-Transfer-Encoding: binary\r\n"); ba.append(QString("Content-Type: image/%1\r\n") .arg(format == "jpg" ? "jpeg" : format) // FIXME!!!!! жуткий костыль, но что поделаешь .toUtf8()); ba.append("\r\n"); QByteArray a; QBuffer buffer(&a); buffer.open( QBuffer::ReadWrite ); originalPixmap.save( &buffer , format.toLatin1() ); ba.append(a); ba.append("\r\n--" + boundary + "--\r\n"); if(manager) { delete manager; } manager = new QNetworkAccessManager(this); if(s->useProxy() && !proxy_.host.isEmpty()) { QNetworkProxy p = QNetworkProxy(QNetworkProxy::HttpCachingProxy, proxy_.host, proxy_.port, proxy_.user, proxy_.pass); if(proxy_.type == "socks") p.setType(QNetworkProxy::Socks5Proxy); manager->setProxy(p); } QNetworkRequest netreq; netreq.setUrl(QUrl(s->url())); netreq.setRawHeader("User-Agent", "Psi-Plus Screenshot plugin"); netreq.setRawHeader("Content-Type", "multipart/form-data, boundary=" + boundary.toLatin1()); netreq.setRawHeader("Cache-Control", "no-cache"); netreq.setRawHeader("Accept", "*/*"); netreq.setRawHeader("Content-Length", QString::number(ba.length()).toLatin1()); ui_.progressBar->setValue(0); ui_.progressBar->show(); ui_.urlFrame->setVisible(false); QNetworkReply* reply = manager->post(netreq, ba); connect(reply, SIGNAL(uploadProgress(qint64 , qint64)), this, SLOT(dataTransferProgress(qint64 , qint64))); connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(httpReplyFinished(QNetworkReply*))); modified = false; } void Screenshot::ftpReplyFinished() { QNetworkReply *reply = (QNetworkReply*)sender(); ui_.urlFrame->setVisible(true); if(reply->error() == QNetworkReply::NoError) { const QString url = reply->url().toString(QUrl::RemoveUserInfo | QUrl::StripTrailingSlash); ui_.lb_url->setText(QString("%1").arg(url)); history_.push_front(url); if(history_.size() > MAX_HISTORY_SIZE) { history_.removeLast(); } settingsChanged(constHistory, history_); } else { ui_.lb_url->setText(reply->errorString()); } reply->close(); reply->deleteLater(); updateWidgets(false); } void Screenshot::httpReplyFinished(QNetworkReply *reply) { if(reply->error() != QNetworkReply::NoError) { ui_.urlFrame->setVisible(true); ui_.lb_url->setText(reply->errorString()); updateWidgets(false); reply->close(); reply->deleteLater(); return; } const QString loc = reply->rawHeader("Location"); const QString refresh = reply->rawHeader("refresh"); if (!loc.isEmpty()) { newRequest(reply, loc); } else if(!refresh.isEmpty() && refresh.contains("url=", Qt::CaseInsensitive)) { QStringList tmp = refresh.split("="); if(tmp.size() > 1) { newRequest(reply, tmp.last()); } } else { Server *s = servers.at(ui_.cb_servers->currentIndex()); QString page = reply->readAll(); // // //Код нужен для анализа html и нахождения ссылки на картинку // QFile f(QDir::home().absolutePath() + "/page.html"); // if(f.open(QIODevice::WriteOnly)) { // QTextStream out(&f); // out << page; // f.close(); // } // QRegExp rx(s->servRegexp()); ui_.urlFrame->setVisible(true); if (rx.indexIn(page) != -1) { QString imageurl = rx.cap(1); ui_.lb_url->setText(QString("%1").arg(imageurl)); history_.push_front(imageurl); if(history_.size() > MAX_HISTORY_SIZE) { history_.removeLast(); } settingsChanged(constHistory, history_); } else ui_.lb_url->setText(tr("Can't parse URL (Reply URL: %1)").arg(reply->url().toString())); updateWidgets(false); } reply->close(); reply->deleteLater(); } void Screenshot::newRequest(const QNetworkReply *const old, const QString &link) { if(!manager || !old || link.isEmpty()) return; QUrl netrequrl(link); if (netrequrl.host().isEmpty()) netrequrl = QUrl("http://" + QUrl::toAce(old->url().host()) + link); QNetworkRequest netreq(netrequrl); ui_.progressBar->setValue(0); QNetworkReply* reply = manager->get(netreq); connect(reply, SIGNAL(uploadProgress(qint64 , qint64)), this, SLOT(dataTransferProgress(qint64 , qint64))); } void Screenshot::closeEvent(QCloseEvent *e) { if(modified) { int ret = QMessageBox::question(this, tr("Close Screenshot"), tr("Are you sure?"), QMessageBox::Ok | QMessageBox::Cancel); if(ret == QMessageBox::Ok) { e->accept(); } else { e->ignore(); } } } void Screenshot::settingsChanged(const QString &option, const QVariant &value) { Options::instance()->setOption(option, value); } void Screenshot::doOptions() { OptionsDlg od(this); if(od.exec() == QDialog::Accepted) { refreshSettings(); } } void Screenshot::doHistory() { new HistoryDlg(history_, this); } //void Screenshot::doProxySettings() //{ // ProxySettingsDlg ps(this); // ps.setProxySettings(proxy_); // if(ps.exec() == QDialog::Accepted) { // setProxy(ps.getSettings()); // } //} void Screenshot::refreshSettings() { Options* o = Options::instance(); format = o->getOption(constFormat, format).toString(); fileNameFormat = o->getOption(constFileName, fileNameFormat).toString(); lastFolder = o->getOption(constLastFolder, lastFolder).toString(); setServersList(o->getOption(constServerList).toStringList()); } void Screenshot::saveGeometry() { Options* o = Options::instance(); o->setOption(constWindowState, QVariant(windowState() & Qt::WindowMaximized)); o->setOption(constWindowX, x()); o->setOption(constWindowY, y()); o->setOption(constWindowWidth, width()); o->setOption(constWindowHeight, height()); } bool Screenshot::eventFilter(QObject *o, QEvent *e) { if(o == ui_.lb_pixmap && e->type() == QEvent::MouseMove) { QMouseEvent *me = static_cast(e); if(me->buttons() == Qt::LeftButton) { QPoint pos = me->pos(); ui_.scrollArea->ensureVisible(pos.x(), pos.y(), 10, 10); } } return QMainWindow::eventFilter(o, e); } #include "screenshot.moc" plugins-1.5/generic/screenshotplugin/screenshot.h000066400000000000000000000053571336777360500224310ustar00rootroot00000000000000/* * screenshot.h - plugin * Copyright (C) 2009-2011 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef SCREENSHOT_H #define SCREENSHOT_H #include "ui_screenshot.h" #include "toolbar.h" #include "applicationinfoaccessinghost.h" class Server; class GrabAreaWidget; class ScreenshotOptions; class QNetworkAccessManager; class QNetworkReply; class Screenshot : public QMainWindow { Q_OBJECT public: Screenshot(); ~Screenshot(); void setProxy(const Proxy& p); void action(int action); protected: void closeEvent(QCloseEvent *); public slots: void shootScreen(); void openImage(); void newScreenshot(); private slots: void saveScreenshot(); void uploadScreenshot(); void printScreenshot(); void cancelUpload(); void dataTransferProgress( qint64 done, qint64 total ); void ftpReplyFinished(); void httpReplyFinished(QNetworkReply*); void captureDesktop(int); void captureWindow(int); void captureArea(int); void shootWindow(); void shootArea(); void screenshotCanceled(); void pixmapAdjusted(); void fixSizes(); void setModified(bool m); void aboutQt(); void doHomePage(); void doHistory(); void doOptions(); //void doProxySettings(); void settingsChanged(const QString& option, const QVariant& value); void copyUrl(); protected: bool eventFilter(QObject *o, QEvent *e); private: void updateScreenshotLabel(); void refreshWindow(); void uploadFtp(); void uploadHttp(); void bringToFront(); void updateWidgets(bool vis); void connectMenu(); void setServersList(const QStringList& servers); void setImagePath(const QString& path); void refreshSettings(); void saveGeometry(); void newRequest(const QNetworkReply *const old, const QString& link); void setupStatusBar(); void updateStatusBar(); bool modified; QPixmap originalPixmap; QString format; QString fileNameFormat; QString lastFolder; QList servers; QPointer manager; QByteArray ba; Proxy proxy_; QStringList history_; GrabAreaWidget* grabAreaWidget_; QLabel *sbLbSize; QPointer so_; Ui::Screenshot ui_; }; #endif plugins-1.5/generic/screenshotplugin/screenshot.ui000066400000000000000000000232631336777360500226130ustar00rootroot00000000000000 Screenshot 0 0 800 600 0 0 Screenshot true Qt::AlignCenter 0 0 780 402 0 0 0 0 0 0 0 0 QFrame::NoFrame QFrame::Plain 0 6 0 0 true Copy to clipboard Qt::Horizontal 40 20 Cancel uploading 24 Upload to server: Qt::ClickFocus Upload Screenshot to selected server Qt::ClickFocus Save Screenshot to Local Drive Qt::ClickFocus Print Screenshot Qt::Horizontal 0 0 Qt::ClickFocus Open image from Local Drive Qt::ClickFocus New Screenshot toolBar TopToolBarArea false true 0 0 800 25 File Settings Help Open Save Print New Screenshot Exit Proxy Settings Options History About Qt Home page Upload ToolBar QToolBar
toolbar.h
PixmapWidget QWidget
pixmapwidget.h
1
plugins-1.5/generic/screenshotplugin/screenshoticonset.cpp000066400000000000000000000030331336777360500243360ustar00rootroot00000000000000/* * iconset.cpp - plugin * Copyright (C) 2011 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "screenshoticonset.h" #include "iconfactoryaccessinghost.h" ScreenshotIconset* ScreenshotIconset::instance_ = 0; ScreenshotIconset* ScreenshotIconset::instance() { if(!instance_) { instance_ = new ScreenshotIconset(); } return instance_; } ScreenshotIconset::ScreenshotIconset() : QObject(0) , icoHost(0) { } ScreenshotIconset::~ScreenshotIconset() { } void ScreenshotIconset::reset() { delete instance_; instance_ = 0; } QIcon ScreenshotIconset::getIcon(const QString& name) { QIcon ico; if(icoHost) { ico = icoHost->getIcon(name); } if(ico.isNull()) ico = QIcon(":/screenshotplugin/" + name); return ico; } //for Psi plugin only void ScreenshotIconset::setIconHost(IconFactoryAccessingHost *_icoHost) { icoHost = _icoHost; } plugins-1.5/generic/screenshotplugin/screenshoticonset.h000066400000000000000000000025061336777360500240070ustar00rootroot00000000000000/* * iconset.h - plugin * Copyright (C) 2011 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef SCREENSHOTICONSET_H #define SCREENSHOTICONSET_H #include //for Psi plugin only class IconFactoryAccessingHost; class ScreenshotIconset : public QObject { Q_OBJECT public: static ScreenshotIconset* instance(); static void reset(); ~ScreenshotIconset(); QIcon getIcon(const QString& name); //for Psi plugin only void setIconHost(IconFactoryAccessingHost* _icoHost); private: ScreenshotIconset(); static ScreenshotIconset* instance_; //for Psi plugin only IconFactoryAccessingHost* icoHost; }; #endif // SCREENSHOTICONSET_H plugins-1.5/generic/screenshotplugin/screenshotoptions.cpp000066400000000000000000000037671336777360500244030ustar00rootroot00000000000000/* * screenshotoptions.cpp - plugin * Copyright (C) 2009-2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "screenshotoptions.h" #include "options.h" #include "defines.h" #include ScreenshotOptions::ScreenshotOptions(int delay, QWidget *parent) : QDialog(parent) { setAttribute(Qt::WA_DeleteOnClose); ui_.setupUi(this); ui_.sb_delay->setValue(delay); connect(ui_.buttonBox, SIGNAL(accepted()), SLOT(okPressed())); connect(ui_.buttonBox,SIGNAL(rejected()), SLOT(cancelPressed())); adjustSize(); setFixedSize(size()); } void ScreenshotOptions::okPressed() { hide(); QTimer::singleShot(500, this, SLOT(hideTimeout())); // чтобы при задержке 0сек это окно успело скрыться } void ScreenshotOptions::hideTimeout() { int delay = ui_.sb_delay->value(); Options::instance()->setOption(constDelay, delay); void(ScreenshotOptions::*signal)(int) = 0; if(ui_.rb_capture_desktop->isChecked()) signal = &ScreenshotOptions::captureDesktop; else if(ui_.rb_capture_window->isChecked()) signal = &ScreenshotOptions::captureWindow; else if(ui_.rb_capture_area->isChecked()) signal = &ScreenshotOptions::captureArea; if(signal) emit (this->*signal)(delay); deleteLater(); } void ScreenshotOptions::cancelPressed() { emit screenshotCanceled(); deleteLater(); } plugins-1.5/generic/screenshotplugin/screenshotoptions.h000066400000000000000000000024001336777360500240270ustar00rootroot00000000000000/* * screenshotoptions.h - plugin * Copyright (C) 2009-2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef SCREENSHOTOPTIONS_H #define SCREENSHOTOPTIONS_H #include "ui_screenshotoptions.h" class ScreenshotOptions : public QDialog { Q_OBJECT public: ScreenshotOptions(int delay, QWidget *parent = 0); signals: void captureDesktop(int); void captureWindow(int); void captureArea(int); void screenshotCanceled(); private slots: void okPressed(); void cancelPressed(); void hideTimeout(); private: Ui::ScreenshotOptions ui_; }; #endif // SCREENSHOTOPTIONS_H plugins-1.5/generic/screenshotplugin/screenshotoptions.ui000066400000000000000000000054041336777360500242240ustar00rootroot00000000000000 ScreenshotOptions Qt::WindowModal 0 0 256 173 0 0 New Screenshot Capture the desktop true Capture current window Select capture area Capture after seconds Qt::Horizontal 0 0 Qt::Horizontal 40 20 QDialogButtonBox::Cancel|QDialogButtonBox::Ok plugins-1.5/generic/screenshotplugin/screenshotplugin.cpp000066400000000000000000000152171336777360500241770ustar00rootroot00000000000000/* * screenshotplugin.cpp - plugin * Copyright (C) 2009-2011 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ class QAction; #include "psiplugin.h" #include "optionaccessor.h" #include "optionaccessinghost.h" #include "shortcutaccessor.h" #include "shortcutaccessinghost.h" #include "plugininfoprovider.h" #include "iconfactoryaccessinghost.h" #include "iconfactoryaccessor.h" #include "menuaccessor.h" #include "applicationinfoaccessinghost.h" #include "applicationinfoaccessor.h" #include "defines.h" #include "optionswidget.h" #include "options.h" #include "screenshoticonset.h" #include "controller.h" class ScreenshotPlugin : public QObject, public PsiPlugin, public OptionAccessor, public ShortcutAccessor, public PluginInfoProvider, public IconFactoryAccessor, public MenuAccessor, public ApplicationInfoAccessor { Q_OBJECT #ifdef HAVE_QT5 Q_PLUGIN_METADATA(IID "com.psi-plus.ScreenshotPlugin") #endif Q_INTERFACES(PsiPlugin OptionAccessor ShortcutAccessor PluginInfoProvider IconFactoryAccessor MenuAccessor ApplicationInfoAccessor) public: ScreenshotPlugin(); virtual QString name() const; virtual QString shortName() const; virtual QString version() const; virtual QWidget* options(); virtual bool enable(); virtual bool disable(); virtual void setOptionAccessingHost(OptionAccessingHost* host); virtual void optionChanged(const QString& /*option*/) { }; virtual void setShortcutAccessingHost(ShortcutAccessingHost* host); virtual void setIconFactoryAccessingHost(IconFactoryAccessingHost* host); virtual void setApplicationInfoAccessingHost(ApplicationInfoAccessingHost* host); virtual QList < QVariantHash > getAccountMenuParam(); virtual QList < QVariantHash > getContactMenuParam(); virtual QAction* getContactAction(QObject* , int , const QString& ) { return 0; }; virtual QAction* getAccountAction(QObject* , int ) { return 0; }; virtual void setShortcuts(); virtual void applyOptions(); virtual void restoreOptions(); virtual QString pluginInfo(); virtual QPixmap icon() const; private slots: void openImage(); private: void disconnectShortcut(); private: bool enabled_; OptionAccessingHost* psiOptions; ShortcutAccessingHost* psiShortcuts; IconFactoryAccessingHost* icoHost; ApplicationInfoAccessingHost* appInfo; QPointer optionsWid; Controller* controller_; }; #ifndef HAVE_QT5 Q_EXPORT_PLUGIN(ScreenshotPlugin); #endif ScreenshotPlugin::ScreenshotPlugin() : enabled_(false) , psiOptions(0) , psiShortcuts(0) , icoHost(0) , appInfo(0) , controller_(0) { } QString ScreenshotPlugin::name() const { return constName; } QString ScreenshotPlugin::shortName() const { return "Screenshot"; } QString ScreenshotPlugin::version() const { return cVersion; } QWidget* ScreenshotPlugin::options() { if (!enabled_) { return 0; } optionsWid = new OptionsWidget(); restoreOptions(); return optionsWid; } bool ScreenshotPlugin::enable() { QFile file(":/screenshotplugin/screenshot"); file.open(QIODevice::ReadOnly); QByteArray image = file.readAll(); icoHost->addIcon("screenshotplugin/screenshot",image); file.close(); Options::instance()->setPsiOptions(psiOptions); ScreenshotIconset::instance()->setIconHost(icoHost); controller_ = new Controller(appInfo); appInfo->getProxyFor(constName); //init proxy settings enabled_ = true; return enabled_; } bool ScreenshotPlugin::disable() { disconnectShortcut(); delete controller_; controller_ = 0; enabled_ = false; return true; } void ScreenshotPlugin::setOptionAccessingHost(OptionAccessingHost* host) { psiOptions = host; } void ScreenshotPlugin::setShortcutAccessingHost(ShortcutAccessingHost* host) { psiShortcuts = host; } void ScreenshotPlugin::setIconFactoryAccessingHost(IconFactoryAccessingHost* host) { icoHost = host; } void ScreenshotPlugin::setApplicationInfoAccessingHost(ApplicationInfoAccessingHost *host) { appInfo = host; } void ScreenshotPlugin::setShortcuts() { const QString shortCut = psiOptions->getPluginOption(constShortCut).toString(); psiShortcuts->connectShortcut(QKeySequence(shortCut), controller_, SLOT(onShortCutActivated())); } void ScreenshotPlugin::disconnectShortcut() { const QString shortCut = psiOptions->getPluginOption(constShortCut).toString(); psiShortcuts->disconnectShortcut(QKeySequence(shortCut), controller_, SLOT(onShortCutActivated())); } QList < QVariantHash > ScreenshotPlugin::getAccountMenuParam() { QVariantHash hash; hash["icon"] = QVariant(QString("screenshotplugin/screenshot")); hash["name"] = QVariant(tr("Upload Image")); hash["reciver"] = qVariantFromValue(qobject_cast(this)); hash["slot"] = QVariant(SLOT(openImage())); QList< QVariantHash > l; l.push_back(hash); return l; } QList < QVariantHash > ScreenshotPlugin::getContactMenuParam() { return QList < QVariantHash >(); } void ScreenshotPlugin::openImage() { if(!enabled_) return; controller_->openImage(); } void ScreenshotPlugin::applyOptions() { optionsWid->applyOptions(); disconnectShortcut(); setShortcuts(); } void ScreenshotPlugin::restoreOptions() { optionsWid->restoreOptions(); } QString ScreenshotPlugin::pluginInfo() { return tr("Authors: ") + "C.H., Dealer_WeARE\n\n" + trUtf8("This plugin allows you to make screenshots and save them to your hard drive or upload them to an FTP or HTTP server.\n" "The plugin has the following settings:\n" "* Shortcut -- hotkey to make the screenshot (by default, Ctrl+Alt+P)\n" "* Format -- the file format in which the screenshot will be stored (default: .jpg)\n" "* File Name -- format of the filename (default: pic-yyyyMMdd-hhmmss, where yyyyMMdd=YYYYMMDD, and hhmmss are current date in the format yearmonthday-hourminutesecond)\n" "The address of FTP server is specified as ftp://ftp.domain.tld/path1/path2") + tr("\n\nSettings for authorization on some hostings can be found here: http://code.google.com/p/qscreenshot/wiki/Authorization"); } QPixmap ScreenshotPlugin::icon() const { return QPixmap(":/screenshotplugin/screenshot"); } #include "screenshotplugin.moc" plugins-1.5/generic/screenshotplugin/screenshotplugin.pro000066400000000000000000000027741336777360500242210ustar00rootroot00000000000000isEmpty(PSISDK) { include(../../psiplugin.pri) } else { include($$PSISDK/plugins/psiplugin.pri) } QT += network greaterThan(QT_MAJOR_VERSION, 4) { QT += printsupport unix:!macx:{ QT += x11extras } } DEPENDPATH += . qxt/core qxt/gui INCLUDEPATH += . qxt/gui qxt/core MOC_DIR = tmp/ OBJECTS_DIR = tmp/ HEADERS = screenshot.h \ server.h \ editserverdlg.h \ screenshotoptions.h \ toolbar.h \ pixmapwidget.h \ options.h \ optionsdlg.h \ optionswidget.h \ screenshoticonset.h \ controller.h \ defines.h \ proxysettingsdlg.h SOURCES = screenshotplugin.cpp \ screenshot.cpp \ server.cpp \ editserverdlg.cpp \ screenshotoptions.cpp \ toolbar.cpp \ pixmapwidget.cpp \ options.cpp \ optionsdlg.cpp \ optionswidget.cpp \ screenshoticonset.cpp \ controller.cpp \ proxysettingsdlg.cpp FORMS += optionswidget.ui \ editserverdlg.ui \ screenshot.ui \ screenshotoptions.ui \ optionsdlg.ui \ proxysettingsdlg.ui RESOURCES += screenshotplugin.qrc #QXT HEADERS += qxt/core/qxtglobal.h \ qxt/gui/qxtwindowsystem.h SOURCES += qxt/core/qxtglobal.cpp \ qxt/gui/qxtwindowsystem.cpp unix:!macx { CONFIG += X11 SOURCES += qxt/gui/qxtwindowsystem_x11.cpp HEADERS += qxt/gui/x11info.h } macx { SOURCES += qxt/gui/qxtwindowsystem_mac.cpp HEADERS += qxt/gui/qxtwindowsystem_mac.h QMAKE_LFLAGS += -framework Carbon -framework CoreFoundation } win32 { SOURCES += qxt/gui/qxtwindowsystem_win.cpp LIBS += -lUser32 } plugins-1.5/generic/screenshotplugin/screenshotplugin.qrc000066400000000000000000000010721336777360500241740ustar00rootroot00000000000000 icons/screenshot.png icons/crop.png icons/draw.png icons/frame.png icons/palette.png icons/print.png icons/undo.png icons/copy.png icons/paste.png plugins-1.5/generic/screenshotplugin/server.cpp000066400000000000000000000053241336777360500221070ustar00rootroot00000000000000/* * server.cpp - plugin * Copyright (C) 2009-2011 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "server.h" Server::Server(QListWidget *parent) : QListWidgetItem(parent) , displayName_("server") , url_("") , userName_("") , password_("") , servPostdata_("") , servFileinput_("") , servRegexp_("") { } void Server::setDisplayName(QString n) { displayName_ = n; } void Server::setServerData(const QString& post, const QString& fInput, const QString& reg/*, QString fFilter*/) { servPostdata_ = post; servFileinput_ = fInput; servRegexp_ = reg; //servFilefilter_ = fFilter; } void Server::setServer(const QString& url, const QString& user, const QString& pass) { url_ = url; userName_ = user; password_ = pass; } QString Server::settingsToString() const { QStringList l = QStringList() << displayName_ << url_ << userName_ << password_; l << servPostdata_ << servFileinput_ << servRegexp_/* << servFilefilter_*/; l << (useProxy_ ? "true" : "false"); return l.join(splitString()); } void Server::setFromString(const QString& settings) { QStringList l = settings.split(splitString()); if(l.size() == 11) { processOltSettingsString(l); return; } if(!l.isEmpty()) displayName_ = l.takeFirst(); if(!l.isEmpty()) url_ = l.takeFirst(); if(!l.isEmpty()) userName_ = l.takeFirst(); if(!l.isEmpty()) password_ = l.takeFirst(); if(!l.isEmpty()) servPostdata_ = l.takeFirst(); if(!l.isEmpty()) servFileinput_ = l.takeFirst(); if(!l.isEmpty()) servRegexp_ = l.takeFirst(); /*if(!l.isEmpty()) servFilefilter_ = l.takeFirst();*/ if(!l.isEmpty()) useProxy_ = (l.takeFirst() == "true"); } void Server::processOltSettingsString(QStringList l) { displayName_ = l.takeFirst(); url_ = l.takeFirst(); userName_ = l.takeFirst(); password_ = l.takeFirst(); //remove old useless proxy settings l.takeFirst(); l.takeFirst(); l.takeFirst(); l.takeFirst(); servPostdata_ = l.takeFirst(); servFileinput_ = l.takeFirst(); servRegexp_ = l.takeFirst(); } QString Server::splitString() { return QString("&split&"); } plugins-1.5/generic/screenshotplugin/server.h000066400000000000000000000040241336777360500215500ustar00rootroot00000000000000/* * server.h - plugin * Copyright (C) 2009-2011 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef SERVER_H #define SERVER_H #include class Server : public QListWidgetItem, public QObject { public: Server(QListWidget *parent = 0); QString displayName() const { return displayName_; }; QString url() const { return url_; }; QString userName() const { return userName_; }; QString password() const { return password_; }; QString servPostdata() const { return servPostdata_; }; QString servFileinput() const { return servFileinput_; }; QString servRegexp() const { return servRegexp_; }; //QString servFilefilter() { return servFilefilter_; }; void setServer(const QString& url, const QString& user = "", const QString& pass = ""); void setServerData(const QString& post = "", const QString& fInput = "", const QString& reg = ""/*, QString fFilter = ""*/); void setDisplayName(QString n); void setUseProxy(bool use) { useProxy_ = use; }; bool useProxy() const { return useProxy_; }; QString settingsToString() const ; void setFromString(const QString& settings); static QString splitString(); private: QString displayName_; QString url_, userName_, password_; QString servPostdata_, servFileinput_, servRegexp_/*, servFilefilter_*/; bool useProxy_; void processOltSettingsString(QStringList l); }; #endif // SERVER_H plugins-1.5/generic/screenshotplugin/toolbar.cpp000066400000000000000000000110701336777360500222360ustar00rootroot00000000000000/* * toolbar.cpp - plugin * Copyright (C) 2009-2011 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include #include #include #include "toolbar.h" #include "screenshoticonset.h" class Button : public QAction { Q_OBJECT public: Button(const QString &tip, const QIcon &ico, ToolBar::ButtonType type, bool checkable, QWidget *parent) : QAction(parent) , type_(type) { setToolTip(tip); setIcon(ico); setCheckable(checkable); } ToolBar::ButtonType type() const { return type_; } private: ToolBar::ButtonType type_; }; //----------------ToolBar-------------------------------- ToolBar::ToolBar(QWidget *parent) : QToolBar(parent) { init(); } ToolBar::~ToolBar() { foreach(Button *b, buttons_) { delete(b); } buttons_.clear(); } void ToolBar::init() { ScreenshotIconset* icoHost = ScreenshotIconset::instance(); addWidget(new QLabel(tr("Line Width:"))); sb = new QSpinBox(this); sb->setMinimum(1); setLineWidth(2); sb->setToolTip(tr("Line width")); addWidget(sb); connect(sb,SIGNAL(valueChanged(int)), this, SIGNAL(newWidth(int))); QPixmap pix(16,16); pix.fill(QColor(Qt::black)); QIcon ico(pix); buttons_.append(new Button(tr("Select Color"), ico, ToolBar::ButtonColor, false,this) ); buttons_.append(new Button(tr("Pen"), icoHost->getIcon("psi/draw"), ToolBar::ButtonPen, true,this) ); buttons_.append(new Button(tr("Select"), icoHost->getIcon("psi/frame"), ToolBar::ButtonSelect, true,this) ); buttons_.append(new Button(tr("Cut"), icoHost->getIcon("psi/crop"), ToolBar::ButtonCut, false,this) ); buttons_.last()->setShortcut(QKeySequence("Ctrl+x")); buttons_.append(new Button(tr("Copy"), icoHost->getIcon("psi/copy"), ToolBar::ButtonCopy, false,this) ); buttons_.last()->setShortcut(QKeySequence("Ctrl+c")); buttons_.append(new Button(tr("Paste"), icoHost->getIcon("psi/paste"), ToolBar::ButtonInsert, false,this) ); buttons_.last()->setShortcut(QKeySequence("Ctrl+v")); buttons_.append(new Button(tr("Rotate"), icoHost->getIcon("psi/rotate"), ToolBar::ButtonRotate, false,this) ); buttons_.append(new Button(tr("Insert Text"), icoHost->getIcon("psi/text"), ToolBar::ButtonText, true,this) ); buttons_.append(new Button(tr("Undo"), icoHost->getIcon("psi/undo"), ToolBar::ButtonUndo, false,this) ); buttons_.last()->setShortcut(QKeySequence("Ctrl+z")); foreach(Button *b, buttons_) { addAction(b); connect(b, SIGNAL(triggered(bool)), SLOT(buttonChecked(bool))); connect(b, SIGNAL(triggered()), SLOT(buttonClicked())); } enableButton(false, ToolBar::ButtonUndo); } void ToolBar::enableButton(bool enable, ToolBar::ButtonType type) { foreach(Button *b, buttons_) { if(b->type() == type) { b->setEnabled(enable); break; } } } void ToolBar::checkButton(ToolBar::ButtonType type) { foreach(Button *b, buttons_) { if(b->type() == type && b->isCheckable()) { b->setChecked(true); break; } } emit checkedButtonChanged(type); } void ToolBar::buttonChecked(bool check) { Button *s = (Button*)sender(); if(!s->isCheckable()) { return; } if(s->type() == ButtonSelect && check) { enableButton(true, ButtonCut); } else { enableButton(false, ButtonCut); } if(check) { foreach(Button *b, buttons_) { if(b != s) b->setChecked(false); } emit checkedButtonChanged(s->type()); } else emit checkedButtonChanged(ToolBar::ButtonNoButton); } void ToolBar::setColorForColorButton(const QColor &color) { foreach(Button *b, buttons_) { if(b->type() == ButtonColor) { QPixmap pix(16,16); pix.fill(color); b->setIcon(QIcon(pix)); break; } } } void ToolBar::buttonClicked() { Button *s = (Button*)sender(); if(s) emit buttonClicked(s->type()); } ToolBar::ButtonType ToolBar::currentButton() const { foreach(Button *b, buttons_) { if(b->isChecked()) return b->type(); } return ToolBar::ButtonNoButton; } void ToolBar::setLineWidth(int width) { sb->setValue(width); } #include "toolbar.moc" plugins-1.5/generic/screenshotplugin/toolbar.h000066400000000000000000000032101336777360500217000ustar00rootroot00000000000000/* * toolbar.h - plugin * Copyright (C) 2009-2011 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef TOOLBAR_H #define TOOLBAR_H #include class QToolBar; class Button; class QSpinBox; class ToolBar : public QToolBar { Q_OBJECT public: enum ButtonType { ButtonSelect, ButtonPen, ButtonCut, ButtonText, ButtonColor, ButtonUndo, ButtonRotate, ButtonCopy, ButtonInsert, ButtonNoButton }; ToolBar(QWidget *parent); ~ToolBar(); void init(); ToolBar::ButtonType currentButton() const; void checkButton(ToolBar::ButtonType); void enableButton(bool enable, ToolBar::ButtonType type); void setColorForColorButton(const QColor &color); void setLineWidth(int width); private slots: void buttonChecked(bool); void buttonClicked(); signals: void buttonClicked(ToolBar::ButtonType); void checkedButtonChanged(ToolBar::ButtonType); void newWidth(int); private: QList buttons_; QSpinBox *sb; }; #endif // TOOLBAR_H plugins-1.5/generic/skinsplugin/000077500000000000000000000000001336777360500170435ustar00rootroot00000000000000plugins-1.5/generic/skinsplugin/CMakeLists.txt000066400000000000000000000026361336777360500216120ustar00rootroot00000000000000unset(_HDRS) unset(_UIS) unset(_SRCS) unset(_RSCS) unset(PLUGIN) set( PLUGIN skinsplugin ) project(${PLUGIN}) cmake_minimum_required(VERSION 3.1.0) set( CMAKE_AUTOMOC TRUE ) IF( NOT WIN32 ) set( LIB_SUFFIX "" CACHE STRING "Define suffix of directory name (32/64)" ) set( PLUGINS_PATH "lib${LIB_SUFFIX}/psi-plus/plugins" CACHE STRING "Install suffix for plugins" ) ELSE() set( PLUGINS_PATH "psi-plus/plugins" CACHE STRING "Install suffix for plugins" ) ENDIF() add_definitions( -DQT_PLUGIN -DHAVE_QT5 ) include_directories( ${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ../../include . ) set( _HDRS skin.h optionsparser.h ) set( _SRCS ${PLUGIN}.cpp skin.cpp optionsparser.cpp ) set( _UIS ${PLUGIN}.ui previewer.ui getskinname.ui ) set( _RSCS ${PLUGIN}.qrc ) find_package( Qt5 COMPONENTS Widgets Xml REQUIRED ) set(QT_DEPLIBS Qt5::Widgets Qt5::Xml ) qt5_wrap_ui(UIS ${_UIS}) qt5_add_resources(RSCS ${_RSCS}) add_library( ${PLUGIN} MODULE ${_SRCS} ${UIS} ${RSCS} ) target_link_libraries( ${PLUGIN} ${QT_DEPLIBS} ) if( UNIX AND NOT( APPLE OR CYGWIN ) ) install( TARGETS ${PLUGIN} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} ) endif() if( WIN32 ) install( TARGETS ${PLUGIN} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} ) endif() plugins-1.5/generic/skinsplugin/changelog.txt000066400000000000000000000135571336777360500215460ustar00rootroot000000000000002013-08-13 v0.3.3 - taurus + Иконка плагина 2011-06-11 v0.3.2 * изменён набор сохраняемых опций 2011-05-27 v0.3.1 * пересобрано с новым appHomeDir 2010-12-17 v0.3.0 * небольшие исправления 2010-11-20 v0.2.9 * расширен набор сохраняемых опций 2010-10-12 v0.2.8 * расширен набор сохраняемых опций 2010-09-11 v0.2.7 * обновлена ссылка на wiki ( http://psi-plus.com/wiki/plugins#skins_plugin ) 2010-07-04 v0.2.6 * расширен набор сохраняемых опций 2010-06-26 v0.2.5 * расширен набор сохраняемых опций 2010-06-21 v0.2.4 * расширен набор сохраняемых опций 2010-06-05 v0.2.3 * расширен набор сохраняемых опций 2010-05-18 v0.2.2 * исправлено падение приложения при выходе 2010-05-17 v0.2.1 + добавлена информация о плагине * исправлено падение приложения при отключении плагина 2010-05-07 v0.2.0 + добавлена возможность преобразования путей 2010-05-04 v0.1.2 * исправлена ссылка на wiki 2010-04-28 v0.1.1 * расширен набор сохраняемых опций - удалена ошибочная всплывающая подсказка в опциях 2010-04-27 v0.1.0 * при применении резервного скина не создается новый резервный скин 2010-04-05 v0.0.9 * расширен набор сохраняемых опций 2010-03-24 v0.0.8 * исправлена перезапись скина 2010-03-23 v0.0.7 * исправлено добавление скина в список скинов при перезаписи существующего скина во время создания нового скина + добавлена возможность перезаписать выбранный скин текущими значениями 2010-03-22 v0.0.6 * исправлено дублирование скинов в списке * более умный поиск скинов по папке ресурсов и домашней папке * исправлено двухкратное появление сообщение о битом скине при попытке предпросмотра * увеличен размер списка скинов + активация основной кнопки "Применить" в окне настроек после применения скина + при обновлении списка скинов не пропадают скины, открытые вручную + по нажатии кнопки Create в поля подставляются значения от выбранного в списке скина + в окне предпросмотра скина добавлена кнопка "Применить" + резервные скины сохраняются в папку skins + добавлена возможность удалить выбранный скин (удаляется только файл скина) + после создания скин попадает в список скинов автоматически + добавлена возможность отключить создание резервных скинов при применении нового скина 2010-03-18 v0.0.5 * изменено определение настроек интерфейса (добавлены в разрешённые настройки иконсэтов) 2010-03-18 v0.0.4 + при сохранении скина по-умолчанию предлагается имя файла, состоящее из имени скина и версии + предпросмотр скина при двойном щелчке на его имени * исправлен предпросмотр скина * имя файла изображения для предпросмотра должно быть таким же, как и имя скина + в окне уведомления об успешном применении скина добавлено сообщение о необходимоти перезагрузки приложения + сохраняются и применяются только настройки, имеющие непосредственное отношение к интерфейсу 2010-03-17 v0.0.3 + при применении нового скина создается бэкап-скин изменяемых настроек * в сохраняемые опции добавлены настройки тулбаров 2010-03-17 v0.0.2 + добавлена возможность работать с различными типами опций * расширен набор сохраняемых опций 2010-03-16 v0.0.1 ! initial version Данный плагин предназначен для создания и применения скинов для Psi+ Скин - это набор настроек. В данный момент в скине сохраняются только настройки цветов. Чтобы загрузить новый скин - создайте в каталоге PsiData папку skins, и расположите там скины. Либо можно открыть файл скина из любого места самостоятельно. Каждый скин должен лежать в отдельной папке. Рядом с файлом скина можно расположить скриншот. plugins-1.5/generic/skinsplugin/defskin.skn000066400000000000000000000140461336777360500212100ustar00rootroot00000000000000 plugins-1.5/generic/skinsplugin/getskinname.ui000066400000000000000000000060741336777360500217160ustar00rootroot00000000000000 GetSkinName Qt::WindowModal 0 0 231 146 0 0 Get Skin Name 0 0 Name: Author: Version: Qt::Horizontal 0 20 OK Cancel Qt::Horizontal 0 20 le_name le_author le_version pb_ok pb_cancel plugins-1.5/generic/skinsplugin/optionsparser.cpp000066400000000000000000000276711336777360500224740ustar00rootroot00000000000000/* * optionsparser.cpp - plugin * Copyright (C) 2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "optionsparser.h" #include #include #include #include OptionsParser::OptionsParser(QObject *parent) :QObject(parent) { } OptionsParser* OptionsParser::instance() { if(!instance_) instance_ = new OptionsParser(); return instance_; } //stolen from varianttree.cpp void OptionsParser::variantToElement(const QVariant& var, QDomElement& e) { QString type = var.typeName(); if (type == "QVariantList") { foreach(QVariant v, var.toList()) { QDomElement item_element = e.ownerDocument().createElement("item"); variantToElement(v,item_element); e.appendChild(item_element); } } else if (type == "QStringList") { foreach(QString s, var.toStringList()) { QDomElement item_element = e.ownerDocument().createElement("item"); QDomText text = e.ownerDocument().createTextNode(s); item_element.appendChild(text); e.appendChild(item_element); } } else if (type == "QSize") { QSize size = var.toSize(); QDomElement width_element = e.ownerDocument().createElement("width"); width_element.appendChild(e.ownerDocument().createTextNode(QString::number(size.width()))); e.appendChild(width_element); QDomElement height_element = e.ownerDocument().createElement("height"); height_element.appendChild(e.ownerDocument().createTextNode(QString::number(size.height()))); e.appendChild(height_element); } else if (type == "QRect") { QRect rect = var.toRect(); QDomElement x_element = e.ownerDocument().createElement("x"); x_element.appendChild(e.ownerDocument().createTextNode(QString::number(rect.x()))); e.appendChild(x_element); QDomElement y_element = e.ownerDocument().createElement("y"); y_element.appendChild(e.ownerDocument().createTextNode(QString::number(rect.y()))); e.appendChild(y_element); QDomElement width_element = e.ownerDocument().createElement("width"); width_element.appendChild(e.ownerDocument().createTextNode(QString::number(rect.width()))); e.appendChild(width_element); QDomElement height_element = e.ownerDocument().createElement("height"); height_element.appendChild(e.ownerDocument().createTextNode(QString::number(rect.height()))); e.appendChild(height_element); } else if (type == "QByteArray") { QDomText text = e.ownerDocument().createTextNode(Base64::encode(var.toByteArray())); e.appendChild(text); } else if (type == "QKeySequence") { QKeySequence k = var.value(); QDomText text = e.ownerDocument().createTextNode(k.toString()); e.appendChild(text); } else { QDomText text = e.ownerDocument().createTextNode(var.toString()); e.appendChild(text); } e.setAttribute("type",type); } QVariant OptionsParser::elementToVariant(const QDomElement& e) { QVariant value; QString type = e.attribute("type"); if (type == "QStringList") { QStringList list; for (QDomNode node = e.firstChild(); !node.isNull(); node = node.nextSibling()) { QDomElement e = node.toElement(); if (!e.isNull() && e.tagName() == "item") { list += e.text(); } } value = list; } else if (type == "QVariantList") { QVariantList list; for (QDomNode node = e.firstChild(); !node.isNull(); node = node.nextSibling()) { QDomElement e = node.toElement(); if (!e.isNull() && e.tagName() == "item") { QVariant v = elementToVariant(e); if (v.isValid()) list.append(v); } } value = list; } else if (type == "QSize") { int width = 0, height = 0; for (QDomNode node = e.firstChild(); !node.isNull(); node = node.nextSibling()) { QDomElement e = node.toElement(); if (!e.isNull()) { if (e.tagName() == "width") { width = e.text().toInt(); } else if (e.tagName() == "height") { height = e.text().toInt(); } } } value = QVariant(QSize(width,height)); } else if (type == "QRect") { int x = 0, y = 0, width = 0, height = 0; for (QDomNode node = e.firstChild(); !node.isNull(); node = node.nextSibling()) { QDomElement e = node.toElement(); if (!e.isNull()) { if (e.tagName() == "width") { width = e.text().toInt(); } else if (e.tagName() == "height") { height = e.text().toInt(); } else if (e.tagName() == "x") { x = e.text().toInt(); } else if (e.tagName() == "y") { y = e.text().toInt(); } } } value = QVariant(QRect(x,y,width,height)); } else if (type == "QByteArray") { value = QByteArray(); for (QDomNode node = e.firstChild(); !node.isNull(); node = node.nextSibling()) { if (node.isText()) { value = Base64::decode(node.toText().data()); break; } } } else { // Standard values QVariant::Type varianttype; bool known = true; if (type=="QString") { varianttype = QVariant::String; } else if (type=="bool") { varianttype = QVariant::Bool; } else if (type=="int") { varianttype = QVariant::Int; } else if (type == "QKeySequence") { varianttype = QVariant::KeySequence; } else if (type == "QColor") { varianttype = QVariant::Color; } else { known = false; } if (known) { for (QDomNode node = e.firstChild(); !node.isNull(); node = node.nextSibling()) { if ( node.isText() ) value=node.toText().data(); } if (!value.isValid()) value = QString(""); value.convert(varianttype); } else { value = QVariant(); } } return value; } OptionsParser *OptionsParser::instance_ = NULL; //----------------------- //---------Base64-------- //----------------------- QString Base64::encode(const QByteArray &s) { int i; int len = s.size(); char tbl[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; int a, b, c; QByteArray p; p.resize((len+2)/3*4); int at = 0; for( i = 0; i < len; i += 3 ) { a = ((unsigned char)s[i] & 3) << 4; if(i + 1 < len) { a += (unsigned char)s[i + 1] >> 4; b = ((unsigned char)s[i + 1] & 0xF) << 2; if(i + 2 < len) { b += (unsigned char)s[i + 2] >> 6; c = (unsigned char)s[i + 2] & 0x3F; } else c = 64; } else { b = c = 64; } p[at++] = tbl[(unsigned char)s[i] >> 2]; p[at++] = tbl[a]; p[at++] = tbl[b]; p[at++] = tbl[c]; } return QString::fromLatin1(p); } QByteArray Base64::decode(const QString& input) { QByteArray s(QString(input).remove('\n').toUtf8()); QByteArray p; // -1 specifies invalid // 64 specifies eof // everything else specifies data signed char tbl[] = { -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63, 52,53,54,55,56,57,58,59,60,61,-1,-1,-1,64,-1,-1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14, 15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1, -1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40, 41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, }; // this should be a multiple of 4 int len = s.size(); if(len % 4) { return p; } p.resize(len / 4 * 3); int i; int at = 0; int a, b, c, d; c = d = 0; for( i = 0; i < len; i += 4 ) { a = tbl[(int)s[i]]; b = tbl[(int)s[i + 1]]; c = tbl[(int)s[i + 2]]; d = tbl[(int)s[i + 3]]; if((a == 64 || b == 64) || (a < 0 || b < 0 || c < 0 || d < 0)) { p.resize(0); return p; } p[at++] = ((a & 0x3F) << 2) | ((b >> 4) & 0x03); p[at++] = ((b & 0x0F) << 4) | ((c >> 2) & 0x0F); p[at++] = ((c & 0x03) << 6) | ((d >> 0) & 0x3F); } if(c & 64) p.resize(at - 2); else if(d & 64) p.resize(at - 1); return p; } plugins-1.5/generic/skinsplugin/optionsparser.h000066400000000000000000000027201336777360500221250ustar00rootroot00000000000000/* * optionsparser.h - plugin * Copyright (C) 2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef OPTIONSPARSER_H #define OPTIONSPARSER_H #include #include #include class OptionsParser : public QObject { Q_OBJECT public: OptionsParser(QObject* parent = 0); static OptionsParser* instance(); QVariant elementToVariant(const QDomElement& e); void variantToElement(const QVariant& var, QDomElement& e); private: static OptionsParser *instance_; }; //stolen from iris class Base64 { public: static QString encode(const QByteArray&); static QByteArray decode(const QString &s); }; #endif // OPTIONSPARSER_H plugins-1.5/generic/skinsplugin/previewer.ui000066400000000000000000000072731336777360500214230ustar00rootroot00000000000000 Previewer 0 0 441 385 Preview Skin 0 0 Preview unavailable Qt::AlignCenter Name: Author: Version: Qt::Vertical 20 40 Apply Qt::Horizontal 0 10 Close Qt::Horizontal 0 10 plugins-1.5/generic/skinsplugin/skin.cpp000066400000000000000000000071471336777360500205240ustar00rootroot00000000000000/* * skin.cpp - plugin * Copyright (C) 2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "skin.h" #include #include #include void Skin::setFile(QString file) { filePass_ = file; } QString Skin::filePass() { return filePass_; } QString Skin::skinFolder() { QString folder = filePass_; int index = folder.lastIndexOf("/"); folder.chop(folder.size() - index); return folder; } QPixmap Skin::previewPixmap() { QDir dir(skinFolder()); QString skinName = name(); QPixmap pix = QPixmap(); foreach(QString fileName, dir.entryList(QDir::Files)) { if((fileName.endsWith(".png", Qt::CaseInsensitive) || fileName.endsWith(".jpg", Qt::CaseInsensitive)) && skinName.left(skinName.length()-4) == fileName.left(fileName.length()-4)) { pix = QPixmap(dir.absolutePath() + "/" + fileName); break; } } return pix; } QString Skin::name() { QString name = filePass_; int index = name.lastIndexOf("/"); index = name.size() - index - 1; name = name.right(index); return name; } //--------------------------------- //---Previewer--------------------- //--------------------------------- Previewer::Previewer(Skin *skin, QWidget *parent) : QDialog(parent) , skin_(skin) { setAttribute(Qt::WA_DeleteOnClose); setModal(true); ui_.setupUi(this); connect(ui_.pb_close, SIGNAL(released()), this, SLOT(close())); connect(ui_.pb_apply, SIGNAL(released()), this, SIGNAL(applySkin())); } bool Previewer::loadSkinInformation() { QFile file(skin_->filePass()); QDomDocument doc; if(!doc.setContent(&file)) { QMessageBox::warning(this, tr("Preview Skin"), tr("Skin is not valid!")); return false; } QDomElement elem = doc.documentElement(); if(elem.tagName() != "skin") { QMessageBox::warning(this, tr("Preview Skin"), tr("Skin is not valid!")); return false; } ui_.lbl_author->setText( elem.attribute("author") ); ui_.lbl_version->setText( elem.attribute("version") ); ui_.lbl_name->setText( elem.attribute("name") ); QPixmap pix = skin_->previewPixmap(); if(!pix.isNull()) ui_.lbl_preview->setPixmap(pix); return true; } //----------------------------- //------GetSkinName------------ //----------------------------- GetSkinName::GetSkinName(QString name, QString author, QString version, QWidget *parent) :QDialog(parent) { setAttribute(Qt::WA_DeleteOnClose); setModal(true); ui_.setupUi(this); connect(ui_.pb_cancel, SIGNAL(released()), this, SLOT(close())); connect(ui_.pb_ok, SIGNAL(released()), this, SLOT(okPressed())); ui_.le_name->setText(name); ui_.le_author->setText(author); ui_.le_version->setText(version); } void GetSkinName::okPressed() { emit ok(ui_.le_name->text(), ui_.le_author->text(), ui_.le_version->text()); close(); } plugins-1.5/generic/skinsplugin/skin.h000066400000000000000000000034461336777360500201670ustar00rootroot00000000000000/* * skin.h - plugin * Copyright (C) 2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef SKIN_H #define SKIN_H #include #include "ui_previewer.h" #include "ui_getskinname.h" class Skin : public QListWidgetItem { public: Skin(QListWidget* parent) : QListWidgetItem(parent) {}; ~Skin() {}; void setFile(QString file); QString filePass(); QString name(); QString skinFolder(); QPixmap previewPixmap(); private: QString filePass_; }; class Previewer : public QDialog { Q_OBJECT public: Previewer(Skin *skin, QWidget *parent = 0); bool loadSkinInformation(); private: Ui::Previewer ui_; Skin *skin_; signals: void applySkin(); }; class GetSkinName : public QDialog { Q_OBJECT public: GetSkinName(QString name, QString author, QString version, QWidget *parent = 0); private slots: void okPressed(); signals: void ok(QString, QString, QString); private: Ui::GetSkinName ui_; }; #endif // SKIN_H plugins-1.5/generic/skinsplugin/skins.png000066400000000000000000000031571336777360500207060ustar00rootroot00000000000000PNG  IHDRaiCCPICC ProfilexTkA6n"Zkx"IYhE6bk Ed3In6&*Ezd/JZE(ޫ(b-nL~7}ov r4 Ril|Bj A4%UN$As{z[V{wwҶ@G*q Y<ߡ)t9Nyx+=Y"|@5-MS%@H8qR>׋infObN~N>! ?F?aĆ=5`5_M'Tq. VJp8dasZHOLn}&wVQygE0  HPEaP@<14r?#{2u$jtbDA{6=Q<("qCA*Oy\V;噹sM^|vWGyz?W15s-_̗)UKuZ17ߟl;=..s7VgjHUO^gc)1&v!.K `m)m$``/]?[xF QT*d4o(/lșmSqens}nk~8X<R5 vz)Ӗ9R,bRPCRR%eKUbvؙn9BħJeRR~NցoEx pHYs  'IDAT8%k\E?sfIwƐFHh+>ҾB!T'滈/*"_blik EB4ݻw]93s=jssz~u4Y=Y9mA)EPZKedJrxa{CmmmFNM>[䱙|~;wpl`JSnj[IAukd˩-QZNx{ʫQid<$cS28LtB>\.rqfǔ3'Qt㩏֯ N F2d)xJ?zΰĉ<QWaI3R5JS4E!T{8̜UYln|G~W^FRMp$w\nIuuy9QwW$7#Z3Dgh=?S;;ԙ&sO-pEic~[{s.߳- ܯ,qi:("6\Ou:Aa_`d,<)DH:#t Jb3U!̰_Z,Q=_81K$Y {=_`9ҰRIENDB`plugins-1.5/generic/skinsplugin/skinsplugin.cpp000066400000000000000000000375021336777360500221240ustar00rootroot00000000000000/* * skinsplugin.cpp - plugin * Copyright (C) 2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include #include #include "psiplugin.h" #include "applicationinfoaccessor.h" #include "applicationinfoaccessinghost.h" #include "optionaccessor.h" #include "optionaccessinghost.h" #include "plugininfoprovider.h" #include "ui_skinsplugin.h" #include "skin.h" #include "optionsparser.h" #define cVer "0.3.3" class SkinsPlugin: public QObject, public PsiPlugin, public ApplicationInfoAccessor, public OptionAccessor, public PluginInfoProvider { Q_OBJECT #ifdef HAVE_QT5 Q_PLUGIN_METADATA(IID "com.psi-plus.SkinsPlugin") #endif Q_INTERFACES(PsiPlugin OptionAccessor ApplicationInfoAccessor PluginInfoProvider) public: SkinsPlugin(); virtual QString name() const; virtual QString shortName() const; virtual QString version() const; virtual QWidget* options(); virtual bool enable(); virtual bool disable(); virtual void applyOptions() {}; virtual void restoreOptions(); virtual void setApplicationInfoAccessingHost(ApplicationInfoAccessingHost* host); virtual void setOptionAccessingHost(OptionAccessingHost* host); virtual void optionChanged(const QString& /*option*/) {}; virtual QString pluginInfo(); virtual QPixmap icon() const; private: bool enabled; OptionAccessingHost* psiOptions; ApplicationInfoAccessingHost *appInfo; Ui::SkinsPlugin ui_; QStringList skins_; void findSkins(QString dir); QDomDocument createSkinDocument(QDomElement sampleDoc, QString name = "", QString author = "", QString version = "", QString path = ""); bool validateOption(QString option); void appendSkin(QString fileName); QPointer optionsWidget; private slots: void updateSkins(); void loadPreview(); void updateButtonPressed(); void openButtonPressed(); void enableButton(); void createSkin(QString name, QString author, QString version); void getSkinName(); void applySkin(); void removeSkin(); void overwrite(); }; #ifndef HAVE_QT5 Q_EXPORT_PLUGIN(SkinsPlugin); #endif SkinsPlugin::SkinsPlugin() { enabled = false; appInfo = 0; psiOptions = 0; } QString SkinsPlugin::name() const { return "Skins Plugin"; } QString SkinsPlugin::shortName() const { return "skins"; } QString SkinsPlugin::version() const { return cVer; } bool SkinsPlugin::enable() { if(psiOptions) { enabled = true; } return enabled; } bool SkinsPlugin::disable() { if(optionsWidget){ delete(ui_.lw_skins); } enabled = false; return true; } QWidget* SkinsPlugin::options() { if(!enabled) { return 0; } optionsWidget = new QWidget(); ui_.setupUi(optionsWidget); skins_.clear(); updateSkins(); ui_.pb_apply->setEnabled(false); ui_.pb_remove->setEnabled(false); ui_.pb_save->setEnabled(false); ui_.lbl_wiki->setText(tr("Wiki (Online)")); ui_.lbl_wiki->setOpenExternalLinks(true); connect(ui_.pb_update, SIGNAL(released()), this, SLOT(updateSkins())); connect(ui_.pb_preview, SIGNAL(released()), this, SLOT(loadPreview())); connect(ui_.pb_update, SIGNAL(released()), this, SLOT(updateButtonPressed())); connect(ui_.pb_open, SIGNAL(released()), this, SLOT(openButtonPressed())); connect(ui_.pb_apply, SIGNAL(released()), this, SLOT(applySkin())); connect(ui_.pb_create, SIGNAL(released()), this, SLOT(getSkinName())); connect(ui_.pb_remove, SIGNAL(released()), this, SLOT(removeSkin())); connect(ui_.pb_save, SIGNAL(released()), this, SLOT(overwrite())); connect(ui_.lw_skins, SIGNAL(currentRowChanged(int)), this, SLOT(enableButton())); connect(ui_.lw_skins, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(loadPreview())); ui_.cb_hack->setVisible(false); //Hack, to enable Apply button return optionsWidget; } void SkinsPlugin::restoreOptions() { } void SkinsPlugin::setApplicationInfoAccessingHost(ApplicationInfoAccessingHost* host) { appInfo = host; } void SkinsPlugin::setOptionAccessingHost(OptionAccessingHost* host) { psiOptions = host; } void SkinsPlugin::updateSkins() { QStringList dirs; dirs << appInfo->appHomeDir(ApplicationInfoAccessingHost::DataLocation) << appInfo->appResourcesDir() + "/skins" << appInfo->appHomeDir(ApplicationInfoAccessingHost::DataLocation) + "/skins"; foreach(QString dirName, dirs) { findSkins(dirName); } } void SkinsPlugin::findSkins(QString path) { if(!ui_.lw_skins) return; QDir dir(path); foreach (QString filename, dir.entryList(QDir::Files)) { if(filename.endsWith(".skn", Qt::CaseInsensitive)) { QString file = dir.absolutePath() + QString("/") + filename; if(skins_.contains(file)) continue; skins_.append(file); Skin *newItem = new Skin(ui_.lw_skins); newItem->setFile(file); newItem->setText(newItem->name()); } } foreach (QString subDir, dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)) { findSkins(path + QDir::separator() + subDir); } } void SkinsPlugin::updateButtonPressed() { if(!ui_.lw_skins) return; updateSkins(); // ui_.pb_apply->setEnabled(false); } void SkinsPlugin::loadPreview() { Skin *skin = (Skin*)ui_.lw_skins->currentItem(); if(!skin) return; Previewer *prev = new Previewer(skin); if(prev->loadSkinInformation()) { connect(prev, SIGNAL(applySkin()), this, SLOT(applySkin())); prev->show(); } else delete(prev); } void SkinsPlugin::openButtonPressed() { QString fileName = QFileDialog::getOpenFileName(0,tr("Choose a skin file"), appInfo->appHomeDir(ApplicationInfoAccessingHost::DataLocation), tr("*.skn")); if(fileName.isEmpty()) return; if(skins_.contains(fileName)) return; appendSkin(fileName); } void SkinsPlugin::appendSkin(QString fileName) { if(!ui_.lw_skins) return; skins_.append(fileName); Skin *newItem = new Skin(ui_.lw_skins); newItem->setFile(fileName); newItem->setText(newItem->name()); } void SkinsPlugin::enableButton() { ui_.pb_apply->setEnabled(true); ui_.pb_remove->setEnabled(true); ui_.pb_save->setEnabled(true); } void SkinsPlugin::getSkinName() { QString name, author, version; Skin *skin = (Skin*)ui_.lw_skins->currentItem(); if(skin) { QFile file(skin->filePass()); QDomDocument doc; if(doc.setContent(&file)) { QDomElement elem = doc.documentElement(); if(elem.tagName() == "skin") { author = elem.attribute("author"); version = elem.attribute("version"); name = elem.attribute("name"); } } } GetSkinName *getName = new GetSkinName(name, author, version); connect(getName, SIGNAL(ok(QString,QString,QString)), this, SLOT(createSkin(QString,QString,QString))); getName->show(); } void SkinsPlugin::createSkin(QString name, QString author, QString version) { QFile file(":/skinsplugin/defskin.skn"); QDomDocument doc, newDoc; if(!doc.setContent(&file)) { QMessageBox::warning(0, tr("Create Skin"), tr("Unknown error!")); return; } QDomElement elem = doc.documentElement(); if(elem.tagName() != "skin") { QMessageBox::warning(0, tr("Create Skin"), tr("Unknown error!")); return; } QString fileName = QFileDialog::getSaveFileName(0,tr("Save a skin file"), appInfo->appHomeDir(ApplicationInfoAccessingHost::DataLocation) + QString("/%1_%2").arg(name, version), tr("*.skn")); if(fileName.isEmpty()) return; if(fileName.right(4) != ".skn") fileName.append(".skn"); QString skinPath = fileName; skinPath.chop(skinPath.size() - skinPath.lastIndexOf("/")); newDoc = createSkinDocument(elem, name, author, version, skinPath); QFile saveFile(fileName); if(saveFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) { QTextStream str(&saveFile); str.setCodec("UTF-8"); int indent = 4; str.setGenerateByteOrderMark(false); newDoc.save(str, indent); if(!skins_.contains(fileName)) appendSkin(fileName); } else { QMessageBox::warning(0, tr("Create Skin"), tr("Can't save skin!")); } } void SkinsPlugin::applySkin() { Skin *skin = (Skin*)ui_.lw_skins->currentItem(); if(!skin) return; QFile file(skin->filePass()); QDomDocument doc; if(!doc.setContent(&file)) { QMessageBox::warning(0, tr("Apply Skin"), tr("Unknown error!")); return; } QDomElement elem = doc.documentElement(); if(elem.tagName() != "skin") { QMessageBox::warning(0, tr("Apply Skin"), tr("Unknown error!")); return; } bool backup = ui_.cb_backup->isChecked(); QString fileName; if(backup && skin->name().left(11) != "backupSkin_") { QDomDocument backUp = createSkinDocument(elem, "backup", "SkinsPlugin", "0"); QDir skinsDir(appInfo->appHomeDir(ApplicationInfoAccessingHost::DataLocation) + QString("/skins")); if(!skinsDir.exists()) skinsDir.mkdir(appInfo->appHomeDir(ApplicationInfoAccessingHost::DataLocation) + QString("/skins")); fileName = skinsDir.absolutePath() + "/backupSkin_" + QDateTime::currentDateTime().toString("yyyy-MM-dd_hh-mm-ss") + ".skn"; QFile backUpFile(fileName); if(backUpFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) { QTextStream str(&backUpFile); str.setCodec("UTF-8"); int indent = 4; str.setGenerateByteOrderMark(false); backUp.save(str, indent); appendSkin(fileName); } else { QMessageBox::warning(0, tr("Apply Skin"), tr("Can't save the backup skin!")); return; } } QDomElement options = elem.firstChildElement("options"); QDomNode optionNode = options.firstChild(); while(!optionNode.isNull()) { QDomElement optionElem = optionNode.toElement(); QString oldPath = elem.attribute("path"); QString optionName = optionElem.tagName(); if(validateOption(optionName)) { QVariant optionValue = OptionsParser::instance()->elementToVariant(optionElem); if(!oldPath.isEmpty() && optionValue.type() == QVariant::String) { QString str = optionValue.toString(); str.replace(oldPath, skin->skinFolder()); optionValue = str; } psiOptions->setGlobalOption(optionName, optionValue); } optionNode = optionNode.nextSibling(); } QString mes = QString("Skin %1 successfully applied!\n" "Some changes may only have full effect upon restart!").arg(elem.attribute("name")); if(backup) { mes += QString("\nBackup skin saved to %2").arg(fileName); } QMessageBox::information(0, tr("Apply Skin"), mes); ui_.cb_hack->toggle(); //enable Apply button } QDomDocument SkinsPlugin::createSkinDocument(QDomElement elem, QString name, QString author, QString version, QString path) { QDomDocument newDoc; QDomElement newElem = newDoc.createElement("skin"); newElem.setAttribute("name", name); newElem.setAttribute("author", author); newElem.setAttribute("version", version); newElem.setAttribute("path", path); QDomElement newOptions = newDoc.createElement("options"); QDomElement options = elem.firstChildElement("options"); QDomNode optionNode = options.firstChild(); while(!optionNode.isNull()) { QString optionName = optionNode.toElement().tagName(); if(validateOption(optionName)) { QVariant optionValue = psiOptions->getGlobalOption(optionName); QDomElement newOption = newDoc.createElement(optionName); OptionsParser::instance()->variantToElement(optionValue, newOption); newOptions.appendChild(newOption); } optionNode = optionNode.nextSibling(); } newElem.appendChild(newOptions); newDoc.appendChild(newElem); return newDoc; } bool SkinsPlugin::validateOption(QString optionName) { bool b =(optionName.contains("options.ui.") || optionName.contains("options.iconsets.")) && !optionName.contains("notifications.send-receipts") && !optionName.contains("spell-check.enabled") && !optionName.contains("service-discovery"); return b; } void SkinsPlugin::overwrite() { int ret = QMessageBox::question(0, tr("Overwrite selected skin"), tr("Are You Sure?"), QMessageBox::Ok | QMessageBox::Cancel); if(ret == QMessageBox::Cancel) return; Skin *skin = (Skin*)ui_.lw_skins->currentItem(); if(!skin) return; QFile file(skin->filePass()); QDomDocument doc; if(!doc.setContent(&file)) { QMessageBox::warning(0, tr("Overwrite Skin"), tr("Unknown error!")); return; } QDomElement elem = doc.documentElement(); if(elem.tagName() != "skin") { QMessageBox::warning(0, tr("Overwrite Skin"), tr("Unknown error!")); return; } QDomDocument overwriteDoc = createSkinDocument(elem, elem.attribute("name"), elem.attribute("author"), elem.attribute("version"), skin->skinFolder()); if(file.open(QIODevice::WriteOnly | QIODevice::Truncate)) { QTextStream str(&file); str.setCodec("UTF-8"); int indent = 4; str.setGenerateByteOrderMark(false); overwriteDoc.save(str, indent); } else { QMessageBox::warning(0, tr("Overwrite Skin"), tr("Can't save the skin!")); return; } } void SkinsPlugin::removeSkin() { Skin *skin = (Skin*)ui_.lw_skins->currentItem(); if(!skin) return; int ret = QMessageBox::question(0, tr("Delete skin"), tr("Are You Sure?"), QMessageBox::Ok | QMessageBox::Cancel); if(ret == QMessageBox::Cancel) return; QString filePass = skin->filePass(); QFile file(filePass); if(file.open(QIODevice::ReadWrite)) { ui_.lw_skins->removeItemWidget(skin); delete(skin); file.remove(); skins_.removeAt(skins_.indexOf(filePass)); } } QString SkinsPlugin::pluginInfo() { return tr("Author: ") + "Dealer_WeARE\n" + tr("Email: ") + "wadealer@gmail.com\n\n" + trUtf8("This plugin is designed to create, store and apply skins to Psi+.\n" "Skin - a set of custom settings.\n" "To download a new skin, create a folder named skins in the PsiData directory and put the new skin in it. You can also just open a skin file.\n" "Each skin must be in a separate directory. You can also add a screenshot to the skin file.\n" "In most cases, to be sure that the skin is applied correctly, you must perform a sequence of actions:\n" "1. Apply the skin\n" "2. Restart the application\n" "3. Apply the same skin again\n" "This allows all settings (icons, toolbar layout) to be picked up correctly. "); } QPixmap SkinsPlugin::icon() const { return QPixmap(":/skinsplugin/skins.png"); } #include "skinsplugin.moc" plugins-1.5/generic/skinsplugin/skinsplugin.pro000066400000000000000000000004611336777360500221340ustar00rootroot00000000000000isEmpty(PSISDK) { include(../../psiplugin.pri) } else { include($$PSISDK/plugins/psiplugin.pri) } SOURCES += skinsplugin.cpp \ skin.cpp \ optionsparser.cpp FORMS += skinsplugin.ui \ previewer.ui \ getskinname.ui HEADERS += skin.h \ optionsparser.h RESOURCES += skinsplugin.qrc plugins-1.5/generic/skinsplugin/skinsplugin.qrc000066400000000000000000000002051336777360500221150ustar00rootroot00000000000000 defskin.skn skins.png plugins-1.5/generic/skinsplugin/skinsplugin.ui000066400000000000000000000106421336777360500217530ustar00rootroot00000000000000 SkinsPlugin 0 0 490 336 Form 0 0 16777215 16777215 Preview skin Preview Update skins list Update Apply selected skin Apply Open skin file Open Remove selected skin Remove Qt::Vertical 20 40 true Overwrite selected skin with the current settings Save Create new skin from current settings Create Backup skin before applying true false 0 0 plugins-1.5/generic/stopspamplugin/000077500000000000000000000000001336777360500175625ustar00rootroot00000000000000plugins-1.5/generic/stopspamplugin/CMakeLists.txt000066400000000000000000000027341336777360500223300ustar00rootroot00000000000000unset(_HDRS) unset(_UIS) unset(_SRCS) unset(_RSCS) unset(PLUGIN) set( PLUGIN stopspamplugin ) project(${PLUGIN}) cmake_minimum_required(VERSION 3.1.0) set( CMAKE_AUTOMOC TRUE ) IF( NOT WIN32 ) set( LIB_SUFFIX "" CACHE STRING "Define suffix of directory name (32/64)" ) set( PLUGINS_PATH "lib${LIB_SUFFIX}/psi-plus/plugins" CACHE STRING "Install suffix for plugins" ) ELSE() set( PLUGINS_PATH "psi-plus/plugins" CACHE STRING "Install suffix for plugins" ) ENDIF() add_definitions( -DQT_PLUGIN -DHAVE_QT5 ) include_directories( ${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ../../include . ) set( _HDRS view.h model.h viewer.h typeaheadfind.h deferredstanzasender.h ) set( _SRCS ${PLUGIN}.cpp view.cpp model.cpp viewer.cpp typeaheadfind.cpp deferredstanzasender.cpp ) set( _UIS options.ui ) set( _RSCS resources.qrc ) find_package( Qt5 COMPONENTS Widgets Xml REQUIRED ) set(QT_DEPLIBS Qt5::Widgets Qt5::Xml ) qt5_wrap_ui(UIS ${_UIS}) qt5_add_resources(RSCS ${_RSCS}) add_library( ${PLUGIN} MODULE ${_SRCS} ${UIS} ${RSCS} ) target_link_libraries( ${PLUGIN} ${QT_DEPLIBS} ) if( UNIX AND NOT( APPLE OR CYGWIN ) ) install( TARGETS ${PLUGIN} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} ) endif() if( WIN32 ) install( TARGETS ${PLUGIN} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} ) endif() plugins-1.5/generic/stopspamplugin/changelog.txt000066400000000000000000000320671336777360500222620ustar00rootroot000000000000002013-09-02 v0.5.7 - taurus * Использовать слово Groupchat вместо Conference и MUC 2013-08-13 v0.5.6 - taurus + Иконка плагина 2012-02-20 v0.5.5 * исправления для нового попап-интерфейса 2012-01-26 v0.5.4 * теперь при редактировании правил удаляется выбранная строка, а не последняя * исправлено установка\снятие галочки * мелкие фиксы 2011-05-27 v0.5.3 * пересобрано с новым appHomeDir 2011-02-24 v0.5.2 * исправлена очередность посылки отложенных станз 2011-02-02 v0.5.1 * настройка времени показа всплывающего уведомления перенесена в настройки всплывающих уведомлений для всего приложения 2011-02-01 v0.5.0 * переписаны опции - убрана ненужная настройка "показывать попапы". для отключения попапов нужно выставить интервал 0 * много различных исправлений + добавлена отложенная отправка сообщений. теперь ответы посылаются с задержкой в 0.5сек 2010-12-17 v0.4.7 * различные мелкие исправления 2010-10-13 v0.4.4 + в логе заблокированных станз теперь указывается время 2010-09-11 v0.4.3 * обновлена ссылка на wiki ( http://psi-plus.com/wiki/plugins#stop_spam_plugin ) 2010-09-04 v0.4.2 * немного исправлена блокировка инвайтов 2010-08-30 v0.4.1 + блокируются приглашения в конференции от контактов не из ростера + не блокируются каптчи 2010-08-27 v0.4.0 + стопспам автоматически отключается для людей не из списка, которым вы написали первыми (обычные контакты и приваты в конференциях) + список джидов, для которых стопспам отключен (прошли проверку, или вы сами им писали) автоматически очищается спустя 3 дня после последнего изменения * изменен механизм определения того, что контакт является приватом или конференцией (должно работать для конференций, не имеющих в названии conference) 2010-05-17 v0.3.6 * исправлено падение приложения при отключении плагина 2010-05-06 v0.3.5 + если по какой-то причине не удалось получить ростер (например, ошибка сервера), входящие сообщения не будут блокироваться + добавлена информация о плагине + при сбросе счетчика теперь лог заблокированных станз не удаляется + расширено поле для ввода поздравления 2010-05-06 v0.3.4 + попытка добавить блокировку нежелательных iq запросов + изменено название библиотеки так, чтобы плагин находился первым в каталоге * различные оптимизации кода ВНИМАНИЕ! В связи с изменением названия библиотеки, не забудьте удалить старую версию плагина! 2010-05-04 v0.3.3 * исправлена ссылка на wiki 2010-04-26 v0.3.2 + расширен функционал просмотрщика лога заблокированных станз 2010-04-17 v0.3.1 * инвертирована опция политики по умолчанию * политика по умолчанию для конференций - всегда включено * редизайнинг опций 2010-04-17 v0.3.0 + список исключений заменён на таблицу правил, благодаря чему можно более гибко настроить плагин. Правила проверяются сверху вниз. Если ни одно правило не сработало применяется политика по умолчанию + редизайнинг опций (добавлена новая вкладка) + оптимизирован код обработки приватов 2010-04-08 v0.2.2 * некоторые исправления для режима блокировки сообщений в конференциях 2010-03-26 v0.2.1 * по умолчанию стопспам отключен для участников + добавлена возможность включить отправку уведомления в случае блокировки всех приватных сообщений + активность/неактивность опций зависит от настроек ВНИМАНИЕ! Для того, чтобы плагин мог правильно определить роли и ранги учаcтников конференции необходимо включить обработку приватов _ДО_ входа в конференцию. 2010-03-25 v0.2.0 + добавлена возможность включить стопспам для приватных сообщений в конференциях + можно задать, для каких ролей и рангов плагин будет срабатывать + добавлена опция включения блокировки всех приватных сообщений, отправители которых не попадают в исключения. в этом случае входящее сообщение будет заблокировано, но никакого вопроса отправителю слаться не будет 2010-03-24 v0.1.8 * иправлено отключение Psi+ от сервера при попытке плагином послать сообщение, содержащее некоторые спецсимволы 2010-01-25 v0.1.7 * небольшие исправления во всплывающих сообщениях 2010-01-04 v0.1.6 + добавлена возможность включить запись заблокированных сообщений в историю контакта * при открытии лога заблокированных станз позиция курсора устанавливается в конец лога 2009-12-27 v0.1.5 + добавлена возможность задать сколько раз плагин будет отвечать на сообщения + добавлена возможность задать интервал времени, после которого счетчик будет сброшен 2009-12-26 v0.1.4 + в настройках можно задать время, в течение которого будет показываться всплывающее окно + добавлена возможность включать/выключать всплывающие уведомления + если контакт пройдёт проверку, то будет показано соответствующее окно уведомления + включение/выключение всплывающих окон не зависит от глобальных настроек 2009-12-25 v0.1.3 * some fixes and optimizations 2009-12-24 v0.1.2 + добавлена нотификация о заблокированных станзах с помощью всплывающих сообщений ВНИМАНИЕ! Для работы нужно использовать psi+ r1516 и старше 2009-12-08 v0.1.1 + в настройках плагина добавлена ссылка на wiki 2009-12-03 v0.1.0 + добавлена возможность задать текст сообщения, которое шлет плагин при правильном ответе ВНИМАНИЕ! Перед регистрацией на новом транспорте рекомендуется добавить транспорт в исключения. Это связано с тем, что после регистрации транспорт запрашивает авторизацию для всех контактов и если его не добавить в исключения, плагин Стоп Спам заблокирует все запросы. 2009-11-30 v0.0.9 + добавлена возможность просмотреть лог заблокированных станз из настроек плагина * лог заблокированных станз перенесён в каталог профиля * лог заблокированных станз будет вестись в кодировке utf-8 и на ОС семейства Windows 2009-11-17 v0.0.8 * fixes 2009-11-05 v0.0.7 + добавлено ведения лога заблокированных станз для контроля работы плагина. лог хранится в каталоге настроек в файле Blockedstanzas.log + в опциях добавлена кнопка сброса счётчика заблокированных станз (она также удаляет и лог) * различные оптимизации кода 2009-10-30 v0.0.6 + добавлено ограничение на отправку сообщений пользователям не из списка. Плагин отвечает максимум на 2 сообщения, не содержащих правильного ответа, дальнейшие сообщения игнорируются + сообщения, пришедшие от такого же спамбота пропускаются, чтобы исключить ситуацию, когда спамботы написали друг другу, а пользователи ничего не увидели ВНИМАНИЕ! Если отправить сообщение пользователю, которого нет в вашем списке (опция "Создать сообщение") и у него будет тоже установлен спамбот (но не этот ;) ), то произойдёт неприятная ситуация - ни он, ни вы не получите никаких сообщений - спамботы их заблокируют. Чтобы этого избежать, либо не отсылайте сообщения пользователям не из списка, либо предварительно добавляйте их в список исключения. Если к вам будет стучаться пользователь с gmail.com, то возможна ситуация, что сообщение спамбота не будет принято сервером. В таком случае оно вернётся ошибкой, и также будет заблокировано вашим спамботом. С одной стороны, это удобно Вам - ничего не увидите. С другой стороны, пользователь с gmail.com не получит никакого ответа. С этим сделать что-либо сложно, т.к. это особенности реализации сервера gmail.com 2009-10-28 v0.0.5 + добавлен счётчик заблокированных станз (для контроля работы) * улучшен алгоритм блокировки + пользователи, добавленные в ростер, автоматически удаляются из списка разблокированных 2009-10-27 v0.0.3 + список разблокированных пользователей теперь хранится в настройках плагина. он пока не очищается, поэтому его иногда нужно чистить вручную + добавлен список исключений + добавлена защита от общения плагина с самим собой и с плагином Autoreply + если правильный ответ не был дан, то запросы авторизации отклоняются 2009-10-26 v0.0.1 ! initial version plugins-1.5/generic/stopspamplugin/deferredstanzasender.cpp000066400000000000000000000046521336777360500244770ustar00rootroot00000000000000/* * deferredstanzasender.cpp - plugin * Copyright (C) 2011 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "deferredstanzasender.h" #define DELAY 500 DefferedStanzaSender::DefferedStanzaSender(StanzaSendingHost *host, QObject* p) : QObject(p) , stanzaSender_(host) , timer_(new QTimer(this)) { timer_->setInterval(DELAY); connect(timer_, SIGNAL(timeout()), SLOT(timeout())); } void DefferedStanzaSender::sendStanza(int account, const QDomElement& xml) { XmlStanzaItem item(account, xml); items_.append(Item(Xml, item)); timer_->start(); // стартуем или рестартуем таймер. рестарт нужен, чтобы быть уверенным, что интервал будет соблюден } void DefferedStanzaSender::sendStanza(int account, const QString& xml) { StringStanzaItem item(account, xml); items_.append(Item(String, item)); timer_->start(); } void DefferedStanzaSender::sendMessage(int account, const QString& to, const QString& body, const QString& subject, const QString& type) { MessageItem item(account, to, body, subject, type); items_.append(Item(Message, item)); timer_->start(); } QString DefferedStanzaSender::uniqueId(int account) const { return stanzaSender_->uniqueId(account); } void DefferedStanzaSender::timeout() { if(!items_.isEmpty()) { Item i = items_.takeFirst(); switch(i.type) { case Xml: stanzaSender_->sendStanza(i.xmlItem.first, i.xmlItem.second); break; case String: stanzaSender_->sendStanza(i.stringItem.first, i.stringItem.second); break; case Message: { MessageItem mi = i.messageItem; stanzaSender_->sendMessage(mi.account, mi.to, mi.body, mi.subject, mi.type); break; } default: break; } } else { timer_->stop(); } }; plugins-1.5/generic/stopspamplugin/deferredstanzasender.h000066400000000000000000000044151336777360500241410ustar00rootroot00000000000000/* * deferredstanzasender.cpp - plugin * Copyright (C) 2011 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef DEFERREDSTANZASENDER_H #define DEFERREDSTANZASENDER_H #include #include #include #include "stanzasendinghost.h" class DefferedStanzaSender : public QObject { Q_OBJECT public: DefferedStanzaSender(StanzaSendingHost *host, QObject* p = 0); void sendStanza(int account, const QDomElement& xml); void sendStanza(int account, const QString& xml); void sendMessage(int account, const QString& to, const QString& body, const QString& subject, const QString& type); QString uniqueId(int account) const; private slots: void timeout(); private: StanzaSendingHost *stanzaSender_; QTimer* timer_; typedef QPair XmlStanzaItem; typedef QPair StringStanzaItem; struct MessageItem { MessageItem(int acc, const QString& _to, const QString& _body, const QString& _subject, const QString& _type) : account(acc) , to(_to) , body(_body) , subject(_subject) , type(_type) { } MessageItem() { } int account; QString to; QString body; QString subject; QString type; }; enum ItemType { Xml, String, Message }; struct Item { Item(ItemType t, XmlStanzaItem x) : type(t) , xmlItem(x) {} Item(ItemType t, StringStanzaItem s) : type(t) , stringItem(s) {} Item(ItemType t, MessageItem m) : type(t) , messageItem(m) {} ItemType type; XmlStanzaItem xmlItem; StringStanzaItem stringItem; MessageItem messageItem; }; QList items_; }; #endif // DEFERREDSTANZASENDER_H plugins-1.5/generic/stopspamplugin/model.cpp000066400000000000000000000102401336777360500213630ustar00rootroot00000000000000/* * model.cpp - plugin * Copyright (C) 2009-2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "model.h" Model::Model(QStringList Jids_, QVariantList Sounds_, QObject* parent) : QAbstractTableModel(parent) , Jids(Jids_) { headers << tr("Enable/Disable") << tr("JID (or part of JID)"); tmpJids_ = Jids; for(int i = Sounds_.size(); i > 0;) { bool b = Sounds_.at(--i).toBool(); if(b) selected << Jids.at(i); } } QVariant Model::headerData ( int section, Qt::Orientation orientation, int role) const { if (role == Qt::DisplayRole) { if (orientation == Qt::Horizontal) { return headers.at(section); } else { return section+1; } } else return QVariant(); } Qt::ItemFlags Model::flags ( const QModelIndex & index ) const { Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled; int column = index.column(); if(column == 0) flags |= Qt::ItemIsUserCheckable; else if(column == 1) flags |= Qt::ItemIsEditable; return flags; } int Model::columnCount(const QModelIndex & /*parent*/) const { return headers.size(); } int Model::rowCount(const QModelIndex &/* parent*/) const { return tmpJids_.size(); } QVariant Model::data(const QModelIndex & index, int role) const { if(!index.isValid()) return QVariant(); int i = index.column(); switch(i) { case(0): if (role == Qt::CheckStateRole) return selected.contains(tmpJids_.at(index.row())) ? 2:0; else if (role == Qt::TextAlignmentRole) return (int)(Qt::AlignRight | Qt::AlignVCenter); else if (role == Qt::DisplayRole) return QVariant(""); case(1): if (role == Qt::TextAlignmentRole) return (int)(Qt::AlignRight | Qt::AlignVCenter); else if (role == Qt::DisplayRole) return QVariant(tmpJids_.at(index.row())); } return QVariant(); } QString Model::jid(const QModelIndex & index) const { if(!index.isValid()) return QString(); return Jids.at(index.row()); } bool Model::setData(const QModelIndex & index, const QVariant & value, int role) { if(!index.isValid() || role != Qt::EditRole) return false; int column = index.column(); if(column == 0) { switch(value.toInt()) { case(0): selected.remove(tmpJids_.at(index.row())); break; case(2): selected << tmpJids_.at(index.row()); break; case(3): if( selected.contains(tmpJids_.at(index.row())) ) selected.remove(tmpJids_.at(index.row())); else selected << tmpJids_.at(index.row()); break; } } else if(column == 1) tmpJids_.replace(index.row(), value.toString()); emit dataChanged(index, index); return true; } void Model::reset() { tmpJids_ = Jids; } void Model::addRow() { beginInsertRows(QModelIndex(), tmpJids_.size(), tmpJids_.size()); tmpJids_.append(""); endInsertRows(); } void Model::deleteRow(int row) { if(tmpJids_.isEmpty() || tmpJids_.size() <= row || row < 0) return; QString jid_ = tmpJids_.takeAt(row); if(selected.contains(jid_)) selected.remove(jid_); emit layoutChanged(); } void Model::apply() { Jids = tmpJids_; } int Model::indexByJid(const QString& jid) const { return Jids.indexOf(jid); } QStringList Model::getJids() const { return Jids; } QVariantList Model::enableFor() const { QVariantList list; foreach(QString jid, Jids) { list.append(selected.contains(jid)); } return list; } plugins-1.5/generic/stopspamplugin/model.h000066400000000000000000000037251336777360500210420ustar00rootroot00000000000000/* * model.h - plugin * Copyright (C) 2009-2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef MODEL_H #define MODEL_H #include #include #include #include class Model : public QAbstractTableModel { Q_OBJECT public: Model(QStringList Jids_, QVariantList selected_, QObject *parent = 0); ~Model() {} virtual Qt::ItemFlags flags ( const QModelIndex & index ) const; virtual QVariant headerData ( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const; virtual QVariant data ( const QModelIndex & index, int role = Qt::DisplayRole ) const; virtual int rowCount ( const QModelIndex & parent = QModelIndex() ) const; virtual int columnCount ( const QModelIndex & parent = QModelIndex() ) const; virtual bool setData ( const QModelIndex & index, const QVariant & value, int role = Qt::EditRole ); QString jid(const QModelIndex & index) const; void reset(); void apply(); void addRow(); void deleteRow(int row); int indexByJid(const QString& jid) const; QVariantList enableFor() const; QStringList getJids() const; private: QStringList headers, Jids, tmpJids_; QSet selected; }; #endif // MODEL_H plugins-1.5/generic/stopspamplugin/options.ui000066400000000000000000000314241336777360500216200ustar00rootroot00000000000000 Options 0 0 600 497 Form 0 0 0 Main Question: 0 0 0 0 Answer: Congratulation: 0 0 16777215 70 Groupchat Enable Stop Spam for private messages in groupchat Enable Stop Spam for affiliations: Owner Admin Member None Qt::Horizontal 40 20 Enable Stop Spam for roles: Moderator Participant Visitor Qt::Horizontal 40 20 Block all private messages Send message: 0 0 Misc Number of blocked stanzas: 0 0 0 0 60 16777215 View Log Reset Qt::Horizontal 40 20 Send maximum Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 60 16777215 times Timeout to reset counter: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 60 16777215 min. Qt::Horizontal 40 20 Log blocked messages to contact's history 0 0 Qt::Horizontal 40 20 Add Del Disable stopspam, if don't match any rule above (does not work for muc private messages) <a href="http://psi-plus.com/wiki/plugins#stop_spam_plugin">Wiki (Online)</a> true Viewer QTableView
view.h
plugins-1.5/generic/stopspamplugin/resources.qrc000066400000000000000000000001401336777360500222760ustar00rootroot00000000000000 stopspam.png plugins-1.5/generic/stopspamplugin/stopspam.png000066400000000000000000000064771336777360500221540ustar00rootroot00000000000000PNG  IHDRa DiCCPICC ProfilexwTl/]"e齷.H& KYe7D"V$(bh(+X "J F;'Nw>}w(!a@P"f'0D6p(h@_63u_ -Z[3C+K;?r!YLD)c#c1 ʪ2N|bO h{yIHD.VV>RV:|{ [RF ”"MF1L1[Te'Jx%C%_%RJ#4GcӸu:(G73%Ie%e{SC add1T4UT*TTTUzUUUoScemUkS{Q7UPWߣ~A}b}9Հ5L5"5iјi<9Ъ:5MvhWh~Tfz1U.椎NTgNΌ|ݵͺHz,T NI}mPw ,tӆF -5j4oL50^l\k|g24mr6u0M713fͱBZA EEŰ%2res+}VV(٬Ԗk[c{Îjgʮ=~mCNNb&q'}d]N,:+Uʺuv^|o]5˟[7wM׍mȝ}CǃQSϓY9eu빷ػ{^>*}7l6 8`k`f 7!p2)hEPW0%8*:Qi8# z<ἶ0-AQ#p5#m"GvGѢG.7xt~g|LbLCtOlyPU܊|BLB}&:$%Zh`EꋲJO$O&&N~ rRSvLrgIsKۖ6^>!` /22fLge̜͊j&d'g* 3]9Z99"3Qhh'\(wanLHyy5yoc( z.ٴdloaqu.Yf WB+SVv[UjtCkHk2zmWbuj.Y￾HH\4uލ6W|ĺ})76T}39usocٞ---zl=TX|d[ fEqūI/WWA!1TRվS疝ӫox4صin={j-n`[k k+x\S-ۆzEjpjh8qn6Ik:8w7ޜw[nn?uݼ3V/~ڟM~nr:53(ѽȳ_ry?ZrL{퓓~מ.x:LlfW_w=7~oLM˃_uNO=|zfڛCoYož_CgggI) pHYs  IDAT8SAOA~3mn#bDR/p!/& ćr>n.N%i"*u N?K$ls7͙X08r-c!˂(P,6zI,#wefK(+&{ٙv]~\e{"%88/-X rW\Džn'@ZՐ he6Ve(eum ?:%n0 Dqǐ.%|>`XFA/7 QhPrpyxqUAuyY&50ut#>Lh,AZIb)|289u5Qh|۶$ qua5-٧.wi#Kx@ [ob/ob=P7[(xsy{ԧJEUЖDQD荺bu`P\(j+eB ndɸ{u8o`<3'w/1A`IENDB`plugins-1.5/generic/stopspamplugin/stopspamplugin.cpp000066400000000000000000001024071336777360500233570ustar00rootroot00000000000000/* * stopspamplugin.cpp - plugin * Copyright (C) 2009-2011 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include #include "psiplugin.h" #include "optionaccessor.h" #include "optionaccessinghost.h" #include "stanzafilter.h" #include "stanzasender.h" #include "stanzasendinghost.h" #include "accountinfoaccessor.h" #include "accountinfoaccessinghost.h" #include "applicationinfoaccessor.h" #include "applicationinfoaccessinghost.h" #include "popupaccessor.h" #include "popupaccessinghost.h" #include "iconfactoryaccessor.h" #include "iconfactoryaccessinghost.h" #include "plugininfoprovider.h" #include "eventfilter.h" #include "contactinfoaccessinghost.h" #include "contactinfoaccessor.h" #include "view.h" #include "viewer.h" #include "model.h" #include "ui_options.h" #include "deferredstanzasender.h" #define cVer "0.5.7" #define constQuestion "qstn" #define constAnswer "answr" #define constUnblocked "UnblockedList" #define constJids "dsblJids" #define constselected "slctd" #define constCounter "cntr" #define constHeight "Height" #define constWidth "Width" #define constCongratulation "cngrtltn" #define constPopupNotify "popupntf" #define constInterval "intrvl" #define constTimes "times" #define constResetTime "resettm" #define constLogHistory "lghstr" #define constDefaultAct "dfltact" #define constUseMuc "usemuc" #define constAdmin "affadmin" #define constModer "rolemoder" #define constOwner "affowner" #define constMember "affmember" #define constParticipant "roleparticipant" #define constNone "affnone" #define constVisitor "rolevisitor" #define constBlockAll "blockall" #define constBlockAllMes "blockallmes" #define constEnableBlockAllMes "enableblockallmes" #define constLastUnblock "lastunblock" #define POPUP_OPTION "Stop Spam Plugin" class StopSpam: public QObject, public PsiPlugin, public OptionAccessor, public StanzaSender, public StanzaFilter, public AccountInfoAccessor, public ApplicationInfoAccessor, public PopupAccessor, public IconFactoryAccessor, public PluginInfoProvider, public EventFilter, public ContactInfoAccessor { Q_OBJECT #ifdef HAVE_QT5 Q_PLUGIN_METADATA(IID "com.psi-plus.StopSpam") #endif Q_INTERFACES(PsiPlugin OptionAccessor StanzaSender StanzaFilter AccountInfoAccessor ApplicationInfoAccessor PopupAccessor IconFactoryAccessor PluginInfoProvider EventFilter ContactInfoAccessor) public: StopSpam(); virtual QString name() const; virtual QString shortName() const; virtual QString version() const; virtual PsiPlugin::Priority priority(); virtual QWidget* options(); virtual bool enable(); virtual bool disable(); virtual void applyOptions(); virtual void restoreOptions(); virtual QPixmap icon() const; virtual void setOptionAccessingHost(OptionAccessingHost* host); virtual void optionChanged(const QString& ) {} virtual void setStanzaSendingHost(StanzaSendingHost *host); virtual bool incomingStanza(int account, const QDomElement& xml); virtual bool outgoingStanza(int account, QDomElement& xml); virtual void setAccountInfoAccessingHost(AccountInfoAccessingHost* host); virtual void setApplicationInfoAccessingHost(ApplicationInfoAccessingHost* host); virtual void setPopupAccessingHost(PopupAccessingHost* host); virtual void setIconFactoryAccessingHost(IconFactoryAccessingHost* host); virtual void setContactInfoAccessingHost(ContactInfoAccessingHost* host); virtual QString pluginInfo(); virtual bool processEvent(int , QDomElement& ) { return false; } virtual bool processMessage(int , const QString& , const QString& , const QString& ) { return false; } virtual bool processOutgoingMessage(int account, const QString& fromJid, QString& body, const QString& type, QString& subject); virtual void logout(int ) {} private slots: void resetCounter(); void view(); void close(int w, int h); void changeWidgetsState(); void addRow(); void removeRow(); void hack(); void onOptionsClose(); private: bool findMucNS(const QDomElement& stanza); void updateCounter(const QDomElement& stanza, bool b); bool findAcc(int account, const QString& Jid, int &i); bool findMuc(const QString& mucJid, const QString& nick, int &i); void logHistory(const QDomElement& stanza); bool processMuc(int account, const QDomElement& stanza); bool enabled; OptionAccessingHost* psiOptions; DefferedStanzaSender* stanzaHost; AccountInfoAccessingHost *accInfoHost; ApplicationInfoAccessingHost *appInfoHost; IconFactoryAccessingHost* icoHost; PopupAccessingHost* popup; ContactInfoAccessingHost* contactInfo; QString Question; //вопрос QString Answer; // ответ QString Unblocked; // прошедшие проверку QStringList Jids; // список джидов правил QVariantList selected; // список вкл\выкл int Counter; // счетчик int Height; //высота и ширина int Width; QString Congratulation; // поздравление bool DefaultAct; // выключить, если не подошло ни одно правило int Times; // сколько раз слать int ResetTime; // через сколько сбросить счетчик bool LogHistory; // логировать в историю bool UseMuc, BlockAll, EnableBlockAllMes; // включечить для конф, блокировать все приваты, слать сообщение, если блокируем все приваты bool Admin, Owner, None, Member; // аффилиации bool Moder, Participant, Visitor; // роли QString BlockAllMes; // сообщение, которое шлется приватам если блокируем все приваты struct Blocked { // структура, необходимая для подсчета кол-ва сообщений для конкретного джида int Acc; QString Jid; int count; QDateTime LastMes; }; struct MucUser { // структура, описывающая посетителя конференции QString mucJid; QString nick; QString jid; QString role; QString affiliation; }; QVector BlockedJids; QPointer viewer; Model *model_; QVector mucUsers_; QPointer options_; Ui::Options ui_; int popupId; }; #ifndef HAVE_QT5 Q_EXPORT_PLUGIN(StopSpam); #endif StopSpam::StopSpam() : enabled(false) , psiOptions(0) , stanzaHost(0) , accInfoHost(0) , appInfoHost(0) , icoHost(0) , popup(0) , contactInfo(0) , Question("2+3=?") , Answer("5") , Unblocked("") , Counter(0) , Height(500) , Width(600) , Congratulation("Congratulations! Now you can chat!") , DefaultAct(false) , Times(2) , ResetTime(5) , LogHistory(false) , UseMuc(false) , BlockAll(false) , EnableBlockAllMes(true) , Admin(false) , Owner(false) , None(true) , Member(false) , Moder(false) , Participant(true) , Visitor(true) , BlockAllMes("The private messages are blocked! Send your message to groupchat, please.") , viewer(0) , model_(0) , options_(0) , popupId(0) { } QString StopSpam::name() const { return "Stop Spam Plugin"; } QString StopSpam::shortName() const { return "stopspam"; } QString StopSpam::version() const { return cVer; } PsiPlugin::Priority StopSpam::priority() { return PriorityHighest; } bool StopSpam::enable() { if (psiOptions) { enabled = true; BlockedJids.clear(); mucUsers_.clear(); Question = psiOptions->getPluginOption(constQuestion, QVariant(Question)).toString(); Answer = psiOptions->getPluginOption(constAnswer, QVariant(Answer)).toString(); Congratulation = psiOptions->getPluginOption(constCongratulation, QVariant(Congratulation)).toString(); Unblocked = psiOptions->getPluginOption(constUnblocked, QVariant(Unblocked)).toString(); DefaultAct = psiOptions->getPluginOption(constDefaultAct, QVariant(DefaultAct)).toBool(); Height = psiOptions->getPluginOption(constHeight, QVariant(Height)).toInt(); Width = psiOptions->getPluginOption(constWidth, QVariant(Width)).toInt(); Times = psiOptions->getPluginOption(constTimes, QVariant(Times)).toInt(); ResetTime = psiOptions->getPluginOption(constResetTime, QVariant(ResetTime)).toInt(); LogHistory = psiOptions->getPluginOption(constLogHistory, QVariant(LogHistory)).toBool(); Counter = psiOptions->getPluginOption(constCounter, QVariant(Counter)).toInt(); UseMuc = psiOptions->getPluginOption(constUseMuc, QVariant(UseMuc)).toBool(); BlockAll = psiOptions->getPluginOption(constBlockAll, QVariant(BlockAll)).toBool(); Admin = psiOptions->getPluginOption(constAdmin, QVariant(Admin)).toBool(); Owner = psiOptions->getPluginOption(constOwner, QVariant(Owner)).toBool(); None = psiOptions->getPluginOption(constNone, QVariant(None)).toBool(); Member = psiOptions->getPluginOption(constMember, QVariant(Member)).toBool(); Moder = psiOptions->getPluginOption(constModer, QVariant(Moder)).toBool(); Participant = psiOptions->getPluginOption(constParticipant, QVariant(Participant)).toBool(); Visitor = psiOptions->getPluginOption(constVisitor, QVariant(Visitor)).toBool(); BlockAllMes = psiOptions->getPluginOption(constBlockAllMes, QVariant(BlockAllMes)).toString(); EnableBlockAllMes = psiOptions->getPluginOption(constEnableBlockAllMes, QVariant(EnableBlockAllMes)).toBool(); QDate luTime = QDate::fromString(psiOptions->getPluginOption( constLastUnblock, QVariant(QDate::currentDate().toString("yyyyMMdd")) ).toString(), "yyyyMMdd"); if(!Unblocked.isEmpty() && luTime.daysTo(QDate::currentDate()) > 3) { Unblocked.clear(); psiOptions->setPluginOption(constUnblocked, QVariant(Unblocked)); } Jids = psiOptions->getPluginOption(constJids, QVariant(Jids)).toStringList(); selected = psiOptions->getPluginOption(constselected, QVariant(selected)).value(); model_ = new Model(Jids, selected, this); connect(model_, SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(hack())); //register popup option int interval = psiOptions->getPluginOption(constInterval, QVariant(5000)).toInt()/1000; popupId = popup->registerOption(POPUP_OPTION, interval, "plugins.options."+shortName()+"."+constInterval); } return enabled; } bool StopSpam::disable() { delete viewer; viewer = 0; delete model_; model_ = 0; delete stanzaHost; stanzaHost = 0; popup->unregisterOption(POPUP_OPTION); enabled = false; return true; } void StopSpam::applyOptions() { if (!options_) return; Question = ui_.te_question->toPlainText(); psiOptions->setPluginOption(constQuestion, Question); Answer = ui_.le_answer->text(); psiOptions->setPluginOption(constAnswer, Answer); Congratulation = ui_.te_congratulation->toPlainText(); psiOptions->setPluginOption(constCongratulation, Congratulation); DefaultAct = ui_.cb_default_act->isChecked(); psiOptions->setPluginOption(constDefaultAct, QVariant(DefaultAct)); Times = ui_.sb_times->value(); psiOptions->setPluginOption(constTimes, Times); ResetTime = ui_.sb_reset->value(); psiOptions->setPluginOption(constResetTime, ResetTime); LogHistory = ui_.cb_log_history->isChecked(); psiOptions->setPluginOption(constLogHistory, LogHistory); UseMuc = ui_.cb_enable_muc->isChecked(); psiOptions->setPluginOption(constUseMuc, UseMuc); BlockAll = ui_.cb_block_privates->isChecked(); psiOptions->setPluginOption(constBlockAll, BlockAll); Admin = ui_.cb_admin->isChecked(); psiOptions->setPluginOption(constAdmin, Admin); Owner = ui_.cb_owner->isChecked(); psiOptions->setPluginOption(constOwner, Owner); None = ui_.cb_none->isChecked(); psiOptions->setPluginOption(constNone, None); Member = ui_.cb_member->isChecked(); psiOptions->setPluginOption(constMember, Member); Moder =ui_.cb_moderator->isChecked(); psiOptions->setPluginOption(constModer, Moder); Participant = ui_.cb_participant->isChecked(); psiOptions->setPluginOption(constParticipant, Participant); Visitor = ui_.cb_visitor->isChecked(); psiOptions->setPluginOption(constVisitor, Visitor); EnableBlockAllMes = ui_.cb_send_block_all_mes->isChecked(); psiOptions->setPluginOption(constEnableBlockAllMes, EnableBlockAllMes); BlockAllMes = ui_.te_muc->toPlainText(); psiOptions->setPluginOption(constBlockAllMes, BlockAllMes); model_->apply(); Jids = model_->getJids(); selected = model_->enableFor(); psiOptions->setPluginOption(constJids, Jids); psiOptions->setPluginOption(constselected, selected); } void StopSpam::restoreOptions() { if (!options_) return; ui_.te_question->setText(Question); ui_.le_answer->setText(Answer); ui_.te_congratulation->setText(Congratulation); ui_.cb_default_act->setChecked(DefaultAct); ui_.sb_times->setValue(Times); ui_.sb_reset->setValue(ResetTime); ui_.cb_log_history->setChecked(LogHistory); ui_.cb_enable_muc->setChecked(UseMuc); ui_.cb_block_privates->setChecked(BlockAll); ui_.cb_admin->setChecked(Admin); ui_.cb_owner->setChecked(Owner); ui_.cb_none->setChecked(None); ui_.cb_member->setChecked(Member); ui_.cb_moderator->setChecked(Moder); ui_.cb_participant->setChecked(Participant); ui_.cb_visitor->setChecked(Visitor); ui_.cb_send_block_all_mes->setChecked(EnableBlockAllMes); ui_.te_muc->setText(BlockAllMes); ui_.le_number->setText(QString::number(Counter)); model_->reset(); } QPixmap StopSpam::icon() const { return QPixmap(":/icons/stopspam.png"); } QWidget* StopSpam::options() { if (!enabled) { return 0; } options_ = new QWidget(); ui_.setupUi(options_); connect(options_, SIGNAL(destroyed()), SLOT(onOptionsClose())); ui_.tv_rules->setModel(model_); ui_.tv_rules->init(); connect(ui_.cb_send_block_all_mes, SIGNAL(stateChanged(int)), SLOT(changeWidgetsState())); connect(ui_.cb_enable_muc, SIGNAL(stateChanged(int)), SLOT(changeWidgetsState())); connect(ui_.cb_block_privates, SIGNAL(stateChanged(int)), SLOT(changeWidgetsState())); connect(ui_.pb_add, SIGNAL(released()), SLOT(addRow())); connect(ui_.pb_del, SIGNAL(released()), SLOT(removeRow())); connect(ui_.pb_reset, SIGNAL(released()), SLOT(resetCounter())); connect(ui_.pb_view, SIGNAL(released()), SLOT(view())); restoreOptions(); changeWidgetsState(); return options_; } void StopSpam::setOptionAccessingHost(OptionAccessingHost* host) { psiOptions = host; } void StopSpam::setIconFactoryAccessingHost(IconFactoryAccessingHost* host) { icoHost = host; } void StopSpam::setPopupAccessingHost(PopupAccessingHost* host) { popup = host; } void StopSpam::setStanzaSendingHost(StanzaSendingHost *host) { stanzaHost = new DefferedStanzaSender(host); } void StopSpam::setAccountInfoAccessingHost(AccountInfoAccessingHost* host) { accInfoHost = host; } void StopSpam::setApplicationInfoAccessingHost(ApplicationInfoAccessingHost* host) { appInfoHost = host; } void StopSpam::setContactInfoAccessingHost(ContactInfoAccessingHost *host) { contactInfo = host; } bool StopSpam::incomingStanza(int account, const QDomElement& stanza) { if (enabled) { if(stanza.tagName() == "iq") { QDomElement query = stanza.firstChildElement("query"); if(!Unblocked.isEmpty() && !query.isNull() && query.attribute("xmlns") == "jabber:iq:roster") { QStringList Roster = accInfoHost->getRoster(account); QStringList UnblockedList = Unblocked.split("\n"); while(!Roster.isEmpty()) { QString jid = Roster.takeFirst(); UnblockedList.removeOne(jid); } Unblocked = ""; while(!UnblockedList.isEmpty()) { QString jid = UnblockedList.takeFirst(); if(jid != "") { Unblocked += jid + "\n"; } } psiOptions->setPluginOption(constUnblocked, QVariant(Unblocked)); } } QString from = stanza.attribute("from"); QString to = stanza.attribute("to"); QString valF = from.split("/").takeFirst(); QString valT = to.split("/").takeFirst(); if(valF.toLower() == valT.toLower() || valF.toLower() == accInfoHost->getJid(account).toLower()) return false; if(!from.contains("@")) return false; // Нам необходимо сделать эту проверку здесь, // иначе мы рискуем вообще ее не сделать if (stanza.tagName() == "message") { bool findInvite = false; QString invFrom; QDomElement x = stanza.firstChildElement("x"); while(!x.isNull()) { QDomElement invite = x.firstChildElement("invite"); if(!invite.isNull()) { findInvite = true; invFrom = invite.attribute("from"); break; } x = x.nextSiblingElement("x"); } if(findInvite) { // invite to MUC QStringList r = accInfoHost->getRoster(account); if(r.contains(invFrom.split("/").first(), Qt::CaseInsensitive)) return false; else { bool findRule = false; for(int i = 0; i < Jids.size(); i++) { QString jid_ = Jids.at(i); if(jid_.isEmpty()) continue; if(invFrom.contains(jid_, Qt::CaseInsensitive)) { findRule = true; if(!selected[i].toBool()) return false; break; } } if(!findRule && DefaultAct) return false; else { updateCounter(stanza, false); return true; } } } } if(contactInfo->isConference(account, valF) || contactInfo->isPrivate(account, from) || findMucNS(stanza)) { if(UseMuc) return processMuc(account, stanza); else return false; } QStringList Roster = accInfoHost->getRoster(account); if(Roster.isEmpty() || Roster.contains("-1")) return false; if(Roster.contains(valF, Qt::CaseInsensitive)) return false; QStringList UnblockedJids = Unblocked.split("\n"); if(UnblockedJids.contains(valF, Qt::CaseInsensitive)) return false; bool findRule = false; for(int i = 0; i < Jids.size(); i++) { QString jid_ = Jids.at(i); if(jid_.isEmpty()) continue; if(from.contains(jid_, Qt::CaseInsensitive)) { findRule = true; if(!selected[i].toBool()) return false; break; } } if(!findRule && DefaultAct) return false; if (stanza.tagName() == "message") { QString subj = stanza.firstChildElement("subject").text(); QString type = ""; type = stanza.attribute("type"); if(type == "error" && subj == "StopSpam Question") { updateCounter(stanza, false); return true; } if (subj == "AutoReply" || subj == "StopSpam" || subj == "StopSpam Question") return false; if(type == "groupchat" || type == "error") return false; QDomElement captcha = stanza.firstChildElement("captcha"); if(!captcha.isNull() && captcha.attribute("xmlns") == "urn:xmpp:captcha") return false; // CAPTCHA QDomElement Body = stanza.firstChildElement("body"); if(!Body.isNull()) { QString BodyText = Body.text(); if(BodyText == Answer) { Unblocked += valF + "\n"; psiOptions->setPluginOption(constUnblocked, QVariant(Unblocked)); psiOptions->setPluginOption(constLastUnblock, QVariant(QDate::currentDate().toString("yyyyMMdd"))); stanzaHost->sendMessage(account, from, Congratulation, "StopSpam", "chat"); updateCounter(stanza, true); if(LogHistory) logHistory(stanza); return true; } else { int i = BlockedJids.size(); if(findAcc(account, valF, i)) { Blocked &B = BlockedJids[i]; if(B.count < Times) { stanzaHost->sendMessage(account, from, Question, "StopSpam Question", "chat"); updateCounter(stanza, false); if(LogHistory) logHistory(stanza); B.count++; B.LastMes = QDateTime::currentDateTime(); return true; } else { if(QDateTime::currentDateTime().secsTo(B.LastMes) >= -ResetTime*60) { updateCounter(stanza, false); if(LogHistory) logHistory(stanza); return true; } else { B.count = 1; B.LastMes = QDateTime::currentDateTime(); stanzaHost->sendMessage(account, from, Question, "StopSpam Question", "chat"); updateCounter(stanza, false); if(LogHistory) logHistory(stanza); return true; } } } else { Blocked B = { account, valF, 1, QDateTime::currentDateTime() }; BlockedJids << B; stanzaHost->sendMessage(account, from, Question, "StopSpam Question", "chat"); updateCounter(stanza, false); if(LogHistory) logHistory(stanza); return true; } } } updateCounter(stanza, false); return true; } if (stanza.tagName() == "presence") { QString type = stanza.attribute("type"); if(type == "subscribe") { stanzaHost->sendMessage(account, from, Question, "StopSpam Question", "chat"); stanzaHost->sendStanza(account, ""); updateCounter(stanza, false); if(LogHistory) logHistory(stanza); return true; } else return false; } if (stanza.tagName() == "iq" && stanza.attribute("type") == "set") { QString msg = QString("sendStanza(account, msg); updateCounter(stanza, false); return true; } return false; } return false; } bool StopSpam::findMucNS(const QDomElement &stanza) { bool find = false; QDomNodeList nodeList = stanza.elementsByTagName("x"); for(int i = 0; i < nodeList.size(); i++) { QDomElement item = nodeList.at(i).toElement(); if(!item.isNull() && item.attribute("xmlns").contains("http://jabber.org/protocol/muc")) { find = true; break; } } return find; } bool StopSpam::outgoingStanza(int /*account*/, QDomElement& /*xml*/) { return false; } bool StopSpam::processOutgoingMessage(int acc, const QString &fromJid, QString &body, const QString &type, QString &/*subject*/) { if(enabled && type != "groupchat" && !body.isEmpty()) { QString bareJid; if(contactInfo->isPrivate(acc, fromJid)) { bareJid = fromJid; } else { bareJid = fromJid.split("/").first(); if(contactInfo->inList(acc, bareJid)) return false; } if(!Unblocked.split("\n").contains(bareJid, Qt::CaseInsensitive)) { Unblocked += bareJid + "\n"; psiOptions->setPluginOption(constUnblocked, QVariant(Unblocked)); psiOptions->setPluginOption(constLastUnblock, QVariant(QDate::currentDate().toString("yyyyMMdd"))); } } return false; } void StopSpam::updateCounter(const QDomElement& stanza, bool b) { ++Counter; psiOptions->setPluginOption(constCounter, QVariant(Counter)); QString path = appInfoHost->appProfilesDir(ApplicationInfoAccessingHost::DataLocation); QFile file(path + QDir::separator() + "Blockedstanzas.log"); if(file.open(QIODevice::WriteOnly | QIODevice::Append)) { QString date = QDateTime::currentDateTime().toString("dd.MM.yyyy hh:mm:ss"); QTextStream out(&file); out.setCodec("UTF-8"); //out.seek(file.size()); out.setGenerateByteOrderMark(false); out << date << endl << stanza << endl; } if(!popup->popupDuration(POPUP_OPTION)) return; if(!b) { QString popupText = tr("Block stanza from ") + stanza.attribute("from"); popup->initPopup(popupText, tr("Stop Spam Plugin"), "psi/cancel", popupId); } else { QString popupText = stanza.attribute("from") + tr(" pass the test"); popup->initPopup(popupText, tr("Stop Spam Plugin"), "psi/headline", popupId); } } bool StopSpam::findAcc(int account, const QString& Jid, int &i) { for(; i > 0;) { Blocked Block = BlockedJids[--i]; if(Block.Acc == account && Block.Jid == Jid) { return true; } } return false; } void StopSpam::resetCounter() { Counter = 0; psiOptions->setPluginOption(constCounter, QVariant(Counter)); ui_.le_number->setText("0"); } void StopSpam::view() { if(viewer) viewer->raise(); else { QString path = appInfoHost->appProfilesDir(ApplicationInfoAccessingHost::DataLocation) + QDir::separator() + "Blockedstanzas.log"; viewer = new ViewLog(path, icoHost); connect(viewer, SIGNAL(onClose(int, int)), this, SLOT(close(int,int))); if(!viewer->init()) return; viewer->resize(Width, Height); viewer->show(); } } void StopSpam::close(int width, int height) { Height = height; Width = width; psiOptions->setPluginOption(constHeight, QVariant(Height)); psiOptions->setPluginOption(constWidth, QVariant(Width)); } void StopSpam::logHistory(const QDomElement& stanza) { QString folder = appInfoHost->appHistoryDir(); QString filename = stanza.attribute("from").split("/").takeFirst() + QString::fromUtf8(".history"); filename.replace("%", "%25"); filename.replace("_", "%5f"); filename.replace("-", "%2d"); filename.replace("@", "_at_"); QFile file(folder + QDir::separator() + filename); if(!file.open(QIODevice::WriteOnly | QIODevice::Append)) return; QString time = QDateTime::currentDateTime().toString("|yyyy-MM-ddThh:mm:ss|"); QString type; if(stanza.tagName() == "presence") type = "3|"; else type = "1|"; QString body = stanza.firstChildElement("body").text(); if(body.isEmpty()) body = "subscribe"; QString outText = time + type + QString::fromUtf8("from|N---|") + body; QTextStream out(&file); out.setCodec("UTF-8"); //out.seek(file.size()); out.setGenerateByteOrderMark(false); out << outText << endl; } bool StopSpam::processMuc(int account, const QDomElement& stanza) { if(stanza.tagName() == "presence") { QStringList jidList = stanza.attribute("from").split("/"); int i = mucUsers_.size(); if(findMuc(jidList.first(),jidList.last(), i)) { MucUser &mu = mucUsers_[i]; QDomNodeList nodeList = stanza.elementsByTagName("x"); for(int i = nodeList.size(); i> 0;) { QDomNode node = nodeList.at(--i).firstChild(); while(!node.isNull()) { QDomElement item = node.toElement(); if(item.tagName() == "item") { mu.affiliation = item.attribute("affiliation"); mu.role = item.attribute("role"); mu.jid = item.attribute("jid"); break; } node = node.nextSibling(); } } } else { MucUser mu; mu.mucJid = jidList.first(); mu.nick = jidList.last(); QDomNodeList nodeList = stanza.elementsByTagName("x"); for(int i = nodeList.size(); i> 0;) { QDomNode node = nodeList.at(--i).firstChild(); while(!node.isNull()) { QDomElement item = node.toElement(); if(item.tagName() == "item") { mu.affiliation = item.attribute("affiliation"); mu.role = item.attribute("role"); mu.jid = item.attribute("jid"); break; } node = node.nextSibling(); } } mucUsers_ << mu; } } else if(stanza.tagName() == "message" && stanza.attribute("type") == "chat") { QDomElement subj = stanza.firstChildElement("subject"); if (subj.text() == "StopSpam" || subj.text() == "StopSpam Question") return false; QString valF = stanza.attribute("from"); if (contactInfo->isConference(account, valF)) return false; MucUser mu; QStringList jidList = valF.split("/"); int i = mucUsers_.size(); if(findMuc(jidList.first(),jidList.last(), i)) { mu = mucUsers_[i]; } else { mu.affiliation = ""; mu.jid = ""; mu.mucJid = ""; mu.nick = ""; mu.role = ""; } bool find = false; if(mu.affiliation == "owner" && !Owner) find = true; else if( mu.affiliation == "admin" && !Admin) find = true; else if(mu.affiliation == "none" && !None) find = true; else if(mu.affiliation == "member" && !Member) find = true; if(find) return false; if(mu.role == "moderator" && !Moder) find = true; else if(mu.role == "participant" && !Participant) find = true; else if(mu.role == "visitor" && !Visitor) find = true; if(find) return false; QStringList UnblockedJids = Unblocked.split("\n"); if(UnblockedJids.contains(valF, Qt::CaseInsensitive)) return false; for(int i = 0; i < Jids.size(); i++) { QString jid_ = Jids.at(i); if(jid_.isEmpty()) continue; if(mu.jid.contains(jid_, Qt::CaseInsensitive) || mu.nick.contains(jid_, Qt::CaseInsensitive) || mu.mucJid.contains(jid_, Qt::CaseInsensitive)) { if(!selected[i].toBool()) return false; break; } } QDomElement Body = stanza.firstChildElement("body"); if(Body.isNull()) return false; if(BlockAll) { updateCounter(stanza, false); if(EnableBlockAllMes) stanzaHost->sendMessage(account, valF, BlockAllMes, "StopSpam", "chat"); return true; } QString BodyText = Body.text(); if(BodyText == Answer) { Unblocked += valF + "\n"; QVariant vUnblocked(Unblocked); psiOptions->setPluginOption(constUnblocked, vUnblocked); psiOptions->setPluginOption(constLastUnblock, QVariant(QDate::currentDate().toString("yyyyMMdd"))); stanzaHost->sendMessage(account, valF, Congratulation, "StopSpam", "chat"); updateCounter(stanza, true); return true; } else { int i = BlockedJids.size(); if(findAcc(account, valF, i)) { Blocked &B = BlockedJids[i]; if(B.count < Times) { stanzaHost->sendMessage(account, valF, Question, "StopSpam Question", "chat"); updateCounter(stanza, false); B.count++; B.LastMes = QDateTime::currentDateTime(); return true; } else { if(QDateTime::currentDateTime().secsTo(B.LastMes) >= -ResetTime*60) { updateCounter(stanza, false); return true; } else { B.count = 1; B.LastMes = QDateTime::currentDateTime(); stanzaHost->sendMessage(account, valF, Question, "StopSpam Question", "chat"); updateCounter(stanza, false); return true; } } } else { Blocked B = { account, valF, 1, QDateTime::currentDateTime() }; BlockedJids << B; stanzaHost->sendMessage(account, valF, Question, "StopSpam Question", "chat"); updateCounter(stanza, false); return true; } } } return false; } void StopSpam::changeWidgetsState() { ui_.gb_affiliations->setEnabled(ui_.cb_enable_muc->isChecked()); ui_.gb_rules->setEnabled(ui_.cb_enable_muc->isChecked()); ui_.cb_block_privates->setEnabled(ui_.cb_enable_muc->isChecked()); ui_.cb_send_block_all_mes->setEnabled(ui_.cb_enable_muc->isChecked() && ui_.cb_block_privates->isChecked()); ui_.te_muc->setEnabled(ui_.cb_enable_muc->isChecked() && ui_.cb_block_privates->isChecked() && ui_.cb_send_block_all_mes->isChecked()); } void StopSpam::addRow() { model_->addRow(); hack(); } void StopSpam::removeRow() { if(model_->rowCount() > 1) { QModelIndex index = ui_.tv_rules->currentIndex(); if(index.isValid()) { model_->deleteRow(index.row()); hack(); } } } void StopSpam::hack() { ui_.cb_admin->toggle(); ui_.cb_admin->toggle(); } bool StopSpam::findMuc(const QString& mucJid, const QString& nick, int &i) { for(; i > 0;) { MucUser mu = mucUsers_[--i]; if(mu.mucJid == mucJid && mu.nick == nick) { return true; } } return false; } void StopSpam::onOptionsClose() { model_->reset(); } QString StopSpam::pluginInfo() { return tr("Author: ") + "Dealer_WeARE\n" + tr("Email: ") + "wadealer@gmail.com\n\n" + trUtf8("This plugin is designed to block spam messages and other unwanted information from Psi+ users." "The functionality of the plugin is based on the principle of \"question - answer\".\n" "With the plugin settings you can:\n" "* Define a security question and the answer\n" "* Define the set of rules that define whether to the trigger plugin for a contact\n" "* Define the text messages sent in the case of the correct answer\n" "* Enable notification through popups\n" "* Enable the saving of blocked messages in the history of the contact\n" "* Define the number of subject parcels\n" "* Set the time interval after which to reset the number of how many questions will be sent\n" "* Enable blocking of private messages in groupchats\n" "* Choose for which ranks and roles of groupchat participants blocking messages will be disabled\n" "* Enable deadlocks in private messages to participants who do not fall into the exceptions list for the roles and ranks which include blocking.\n\n" "The rules are checked from top to bottom. If the rule is Enabled - stopspam is triggered, otherwise - stopspam is not triggered." " In the case where none of the rules triggered stopspam for roster messages, you can specify whether the plugin will activate or not." " For private messages from the same groupchat, it will always work.\n" "Question and answer as well as a list of rules is common for ordinary messages and for private messages in groupchats.\n" "When a user has passed, the test will send a re-authorization request. It should be noted in the messages that are sent back" " the security question was correctly answered.\n" "The plugin keeps a log of blocked messages, which you can view through the plugin settings. The \"Reset\" button deletes the log" " and resets the counter of blocked messages.\n\n" "WARNING!!! Before registering a new transport, it is recommended to add its jid to transport exceptions. This is due to the fact" " that after the transport registration, authorization requests for all contacts will be sent and if the transport was not added to" " as an exception, the plugin will block all the requests."); } #include "stopspamplugin.moc" plugins-1.5/generic/stopspamplugin/stopspamplugin.pro000066400000000000000000000007011336777360500233670ustar00rootroot00000000000000TARGET = stopspamplugin isEmpty(PSISDK) { include(../../psiplugin.pri) } else { include($$PSISDK/plugins/psiplugin.pri) } INCLUDEPATH += $$PWD DEPENDPATH += $$PWD SOURCES += stopspamplugin.cpp \ view.cpp \ model.cpp \ viewer.cpp \ typeaheadfind.cpp \ deferredstanzasender.cpp HEADERS += view.h \ model.h \ viewer.h \ typeaheadfind.h \ deferredstanzasender.h FORMS += options.ui RESOURCES += resources.qrc plugins-1.5/generic/stopspamplugin/typeaheadfind.cpp000066400000000000000000000123221336777360500230730ustar00rootroot00000000000000/* * typeaheadfind.cpp - plugin * Copyright (C) 2009-2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "typeaheadfind.h" #include #include #include #include using namespace Stopspam; class TypeAheadFindBar::Private { public: void doFind(bool backward = false) { QTextDocument::FindFlags options; if (caseSensitive) options |= QTextDocument::FindCaseSensitively; if (backward) { options |= QTextDocument::FindBackward; QTextCursor cursor = te->textCursor(); cursor.setPosition(cursor.selectionStart()); cursor.movePosition(QTextCursor::Left); te->setTextCursor(cursor); } if (find(text, options)) { le_find->setStyleSheet(""); } else { le_find->setStyleSheet("QLineEdit { background: #ff6666; color: #ffffff }"); } } bool find(const QString &str, QTextDocument::FindFlags options, QTextCursor::MoveOperation start = QTextCursor::NoMove) { Q_UNUSED(str); if (start != QTextCursor::NoMove) { QTextCursor cursor = te->textCursor(); cursor.movePosition(start); te->setTextCursor(cursor); } bool found = te->find(text, options); if (!found) { if (start == QTextCursor::NoMove) return find(text, options, options & QTextDocument::FindBackward ? QTextCursor::End : QTextCursor::Start); return false; } return true; } QString text; bool caseSensitive; QTextEdit *te; QLineEdit *le_find; QPushButton *but_next; QPushButton *but_prev; QPushButton *first_page, *next_page, *last_page, *prev_page; QCheckBox *cb_case; }; TypeAheadFindBar::TypeAheadFindBar(IconFactoryAccessingHost *IcoHost, QTextEdit *textedit, const QString &title, QWidget *parent) : QToolBar(title, parent) , icoHost_(IcoHost) { d = new Private(); d->te = textedit; init(); } void TypeAheadFindBar::init() { d->caseSensitive = false; d->text = ""; addWidget(new QLabel(tr("Search: "), this)); d->le_find = new QLineEdit(this); d->le_find->setMaximumWidth(128); connect(d->le_find, SIGNAL(textEdited(const QString &)), SLOT(textChanged(const QString &))); addWidget(d->le_find); d->but_prev = new QPushButton(this); d->but_prev->setFixedSize(25,25); d->but_prev->setIcon(icoHost_->getIcon("psi/arrowUp")); d->but_prev->setEnabled(false); connect(d->but_prev, SIGNAL(released()), SLOT(findPrevious())); addWidget(d->but_prev); d->but_next = new QPushButton(this); d->but_next->setFixedSize(25,25); d->but_next->setIcon(icoHost_->getIcon("psi/arrowDown")); d->but_next->setEnabled(false); connect(d->but_next, SIGNAL(released()), SLOT(findNext())); addWidget(d->but_next); d->cb_case = new QCheckBox(tr("&Case sensitive"), this); connect(d->cb_case, SIGNAL(clicked()), SLOT(caseToggled())); addWidget(d->cb_case); addSeparator(); d->first_page = new QPushButton(this); d->first_page->setToolTip(tr("First page")); connect(d->first_page, SIGNAL(released()), SIGNAL(firstPage())); d->first_page->setFixedSize(25,25); d->first_page->setIcon(icoHost_->getIcon("psi/doubleBackArrow")); addWidget(d->first_page); d->prev_page = new QPushButton(this); d->prev_page->setToolTip(tr("Previous page")); connect(d->prev_page, SIGNAL(released()), SIGNAL(prevPage())); d->prev_page->setFixedSize(25,25); d->prev_page->setIcon(icoHost_->getIcon("psi/arrowLeft")); addWidget(d->prev_page); d->next_page = new QPushButton(this); d->next_page->setToolTip(tr("Next page")); connect(d->next_page, SIGNAL(released()), SIGNAL(nextPage())); d->next_page->setFixedSize(25,25); d->next_page->setIcon(icoHost_->getIcon("psi/arrowRight")); addWidget(d->next_page); d->last_page = new QPushButton(this); d->last_page->setToolTip(tr("Last page")); connect(d->last_page, SIGNAL(released()), SIGNAL(lastPage())); d->last_page->setFixedSize(25,25); d->last_page->setIcon(icoHost_->getIcon("psi/doubleNextArrow")); addWidget(d->last_page); } TypeAheadFindBar::~TypeAheadFindBar() { delete d; d = 0; } void TypeAheadFindBar::textChanged(const QString &str) { QTextCursor cursor = d->te->textCursor(); if (str.isEmpty()) { d->but_next->setEnabled(false); d->but_prev->setEnabled(false); d->le_find->setStyleSheet(""); cursor.clearSelection(); d->te->setTextCursor(cursor); } else { d->but_next->setEnabled(true); d->but_prev->setEnabled(true); cursor.setPosition(cursor.selectionStart()); d->te->setTextCursor(cursor); d->text = str; d->doFind(); } } void TypeAheadFindBar::findNext() { d->doFind(); } void TypeAheadFindBar::findPrevious() { d->doFind(true); } void TypeAheadFindBar::caseToggled() { d->caseSensitive = d->cb_case->checkState(); } plugins-1.5/generic/stopspamplugin/typeaheadfind.h000066400000000000000000000026621336777360500225460ustar00rootroot00000000000000/* * typeaheadfind.h - plugin * Copyright (C) 2009-2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef TYPEAHEADFIND_H #define TYPEAHEADFIND_H #include #include #include "iconfactoryaccessinghost.h" namespace Stopspam { class TypeAheadFindBar : public QToolBar { Q_OBJECT public: TypeAheadFindBar(IconFactoryAccessingHost *IcoHost, QTextEdit *textedit, const QString &title, QWidget *parent = 0); ~TypeAheadFindBar(); void init(); signals: void firstPage(); void lastPage(); void nextPage(); void prevPage(); private slots: void textChanged(const QString &); void findNext(); void findPrevious(); void caseToggled(); private: class Private; Private *d; IconFactoryAccessingHost *icoHost_; }; } #endif plugins-1.5/generic/stopspamplugin/view.cpp000066400000000000000000000027021336777360500212410ustar00rootroot00000000000000/* * view.cpp - plugin * Copyright (C) 2009-2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "view.h" #include void Viewer::init() { setSelectionBehavior(QAbstractItemView::SelectRows); resizeColumnsToContents(); #ifdef HAVE_QT5 horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); #else horizontalHeader()->setResizeMode(QHeaderView::ResizeToContents); #endif horizontalHeader()->setStretchLastSection(true); verticalHeader()->setDefaultAlignment( Qt::AlignHCenter ); connect(this, SIGNAL(clicked(QModelIndex)), this, SLOT(itemClicked(QModelIndex))); } void Viewer::itemClicked(QModelIndex index) { if(index.column() == 0) model()->setData(index, 3); //invert } plugins-1.5/generic/stopspamplugin/view.h000066400000000000000000000020451336777360500207060ustar00rootroot00000000000000/* * view.h - plugin * Copyright (C) 2009-2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef VIEW_H #define VIEW_H #include class Viewer : public QTableView { Q_OBJECT public: Viewer(QWidget *parent = 0) : QTableView(parent) {} void init(); private slots: void itemClicked(QModelIndex index); }; #endif // VIEW_H plugins-1.5/generic/stopspamplugin/viewer.cpp000077500000000000000000000117171336777360500216010ustar00rootroot00000000000000/* * viewer.cpp - plugin * Copyright (C) 2009-2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "viewer.h" #include #include #include #include #include #include ViewLog::ViewLog(QString filename, IconFactoryAccessingHost *IcoHost, QWidget *parent) : QDialog(parent) , icoHost_(IcoHost) , fileName_(filename) { setAttribute(Qt::WA_DeleteOnClose); setWindowTitle(fileName_); QVBoxLayout *layout = new QVBoxLayout(this); textWid = new QTextEdit(); layout->addWidget(textWid); findBar = new Stopspam::TypeAheadFindBar(icoHost_, textWid, tr("Find"), this); QPushButton *Close = new QPushButton(icoHost_->getIcon("psi/quit"), tr("Close")); QPushButton *Save = new QPushButton(icoHost_->getIcon("psi/save"), tr("Save Changes")); QPushButton *Delete = new QPushButton(icoHost_->getIcon("psi/remove"), tr("Delete Log")); QPushButton *Update = new QPushButton(icoHost_->getIcon("psi/reload"), tr("Update Log")); QHBoxLayout *butLayout = new QHBoxLayout(); butLayout->addWidget(Delete); butLayout->addStretch(); butLayout->addWidget(Update); butLayout->addWidget(Save); butLayout->addWidget(Close); layout->addWidget(findBar); layout->addLayout(butLayout); connect(Close, SIGNAL(released()), this, SLOT(close())); connect(Delete, SIGNAL(released()), this, SLOT(deleteLog())); connect(Save, SIGNAL(released()), this, SLOT(saveLog())); connect(Update, SIGNAL(released()), this, SLOT(updateLog())); connect(findBar, SIGNAL(firstPage()), this, SLOT(firstPage())); connect(findBar, SIGNAL(lastPage()), this, SLOT(lastPage())); connect(findBar, SIGNAL(prevPage()), this, SLOT(prevPage())); connect(findBar, SIGNAL(nextPage()), this, SLOT(nextPage())); } void ViewLog::closeEvent(QCloseEvent *e) { emit onClose(width(), height()); QDialog::closeEvent(e); e->accept(); } void ViewLog::deleteLog() { int ret = QMessageBox::question(this, tr("Delete log file"), tr("Are you sure?"), QMessageBox::Yes, QMessageBox::Cancel); if(ret == QMessageBox::Cancel) { return; } close(); QFile file(fileName_); if(file.open(QIODevice::ReadWrite)) { file.remove(); } } void ViewLog::saveLog() { QDateTime Modified = QFileInfo(fileName_).lastModified(); if(lastModified_ < Modified) { QMessageBox msgBox; msgBox.setWindowTitle(tr("Save log")); msgBox.setText(tr("New messages has been added to log. If you save your changes, you will lose them")); msgBox.setInformativeText(tr("Do you want to save your changes?")); msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Cancel); msgBox.setDefaultButton(QMessageBox::Cancel); int ret = msgBox.exec(); if(ret == QMessageBox::Cancel) { return; } } else { int ret = QMessageBox::question(this, tr("Save log"), tr("Are you sure?"), QMessageBox::Yes, QMessageBox::Cancel); if(ret == QMessageBox::Cancel) { return; } } QFile file(fileName_); if(file.open(QIODevice::ReadWrite)) { file.remove(); } if(file.open(QIODevice::ReadWrite)) { QTextStream out(&file); out.setCodec("UTF-8"); QString Text = textWid->toPlainText(); pages_.insert(currentPage_, Text); for(int i = 0; i < pages_.size(); i++) { out.setGenerateByteOrderMark(false); out << pages_.value(i); } } } void ViewLog::updateLog() { pages_.clear(); init(); } bool ViewLog::init() { bool b = false; QFile file(fileName_); if(file.open(QIODevice::ReadOnly)) { QString page; int numPage = 0; QTextStream in(&file); in.setCodec("UTF-8"); while(!in.atEnd()) { page = ""; for(int i = 0; i < 500; i++) { if(in.atEnd()) break; page += in.readLine() + "\n"; } pages_.insert(numPage++, page); } currentPage_ = pages_.size()-1; lastModified_ = QDateTime::currentDateTime(); setPage(); b = true; } return b; } void ViewLog::setPage() { QString text = pages_.value(currentPage_); textWid->setText(text); QTextCursor cur = textWid->textCursor(); cur.setPosition(text.length()); textWid->setTextCursor(cur); } void ViewLog::nextPage() { if(currentPage_ < pages_.size()-1) currentPage_++; setPage(); } void ViewLog::prevPage() { if(currentPage_ > 0) currentPage_--; setPage(); } void ViewLog::lastPage() { currentPage_ = pages_.size()-1; setPage(); } void ViewLog::firstPage() { currentPage_ = 0; setPage(); } plugins-1.5/generic/stopspamplugin/viewer.h000077500000000000000000000030741336777360500212430ustar00rootroot00000000000000/* * viewer.h - plugin * Copyright (C) 2009-2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef VIEWER_H #define VIEWER_H #include #include #include #include #include "iconfactoryaccessinghost.h" #include "typeaheadfind.h" class ViewLog : public QDialog { Q_OBJECT public: ViewLog(QString filename, IconFactoryAccessingHost *IcoHost, QWidget *parent = 0); bool init(); private: IconFactoryAccessingHost *icoHost_; QString fileName_; QDateTime lastModified_; QTextEdit *textWid; Stopspam::TypeAheadFindBar *findBar; QMap pages_; int currentPage_; void setPage(); private slots: void saveLog(); void updateLog(); void deleteLog(); void nextPage(); void prevPage(); void firstPage(); void lastPage(); protected: void closeEvent(QCloseEvent *e); signals: void onClose(int,int); }; #endif // VIEWER_H plugins-1.5/generic/storagenotesplugin/000077500000000000000000000000001336777360500204315ustar00rootroot00000000000000plugins-1.5/generic/storagenotesplugin/CMakeLists.txt000066400000000000000000000030041336777360500231660ustar00rootroot00000000000000unset(_HDRS) unset(_UIS) unset(_SRCS) unset(_RSCS) unset(PLUGIN) set( PLUGIN storagenotesplugin ) project(${PLUGIN}) cmake_minimum_required(VERSION 3.1.0) set( CMAKE_AUTOMOC TRUE ) IF( NOT WIN32 ) set( LIB_SUFFIX "" CACHE STRING "Define suffix of directory name (32/64)" ) set( PLUGINS_PATH "lib${LIB_SUFFIX}/psi-plus/plugins" CACHE STRING "Install suffix for plugins" ) ELSE() set( PLUGINS_PATH "psi-plus/plugins" CACHE STRING "Install suffix for plugins" ) ENDIF() add_definitions( -DQT_PLUGIN -DHAVE_QT5 ) include_directories( ${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ../../include . ) set( _HDRS ${PLUGIN}.h notes.h editnote.h tagsmodel.h notesviewdelegate.h notescontroller.h ) set( _SRCS ${PLUGIN}.cpp notes.cpp editnote.cpp tagsmodel.cpp notesviewdelegate.cpp notescontroller.cpp ) set( _UIS notes.ui editnote.ui ) set( _RSCS ${PLUGIN}.qrc ) find_package( Qt5 COMPONENTS Widgets Xml REQUIRED ) set(QT_DEPLIBS Qt5::Widgets Qt5::Xml ) qt5_wrap_ui(UIS ${_UIS}) qt5_add_resources(RSCS ${_RSCS}) add_library( ${PLUGIN} MODULE ${_SRCS} ${UIS} ${RSCS} ) target_link_libraries( ${PLUGIN} ${QT_DEPLIBS} ) if( UNIX AND NOT( APPLE OR CYGWIN ) ) install( TARGETS ${PLUGIN} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} ) endif() if( WIN32 ) install( TARGETS ${PLUGIN} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} ) endif() plugins-1.5/generic/storagenotesplugin/changelog.txt000066400000000000000000000121751336777360500231270ustar00rootroot000000000000002013-08-13 v0.1.9 - taurus + Иконка плагина 2012-03-09 v0.1.8 * при добавлении первой заметки таги добавляются в список * при добавлении новой заметки в поле "таги" автоматически вписывается выбранный таг * если заметки не поддерживаются сервером, записная книжка автоматически закрывается * правильно обрабатывается перемещение по списку тагов клавиатурой + при сохранении заметок выводится попап, уведомляющий об успешной операции * для таймаута попапа используется таймаут хэдлайн сообщений (раньше использовался таймаут смены статуса контакта) 2012-02-20 v0.1.7 *теперь используется правильная иконка 2011-05-12 v0.1.6 * исправлена отрисовка заметок с незаполненными полями + добавлена возможность открыть несколько окон - по одному для каждого аккаунта 2010-09-11 v0.1.4 * обновлена ссылка на wiki ( http://psi-plus.com/wiki/plugins#storage_notes_plugin ) 2010-08-19 v0.1.3 * привычное для ОС Windows расположение кнопок в окне диалога редактирования заметки + тэги располагаются по алфавиту + тэги нечувствительны к регистру + возможность перевести тэг "All Tags" 2010-05-17 v0.1.2 + добавлена информация о плагине 2010-05-04 v0.1.1 * исправлена ссылка на wiki 2010-04-06 v0.1.0 * исправлено падение приложения при выходе из блокнота по клавише escape и повторной попытке запустить блокнот + добавлены запросы при выходе из блокнота и при перезагрузке заметок в случае, если есть несохраненные изменения 2010-03-19 v0.0.9 * исправлено сохранение заметок с некоторыми спецсимволами 2010-03-11 v0.0.8 * обновлены иконки 2010-03-10 v0.0.7 * исправлено бесполезное появление горизонтального скролла в списке заметок 2010-03-04 v0.0.6 * исправлена работа фильтра тэгов + в заголовок окна добавлен jid аккаунта, для которого открыты заметки + при открытом окне заметок вызов плагина из меню аккаунта перезагружает заметки * различные оптимизации кода 2010-03-04 v0.0.5 - удалена возможность запуска заметок из настроек плагина * исправлено удаление/добавление тэгов при редактировании заметок * исправлена фильтрация заметок по тэгам * исправлено отображение тэгов после перезагрузки заметок * списки тэгов и заметок поменяны местами 2010-02-24 v0.0.4 * переименовано окно редактора заметок + по даблклику на заметке открывается редактор заметок 2010-02-23 v0.0.3 + добавлена кнопка "свернуть" в окне редактирования заметки * исправлено сохранение отредактированной заметки если открыть несколько редакторов * уменьшены размеры главного окна * более корректное отключение плагина * совместимость с последней ревизией psi+ 2010-02-22 v0.0.2 * исправлена ссылка на вики в настройках плагина + добавлена кнопка "свернуть" в окне заметок + добавлен пункт меню для быстрого вызова заметок в меню аккаунта 2010-02-22 v0.0.1 ! initial version Данный плагин представляет собой реализацию XEP-0049 - Private XML Storage. Плагин полностью совместим с заметками, сохранёнными из клиента Miranda IM. Предназначен для хранения заметок на jabber-сервере, с возможностью доступа к ним из любого места через клиент Psi+ или Miranda IM. plugins-1.5/generic/storagenotesplugin/editnote.cpp000066400000000000000000000037571336777360500227640ustar00rootroot00000000000000/* * editnote.cpp - plugin * Copyright (C) 2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "editnote.h" EditNote::EditNote( QWidget *parent, const QString& tags, const QString& title, const QString& text, const QModelIndex& index) : QDialog(parent) , index_(index) { setAttribute(Qt::WA_DeleteOnClose); setModal(false); ui_.setupUi(this); ui_.le_title->setText(title); ui_.le_tags->setText(tags); ui_.pte_text->insertPlainText(text); connect(ui_.buttonBox, SIGNAL(accepted()), this, SLOT(ok())); connect(ui_.buttonBox, SIGNAL(rejected()), this, SLOT(close())); } EditNote::~EditNote() { } void EditNote::ok() { QString text = ui_.pte_text->toPlainText(); QString title = ui_.le_title->text(); QString tags = ui_.le_tags->text(); QDomDocument doc; QDomElement noteElem = doc.createElement("note"); QDomElement titleElem = doc.createElement("title"); QDomElement textElem = doc.createElement("text"); textElem.appendChild(doc.createTextNode(text)); titleElem.appendChild(doc.createTextNode(title)); noteElem.setAttribute("tags", tags); noteElem.appendChild(titleElem); noteElem.appendChild(textElem); doc.appendChild(noteElem); if(!text.isEmpty() || !title.isEmpty() || !tags.isEmpty()) newNote(doc.documentElement()); editNote(doc.documentElement(), index_); close(); } plugins-1.5/generic/storagenotesplugin/editnote.h000066400000000000000000000025171336777360500224220ustar00rootroot00000000000000/* * editnote.h - plugin * Copyright (C) 2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef EDITNOTE_H #define EDITNOTE_H #include "ui_editnote.h" #include #include class EditNote : public QDialog { Q_OBJECT public: EditNote( QWidget *parent = 0, const QString& tags = "", const QString& title = "", const QString& text = "", const QModelIndex& index = QModelIndex()); ~EditNote(); private: Ui::EditNote ui_; QModelIndex index_; signals: void newNote(QDomElement); void editNote(QDomElement, QModelIndex); private slots: void ok(); }; #endif // EDITNOTE_H plugins-1.5/generic/storagenotesplugin/editnote.ui000066400000000000000000000025701336777360500226070ustar00rootroot00000000000000 EditNote 0 0 261 304 Edit Note Title: Tags: QDialogButtonBox::Cancel|QDialogButtonBox::Ok plugins-1.5/generic/storagenotesplugin/notes.cpp000066400000000000000000000171411336777360500222710ustar00rootroot00000000000000/* * notes.cpp - plugin * Copyright (C) 2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "notes.h" #include "editnote.h" #include "notesviewdelegate.h" #include "storagenotesplugin.h" #include Notes::Notes(StorageNotesPlugin *storageNotes, int acc, QWidget *parent) : QDialog(parent, Qt::Window) , account_(acc) , storageNotes_(storageNotes) , tagModel_(new TagModel(this)) , noteModel_(new NoteModel(this)) , proxyModel_(new ProxyModel(this)) , updateTagsTimer_(new QTimer(this)) , newNotes(false) , waitForSave(false) { setModal(false); ui_.setupUi(this); setWindowTitle(tr("Notebook") + " - " + storageNotes_->accInfo->getJid(account_)); setWindowIcon(storageNotes_->iconHost->getIcon("storagenotes/storagenotes")); ui_.pb_add->setIcon(storageNotes_->iconHost->getIcon("psi/action_templates_edit")); ui_.pb_delete->setIcon(storageNotes_->iconHost->getIcon("psi/remove")); ui_.pb_edit->setIcon(storageNotes_->iconHost->getIcon("psi/options")); ui_.pb_load->setIcon(storageNotes_->iconHost->getIcon("psi/reload")); ui_.pb_save->setIcon(storageNotes_->iconHost->getIcon("psi/save")); ui_.pb_close->setIcon(storageNotes_->iconHost->getIcon("psi/cancel")); ui_.tv_tags->setModel(tagModel_); proxyModel_->setSourceModel(noteModel_); ui_.lv_notes->setResizeMode(QListView::Adjust); ui_.lv_notes->setItemDelegate(new NotesViewDelegate(this)); ui_.lv_notes->setModel(proxyModel_); connect(ui_.tv_tags, SIGNAL(clicked(QModelIndex)), this, SLOT(selectTag())); connect(ui_.lv_notes, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(edit())); connect(ui_.pb_save, SIGNAL(released()), this, SLOT(save())); connect(ui_.pb_close, SIGNAL(released()), this, SLOT(close())); connect(ui_.pb_load, SIGNAL(released()), this, SLOT(load())); connect(ui_.pb_add, SIGNAL(released()), this, SLOT(add())); connect(ui_.pb_delete, SIGNAL(released()), this, SLOT(del())); connect(ui_.pb_edit, SIGNAL(released()), this, SLOT(edit())); ui_.tv_tags->installEventFilter(this); updateTagsTimer_->setSingleShot(true); updateTagsTimer_->setInterval(100); connect(updateTagsTimer_, SIGNAL(timeout()), this, SLOT(updateTags())); } Notes::~Notes() { } void Notes::closeEvent(QCloseEvent *e) { if(newNotes) { int rez = QMessageBox::question(this, tr("Notebook"), tr("Some changes are not saved. Are you sure you want to quit?"), QMessageBox::Ok | QMessageBox::Cancel); if(rez == QMessageBox::Cancel) { e->ignore(); return; } } emit notesDeleted(account_); e->ignore(); } void Notes::keyPressEvent(QKeyEvent *e) { if(e->key() == Qt::Key_Escape) { e->ignore(); close(); } else { QDialog::keyPressEvent(e); e->accept(); } } bool Notes::eventFilter(QObject *obj, QEvent *e) { if(obj == ui_.tv_tags && e->type() == QEvent::KeyPress) { QTimer::singleShot(0, this, SLOT(selectTag())); } return QDialog::eventFilter(obj, e); } void Notes::save() { QList notesList = noteModel_->getAllNotes(); QString notes; foreach(const QDomElement& note, notesList) { QString tag = note.attribute("tags"); QString text = note.firstChildElement("text").text(); QString title = note.firstChildElement("title").text(); tag = replaceSymbols(tag); text = replaceSymbols(text); title = replaceSymbols(title); notes+=QString("%2%3") .arg(tag) .arg(title) .arg(text); } QString xml = QString("%1") .arg(notes) .arg(NOTES_ID); storageNotes_->stanzaSender->sendStanza(account_, xml); newNotes = false; waitForSave = true; } void Notes::add() { QString tag = ui_.tv_tags->currentIndex().data(Qt::DisplayRole).toString(); if(tag == TagModel::allTagsName()) tag = QString(); EditNote *editNote = new EditNote(this, tag); connect(editNote, SIGNAL(newNote(QDomElement)), this, SLOT(addNote(QDomElement))); editNote->show(); newNotes = true; } void Notes::del() { noteModel_->delNote(proxyModel_->mapToSource(ui_.lv_notes->currentIndex())); updateTagsTimer_->start(); newNotes = true; } void Notes::updateTags() { QStringList tags = noteModel_->getAllTags(); QString currentTag = ui_.tv_tags->currentIndex().data(Qt::DisplayRole).toString(); tagModel_->clear(); foreach(const QString& tag, tags) { if(!tag.isEmpty()) tagModel_->addTag(tag); } QModelIndex ind = tagModel_->indexByTag(currentTag); if(ind.isValid()) ui_.tv_tags->setCurrentIndex(tagModel_->indexByTag(currentTag)); else ui_.tv_tags->setCurrentIndex(tagModel_->index(0)); selectTag(); ui_.tv_tags->expandToDepth(2); } void Notes::edit() { QModelIndex index = proxyModel_->mapToSource(ui_.lv_notes->currentIndex()); if(!index.isValid()) return; QString text = index.data(NoteModel::NoteRole).toString(); QString title = index.data(NoteModel::TitleRole).toString(); QString tags = index.data(NoteModel::TagRole).toString(); EditNote *editNote = new EditNote( this, tags, title, text, index); connect(editNote, SIGNAL(editNote(QDomElement, QModelIndex)), this, SLOT(noteEdited(QDomElement, QModelIndex))); editNote->show(); } void Notes::noteEdited(const QDomElement& note, const QModelIndex& index) { noteModel_->editNote(note, index); updateTagsTimer_->start(); newNotes = true; } void Notes::load() { if(storageNotes_->accInfo->getStatus(account_) == "offline") return; if(newNotes) { int rez = QMessageBox::question(this, tr("Notebook"), tr("Some changes are not saved. Are you sure you want to continue?"), QMessageBox::Ok | QMessageBox::Cancel); if(rez == QMessageBox::Cancel) { return; } } tagModel_->clear(); ui_.tv_tags->setCurrentIndex(tagModel_->index(0)); selectTag(); noteModel_->clear(); QString str = QString("") .arg(NOTES_ID).arg("http://miranda-im.org/storage#notes"); storageNotes_->stanzaSender->sendStanza(account_, str); newNotes = false; } void Notes::incomingNotes(const QList& notes) { foreach(const QDomElement& note, notes) { addNote(note); } } void Notes::addNote(const QDomElement& note) { QString tag = note.attribute("tags"); noteModel_->addNote(note); updateTagsTimer_->start(); } void Notes::selectTag() { proxyModel_->setFilterFixedString(ui_.tv_tags->currentIndex().data(Qt::DisplayRole).toString()); } void Notes::error() { storageNotes_->popup->initPopup(tr("Error! Perhaps the function is not implemented on the server."), tr("Storage Notes Plugin"), "storagenotes/storagenotes", 7); // 7 - AlertHeadline close(); } void Notes::saved() { if(!waitForSave) return; storageNotes_->popup->initPopup(tr("Notes has been saved."), tr("Storage Notes Plugin"), "storagenotes/storagenotes", 7); // 7 - AlertHeadline waitForSave = false; } QString Notes::replaceSymbols(const QString& str) { return storageNotes_->stanzaSender->escape(str); } plugins-1.5/generic/storagenotesplugin/notes.h000066400000000000000000000035551336777360500217420ustar00rootroot00000000000000/* * notes.h - plugin * Copyright (C) 2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef NOTES_H #define NOTES_H #include "ui_notes.h" #include "tagsmodel.h" #include class StorageNotesPlugin; class QTimer; class Notes : public QDialog { Q_OBJECT public: Notes(StorageNotesPlugin *storageNotes, int acc, QWidget *parent = 0); ~Notes(); void incomingNotes(const QList& notes); void error(); void saved(); private: QString replaceSymbols(const QString& str); signals: void notesDeleted(int); public slots: void load(); private slots: void save(); void add(); void del(); void edit(); void addNote(const QDomElement& note); void noteEdited(const QDomElement& note, const QModelIndex& index); void selectTag(); void updateTags(); protected: void closeEvent(QCloseEvent * event); void keyPressEvent(QKeyEvent *e); bool eventFilter(QObject *obj, QEvent *e); private: Ui::Notes ui_; int account_; StorageNotesPlugin *storageNotes_; TagModel *tagModel_; NoteModel *noteModel_; ProxyModel *proxyModel_; QTimer* updateTagsTimer_; bool newNotes; bool waitForSave; }; #endif // NOTES_H plugins-1.5/generic/storagenotesplugin/notes.ui000066400000000000000000000103451336777360500221230ustar00rootroot00000000000000 Notes 0 0 700 500 Notebook 16777215 16777215 150 16777215 0 false false false false false 24 24 Add note 24 24 Edit note 24 24 Delete note Qt::Horizontal 40 20 Qt::Horizontal 40 20 Load notes Reload Save notes Save Close window Close plugins-1.5/generic/storagenotesplugin/notescontroller.cpp000066400000000000000000000042061336777360500243730ustar00rootroot00000000000000/* * notescontroller.cpp - plugin * Copyright (C) 2011 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "notescontroller.h" #include "notes.h" NotesController::NotesController(StorageNotesPlugin* plugin) : QObject(0) , plugin_(plugin) { } NotesController::~NotesController() { foreach(Notes* n, notesList_.values()) { delete n; n = 0; } notesList_.clear(); } void NotesController::incomingNotes(int account, const QList& notes) { if(notesList_.contains(account)) { Notes* note = notesList_.value(account); if(note) note->incomingNotes(notes); } } void NotesController::start(int account) { QPointer note = 0; if(notesList_.contains(account)) { note = notesList_.value(account); } if(note) { note->load(); note->raise(); } else { note = new Notes(plugin_, account); connect(note, SIGNAL(notesDeleted(int)), this, SLOT(notesDeleted(int))); notesList_.insert(account, note); note->load(); note->show(); } } void NotesController::error(int account) { if(notesList_.contains(account)) { Notes* note = notesList_.value(account); if(note) note->error(); } } void NotesController::saved(int account) { if(notesList_.contains(account)) { Notes* note = notesList_.value(account); if(note) note->saved(); } } void NotesController::notesDeleted(int account) { if(notesList_.contains(account)) { Notes* note = notesList_.value(account); note->deleteLater(); notesList_.remove(account); } } plugins-1.5/generic/storagenotesplugin/notescontroller.h000066400000000000000000000025531336777360500240430ustar00rootroot00000000000000/* * notescontroller.h - plugin * Copyright (C) 2011 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef NOTESCONTROLLER_H #define NOTESCONTROLLER_H #include #include class QDomElement; class StorageNotesPlugin; class Notes; class NotesController : public QObject { Q_OBJECT public: NotesController(StorageNotesPlugin* plugin); ~NotesController(); void incomingNotes(int account, const QList& notes); void start(int account); void error(int account); void saved(int account); private slots: void notesDeleted(int account); private: QHash > notesList_; StorageNotesPlugin* plugin_; }; #endif // NOTESCONTROLLER_H plugins-1.5/generic/storagenotesplugin/notesviewdelegate.cpp000066400000000000000000000055311336777360500246570ustar00rootroot00000000000000/* * notesviewdelegate.cpp - plugin * Copyright (C) 2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "notesviewdelegate.h" #include "tagsmodel.h" NotesViewDelegate::~NotesViewDelegate() { } QSize NotesViewDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const { if(index.isValid()) { QSize size = QItemDelegate::sizeHint(option, index); size.setWidth(size.width()/2); return size; } return QSize(0, 0); } void NotesViewDelegate::paint ( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const { const QRect rect = option.rect; const QString text = index.data(NoteModel::NoteRole).toString(); const QString title = index.data(NoteModel::TitleRole).toString(); const QString tags = index.data(NoteModel::TagRole).toString(); painter->save(); QPalette palette = option.palette; QColor c = (option.state & QStyle::State_Selected) ? palette.color(QPalette::Highlight) : palette.color(QPalette::Base); painter->fillRect(rect, c); QPalette::ColorGroup cg = option.state & QStyle::State_Enabled ? QPalette::Normal : QPalette::Disabled; if (option.state & QStyle::State_Selected) { painter->setPen(palette.color(cg, QPalette::HighlightedText)); } else { painter->setPen(palette.color(cg, QPalette::Text)); } QRect r(rect); const QFontMetrics fm = option.fontMetrics; QFont font = option.font; if(!title.isEmpty()) { r.setHeight(fm.height()); font.setBold(true); painter->setFont(font); painter->drawText(r, Qt::AlignLeft, title); r.moveTo(r.bottomLeft()); } if(!tags.isEmpty()) { r.setHeight(fm.height()); font.setBold(false); font.setItalic(true); font.setUnderline(true); painter->setFont(font); painter->drawText(r, Qt::AlignLeft, tags); r.moveTo(r.bottomLeft()); } if(!title.isEmpty() || !tags.isEmpty()) { r.setBottom(rect.bottom()); } font.setBold(false); font.setItalic(false); font.setUnderline(false); painter->setFont(font); painter->drawText(r, Qt::AlignLeft, text); painter->drawLine(rect.topRight(), rect.topLeft()); painter->drawLine(rect.bottomRight(), rect.bottomLeft()); painter->restore(); } plugins-1.5/generic/storagenotesplugin/notesviewdelegate.h000066400000000000000000000026711336777360500243260ustar00rootroot00000000000000/* * notesviewdelegate.h - plugin * Copyright (C) 2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef NOTESVIEWDELEGATE_H #define NOTESVIEWDELEGATE_H #include #include class NotesViewDelegate : public QItemDelegate { Q_OBJECT public: NotesViewDelegate(QObject * parent = 0) : QItemDelegate(parent) {} ~NotesViewDelegate(); virtual QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const; virtual void drawDisplay(QPainter * /*painter*/, const QStyleOptionViewItem & /*option*/, const QRect & /*rect*/, const QString & /*text*/) const {} void paint ( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const; }; #endif // NOTESVIEWDELEGATE_H plugins-1.5/generic/storagenotesplugin/storagenotes.png000066400000000000000000000032171336777360500236570ustar00rootroot00000000000000PNG  IHDRaiCCPICC ProfilexTkA6n"Zkx"IYhE6bk Ed3In6&*Ezd/JZE(ޫ(b-nL~7}ov r4 Ril|Bj A4%UN$As{z[V{wwҶ@G*q Y<ߡ)t9Nyx+=Y"|@5-MS%@H8qR>׋infObN~N>! ?F?aĆ=5`5_M'Tq. VJp8dasZHOLn}&wVQygE0  HPEaP@<14r?#{2u$jtbDA{6=Q<("qCA*Oy\V;噹sM^|vWGyz?W15s-_̗)UKuZ17ߟl;=..s7VgjHUO^gc)1&v!.K `m)m$``/]?[xF QT*d4o(/lșmSqens}nk~8X<R5 vz)Ӗ9R,bRPCRR%eKUbvؙn9BħJeRR~NցoEx pHYs  GIDAT8MKh\e1d&3IdT R R7mBUZԅ؅ ]>"6 * j-ĦDR6Cv&Lf&3Es9_xbl6%'F7šqir5//,q S8e9Xv+S2POyjd5JxضKaSo4hzB!znI0\zhJqM !am:Bׂ1*MJ}:CJ/dH'RVhlZ${< r-Yrm Vd(llQ6_r:_X1Kfxţ7Er|  Rɫ.vlٌk)o3p}{B%"NfP7n~_S}TZSlvA,#up|4Idz4GJ$ /RJMǕyK.xrw*Z*voNl^===$=zzbt*rU7 ]dp s[b tTj(:T1 <fy"~aUm*\XK} xK<&0_0" ZhuEVVʽw4-IKXNi}VtD";0l]f#^WZxJN]b\zDO׮# "T jO]Hd t\ÁLIMit4$[HIGȮWόEF4΍[OHIENDB`plugins-1.5/generic/storagenotesplugin/storagenotesplugin.cpp000066400000000000000000000107721336777360500251000ustar00rootroot00000000000000/* * storagenotesplugin.cpp - plugin * Copyright (C) 2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "storagenotesplugin.h" #include "notescontroller.h" #include #include #include #include StorageNotesPlugin::StorageNotesPlugin() : stanzaSender(0) , iconHost(0) , accInfo(0) , popup(0) , enabled(false) , controller_(0) { } QString StorageNotesPlugin::name() const { return "Storage Notes Plugin"; } QString StorageNotesPlugin::shortName() const { return "storagenotes"; } QString StorageNotesPlugin::version() const { return constVersion; } bool StorageNotesPlugin::enable() { enabled = true; QFile file(":/storagenotes/storagenotes.png"); file.open(QIODevice::ReadOnly); QByteArray image = file.readAll(); iconHost->addIcon("storagenotes/storagenotes",image); file.close(); controller_ = new NotesController(this); return enabled; } bool StorageNotesPlugin::disable() { delete controller_; controller_ = 0; enabled = false; return true; } QWidget* StorageNotesPlugin::options() { if (!enabled) { return 0; } QWidget *optionsWid = new QWidget(); QVBoxLayout *vbox= new QVBoxLayout(optionsWid); QLabel *wikiLink = new QLabel(tr("Wiki (Online)"),optionsWid); wikiLink->setOpenExternalLinks(true); vbox->addWidget(wikiLink); vbox->addStretch(); return optionsWid; } bool StorageNotesPlugin::incomingStanza(int account, const QDomElement& xml) { if(!enabled) return false; if(xml.tagName() == "iq" && xml.attribute("id") == NOTES_ID) { if(xml.attribute("type") == "error") { controller_->error(account); } else if(xml.attribute("type") == "result") { QList notes; QDomNodeList noteList = xml.elementsByTagName("note"); for(int i = 0; i < noteList.size(); i++) notes.append(noteList.at(i).toElement()); if(!notes.isEmpty()) { controller_->incomingNotes(account, notes); } else { controller_->saved(account); } } return true; } return false; } bool StorageNotesPlugin::outgoingStanza(int/* account*/, QDomElement& /*xml*/) { return false; } void StorageNotesPlugin::setAccountInfoAccessingHost(AccountInfoAccessingHost* host) { accInfo = host; } void StorageNotesPlugin::setIconFactoryAccessingHost(IconFactoryAccessingHost* host) { iconHost = host; } void StorageNotesPlugin::setStanzaSendingHost(StanzaSendingHost *host) { stanzaSender = host; } void StorageNotesPlugin::setPopupAccessingHost(PopupAccessingHost* host) { popup = host; } void StorageNotesPlugin::start() { if(!enabled) return; int acc = sender()->property("account").toInt(); controller_->start(acc); } QList < QVariantHash > StorageNotesPlugin::getAccountMenuParam() { QVariantHash hash; hash["icon"] = QVariant(QString("storagenotes/storagenotes")); hash["name"] = QVariant(tr("Storage Notes")); hash["reciver"] = qVariantFromValue(qobject_cast(this)); hash["slot"] = QVariant(SLOT(start())); QList< QVariantHash > l; l.push_back(hash); return l; } QList < QVariantHash > StorageNotesPlugin::getContactMenuParam() { return QList < QVariantHash >(); } QString StorageNotesPlugin::pluginInfo() { return tr("Author: ") + "Dealer_WeARE\n" + tr("Email: ") + "wadealer@gmail.com\n\n" + trUtf8("This plugin is an implementation of XEP-0049: Private XML Storage.\n" "The plugin is fully compatible with notes saved using Miranda IM.\n" "The plugin is designed to keep notes on the jabber server with the ability to access them from anywhere using Psi+ or Miranda IM."); } QPixmap StorageNotesPlugin::icon() const { return QPixmap(":/storagenotes/storagenotes.png"); } #ifndef HAVE_QT5 Q_EXPORT_PLUGIN(StorageNotesPlugin) #endif plugins-1.5/generic/storagenotesplugin/storagenotesplugin.h000066400000000000000000000062241336777360500245420ustar00rootroot00000000000000/* * storagenotesplugin.h - plugin * Copyright (C) 2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef STORAGENOTESPLUGIN_H #define STORAGENOTESPLUGIN_H class QAction; class QDomElement; #include "psiplugin.h" #include "iconfactoryaccessor.h" #include "iconfactoryaccessinghost.h" #include "stanzasender.h" #include "stanzasendinghost.h" #include "accountinfoaccessinghost.h" #include "accountinfoaccessor.h" #include "stanzafilter.h" #include "popupaccessor.h" #include "popupaccessinghost.h" #include "menuaccessor.h" #include "plugininfoprovider.h" class NotesController; class Notes; #define constVersion "0.1.9" #define NOTES_ID "strnotes_1" class StorageNotesPlugin : public QObject, public PsiPlugin, public StanzaSender, public IconFactoryAccessor, public PluginInfoProvider, public AccountInfoAccessor, public StanzaFilter, public PopupAccessor, public MenuAccessor { Q_OBJECT #ifdef HAVE_QT5 Q_PLUGIN_METADATA(IID "com.psi-plus.StorageNotesPlugin") #endif Q_INTERFACES(PsiPlugin StanzaSender IconFactoryAccessor AccountInfoAccessor StanzaFilter PopupAccessor MenuAccessor PluginInfoProvider) public: StorageNotesPlugin(); virtual QString name() const; virtual QString shortName() const; virtual QString version() const; virtual QWidget* options(); virtual bool enable(); virtual bool disable(); virtual void applyOptions() {} virtual void restoreOptions() {} virtual void setIconFactoryAccessingHost(IconFactoryAccessingHost* host); virtual void setStanzaSendingHost(StanzaSendingHost *host); virtual void setAccountInfoAccessingHost(AccountInfoAccessingHost* host); virtual bool incomingStanza(int account, const QDomElement& xml); virtual bool outgoingStanza(int account, QDomElement& xml); virtual void setPopupAccessingHost(PopupAccessingHost* host); virtual QList < QVariantHash > getAccountMenuParam(); virtual QList < QVariantHash > getContactMenuParam(); virtual QAction* getContactAction(QObject* , int , const QString& ) { return 0; } virtual QAction* getAccountAction(QObject* , int ) { return 0; } virtual QString pluginInfo(); virtual QPixmap icon() const; private slots: void start(); private: StanzaSendingHost* stanzaSender; IconFactoryAccessingHost* iconHost; AccountInfoAccessingHost* accInfo; PopupAccessingHost* popup; bool enabled; NotesController* controller_; friend class Notes; }; #endif // STORAGENOTESPLUGIN_H plugins-1.5/generic/storagenotesplugin/storagenotesplugin.pro000066400000000000000000000007131336777360500251100ustar00rootroot00000000000000isEmpty(PSISDK) { include(../../psiplugin.pri) } else { include($$PSISDK/plugins/psiplugin.pri) } SOURCES += storagenotesplugin.cpp \ notes.cpp \ editnote.cpp \ tagsmodel.cpp \ notesviewdelegate.cpp \ notescontroller.cpp FORMS += notes.ui \ editnote.ui HEADERS += notes.h \ editnote.h \ storagenotesplugin.h \ tagsmodel.h \ notesviewdelegate.h \ notescontroller.h RESOURCES += \ storagenotesplugin.qrc plugins-1.5/generic/storagenotesplugin/storagenotesplugin.qrc000066400000000000000000000001531336777360500250730ustar00rootroot00000000000000 storagenotes.png plugins-1.5/generic/storagenotesplugin/tagsmodel.cpp000066400000000000000000000140031336777360500231120ustar00rootroot00000000000000/* * tagsmodel.cpp - plugin * Copyright (C) 2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include #include "tagsmodel.h" static const QString allTags = QObject::tr("All Tags"); TagModel::TagModel(QObject *parent) : QAbstractItemModel(parent) { stringList.clear(); pIndex = createIndex(0, 0, -1); } int TagModel::rowCount(const QModelIndex &parent) const { if(parent == QModelIndex()) return 1; else if(parent == createAllTagsIndex()) return stringList.count(); return 0; } QVariant TagModel::headerData(int /*section*/, Qt::Orientation /*orientation*/, int /*role*/) const { return QVariant(); } QModelIndex TagModel::index(int row, int column, const QModelIndex& parent) const { if(row > stringList.size() || column != 0) return QModelIndex(); if(parent == QModelIndex()) { if(row == 0) return createAllTagsIndex(); else return QModelIndex(); } else if(parent == createAllTagsIndex()) return createIndex(row, column, row); return QModelIndex(); } QModelIndex TagModel::parent(const QModelIndex& index) const { if(!index.isValid()) return QModelIndex(); if(index.internalId() == (quintptr)-1) return QModelIndex(); if((quintptr)index.row() == index.internalId()) return createAllTagsIndex(); return QModelIndex(); } QVariant TagModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); if (role != Qt::DisplayRole) return QVariant(); if(index.internalId() == (quintptr)-1) return allTags; if (index.row() >= stringList.size() || (quintptr)index.row() != index.internalId()) return QVariant(); return stringList.at(index.row()); } void TagModel::addTag(const QString& tag_) { const QString tag = tag_.toLower(); if(stringList.contains(tag)) return; beginInsertRows(createAllTagsIndex(), stringList.size(), stringList.size()); stringList.append(tag); stringList.sort(); endInsertRows(); } void TagModel::removeTag(const QString& tag_) { const QString tag = tag_.toLower(); int i = stringList.indexOf(tag); if(i == -1) return; beginRemoveRows(QModelIndex(), i, i); stringList.removeAt(i); endRemoveRows(); } void TagModel::clear() { beginResetModel(); stringList.clear(); endResetModel(); } QModelIndex TagModel::indexByTag(const QString& tag) const { int row = stringList.indexOf(tag); if(row == -1) return QModelIndex(); return index(row,0, createAllTagsIndex()); } QModelIndex TagModel::createAllTagsIndex() const { return pIndex; } QString TagModel::allTagsName() { return allTags; } ////--------NoteModel--------------------- NoteModel::NoteModel(QObject *parent) : QAbstractListModel(parent) { } int NoteModel::rowCount(const QModelIndex &/*parent*/) const { return notesList.count(); } QVariant NoteModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); if (index.row() >= notesList.size()) return QVariant(); if(role == Qt::DisplayRole){ QDomElement note = notesList.at(index.row()); QString textNote; QString tag = note.attribute("tags"); QString text = note.firstChildElement("text").text(); QString title = note.firstChildElement("title").text(); if(!title.isEmpty()) textNote += tr("Title: %1").arg(title); if(!tag.isEmpty()) textNote += tr("\nTags: %1").arg(tag); if(!text.isEmpty()) textNote += "\n"+text; return textNote.isEmpty() ? QVariant() : QVariant(textNote); } else if (role == NoteRole) { QDomElement note = notesList.at(index.row()); return QVariant(note.firstChildElement("text").text()); } else if(role == TagRole) { QDomElement note = notesList.at(index.row()); return QVariant(note.attribute("tags")); } else if(role == TitleRole) { QDomElement note = notesList.at(index.row()); return QVariant(note.firstChildElement("title").text()); } else return QVariant(); } void NoteModel::clear() { beginResetModel(); notesList.clear(); endResetModel(); } void NoteModel::editNote(const QDomElement& note, const QModelIndex &index) { delNote(index); insertNote(note, index); } void NoteModel::addNote(const QDomElement& note) { beginInsertRows(QModelIndex(), notesList.size(), notesList.size()); notesList.append(note); endInsertRows(); } void NoteModel::insertNote(const QDomElement& note, const QModelIndex &index) { if (!index.isValid()) return; beginInsertRows(QModelIndex(), index.row(), index.row()); notesList.insert(index.row(), note); endInsertRows(); } void NoteModel::delNote(const QModelIndex &index) { if (!index.isValid()) return; if (index.row() >= notesList.size()) return; beginRemoveRows(QModelIndex(), index.row(), index.row()); notesList.removeAt(index.row()); endRemoveRows(); } QList NoteModel::getAllNotes() const { return notesList; } QStringList NoteModel::getAllTags() const { QStringList tagsList; foreach(const QDomElement& note, notesList) { QStringList tags = note.attribute("tags").split(" ", QString::SkipEmptyParts); tagsList += tags; } return tagsList; } /////-------------ProxyModel--------------- bool ProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &parent) const { QModelIndex index = sourceModel()->index(sourceRow, 0, parent); QString filter = filterRegExp().pattern(); if(allTags.contains(filter)) return true; QStringList tags = index.data(NoteModel::TagRole).toString().split(" "); return tags.contains(filter, Qt::CaseInsensitive); } plugins-1.5/generic/storagenotesplugin/tagsmodel.h000066400000000000000000000052111336777360500225600ustar00rootroot00000000000000/* * tagsmodel.h - plugin * Copyright (C) 2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef TAGSMODEL_H #define TAGSMODEL_H #include #include #include #include class TagModel : public QAbstractItemModel { Q_OBJECT public: TagModel(QObject *parent = 0); int rowCount(const QModelIndex &parent = QModelIndex()) const; int columnCount(const QModelIndex &/*parent*/ = QModelIndex()) const { return 1; } QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; QModelIndex index(int row, int column = 0, const QModelIndex& parent = QModelIndex()) const; QModelIndex parent(const QModelIndex& index) const; QVariant data(const QModelIndex &index, int role) const; void addTag(const QString& tag); void removeTag(const QString& tag); void clear(); QModelIndex indexByTag(const QString& tag) const; static QString allTagsName(); private: QModelIndex createAllTagsIndex() const; QStringList stringList; QModelIndex pIndex; }; class NoteModel : public QAbstractListModel { Q_OBJECT public: enum RoleType { NoteRole = Qt::DisplayRole + 1, TagRole = Qt::DisplayRole + 2, TitleRole = Qt::DisplayRole + 3 }; NoteModel(QObject *parent = 0); int rowCount(const QModelIndex &parent = QModelIndex()) const; QVariant data(const QModelIndex &index, int role) const; void clear(); void addNote(const QDomElement& note); void delNote(const QModelIndex &index); void insertNote(const QDomElement& note, const QModelIndex &index); void editNote(const QDomElement& note, const QModelIndex &index); QList getAllNotes() const; QStringList getAllTags() const; private: QList notesList; }; class ProxyModel : public QSortFilterProxyModel { Q_OBJECT public: ProxyModel(QObject *parent = 0) : QSortFilterProxyModel(parent) {} bool filterAcceptsRow(int sourceRow, const QModelIndex &parent) const; }; #endif // TAGSMODEL_H plugins-1.5/generic/translateplugin/000077500000000000000000000000001336777360500177115ustar00rootroot00000000000000plugins-1.5/generic/translateplugin/CMakeLists.txt000066400000000000000000000024151336777360500224530ustar00rootroot00000000000000unset(_HDRS) unset(_UIS) unset(_SRCS) unset(_RSCS) unset(PLUGIN) set( PLUGIN translateplugin ) project(${PLUGIN}) cmake_minimum_required(VERSION 3.1.0) set( CMAKE_AUTOMOC TRUE ) IF( NOT WIN32 ) set( LIB_SUFFIX "" CACHE STRING "Define suffix of directory name (32/64)" ) set( PLUGINS_PATH "lib${LIB_SUFFIX}/psi-plus/plugins" CACHE STRING "Install suffix for plugins" ) ELSE() set( PLUGINS_PATH "psi-plus/plugins" CACHE STRING "Install suffix for plugins" ) ENDIF() add_definitions( -DQT_PLUGIN -DHAVE_QT5 ) include_directories( ${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ../../include . ) set( _SRCS ${PLUGIN}.cpp ) set( _RSCS resources.qrc ) find_package( Qt5 COMPONENTS Widgets Xml REQUIRED ) set(QT_DEPLIBS Qt5::Widgets Qt5::Xml ) qt5_add_resources(RSCS ${_RSCS}) add_library( ${PLUGIN} MODULE ${_SRCS} ${UIS} ${RSCS} ) target_link_libraries( ${PLUGIN} ${QT_DEPLIBS} ) if( UNIX AND NOT( APPLE OR CYGWIN ) ) install( TARGETS ${PLUGIN} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} ) endif() if( WIN32 ) install( TARGETS ${PLUGIN} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} ) endif() plugins-1.5/generic/translateplugin/changelog.txt000066400000000000000000000063771336777360500224160ustar00rootroot000000000000002016-02-16 v0.4.6 * адаптация к изменениям в плагинных интерфейсах 2013-08-21 v0.4.5 - taurus * Переход на новый плагинный интерфейс доступа к табам чатов 2013-08-13 v0.4.4 - taurus + Иконка плагина 2012-03-14 v0.4.3 + если нет выделения, ссылки не переводятся 2012-02-29 v0.4.2 + опция "не перекодировать ник" работает только в конференциях * исправлен алгоритм работы !!!! если плагин был выключен и снова включен - работать будет только для вновь открытых вкладок 2012-02-28 v0.4.1 * шоткат теперь не глобальный 2011-08-03 v0.4.0 + исправлено падение плагина в случае выбора меню "плагины", если в папке с плагинами этот плаг единственный * чистка и другие исправления кода 2011-01-11 v0.3.2 * незначительные исправления кода 2010-05-17 v0.3.1 + добавлена информация о плагине 2009-08-11 v0.3.0 * переход на новый плагинный интерфейс * очередная попытка решения проблемы неправильного определения активного таба в некоторых случаях * другие незначительные правки 2009-08-09 v0.2.2 + если в строке ввода есть выделенный текст, то будет перекодироваться только он 2009-07-28 v0.2.1 * исправлено падение плагина 2009-07-28 v0.2.0 * переход на новый плагинный интерфейс 2009-07-17 v0.1.7 * незначительные исправления в окне настроек плагина 2009-07-12 v0.1.6 + добавлена таблица для перекодирования из ru в en * редактирование элемента таблицы производится внутри таблицы + добавлена кнопка "Restore Defaults Settings" 2009-07-07 v0.1.5 * очередное исправление для поиска активного таба 2009-06-30 v0.1.4 * исправлен поиск активного таба - убрана перекодировка # <-> № 2009-06-27 v0.1.3 + горячую клавишу теперь можно задать в опциях. По умолчанию - Alt+Ctrl+t 2009-06-26 v0.1.2 + перекодировка производится только в активном чате 2009-06-25 v0.1.1 * исправлено поведение плагина при его отключении * другие исправления кода для увеличения стабильности работы 2009-06-24 v0.1.0 ! initial version Данный плагин позволяет конвертировать выделенный текст в другую языковую раскладку. plugins-1.5/generic/translateplugin/resources.qrc000066400000000000000000000001411336777360500224260ustar00rootroot00000000000000 translate.png plugins-1.5/generic/translateplugin/translate.png000066400000000000000000000007371336777360500224230ustar00rootroot00000000000000PNG  IHDRatEXtSoftwareAdobe ImageReadyqe<IDATxڜSJ@Mf-殂ߡ"RЃ@mD=P C/ݬ;lbhA%3//b4}hYy?C*z$i;TOB0E%,D4@9.VN?0 QrR :VTyYL/X,>& l6#HW[vL&p9#r`JgZN)оf`r 1t an7Fܢ")e\qY :t:fNqDǯTL$gW[(uD??IENDB`plugins-1.5/generic/translateplugin/translateplugin.cpp000066400000000000000000000514021336777360500236330ustar00rootroot00000000000000/* * translateplugin.cpp - plugin * Copyright (C) 2009-2010 Kravtsov Nikolai * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "psiplugin.h" #include "shortcutaccessor.h" #include "shortcutaccessinghost.h" #include "optionaccessor.h" #include "optionaccessinghost.h" #include "activetabaccessor.h" #include "activetabaccessinghost.h" #include "plugininfoprovider.h" #include "chattabaccessor.h" #define constOld "oldsymbol" #define constNew "newsymbol" #define constShortCut "shortcut" #define constNotTranslate "nottranslate" #define constVersion "0.4.6" static const QString mucData = "groupchat"; static const QString chatData = "chat"; class TranslatePlugin : public QObject , public PsiPlugin , public OptionAccessor , public ShortcutAccessor , public ActiveTabAccessor , public PluginInfoProvider , public ChatTabAccessor { Q_OBJECT #ifdef HAVE_QT5 Q_PLUGIN_METADATA(IID "com.psi-plus.TranslatePlugin") #endif Q_INTERFACES(PsiPlugin OptionAccessor ShortcutAccessor ActiveTabAccessor PluginInfoProvider ChatTabAccessor) public: TranslatePlugin(); virtual QString name() const; virtual QString shortName() const; virtual QString version() const; virtual QWidget* options(); virtual bool enable(); virtual bool disable(); virtual void applyOptions(); virtual void restoreOptions(); // OptionAccessor virtual void setOptionAccessingHost(OptionAccessingHost* host); virtual void optionChanged(const QString& option); // ShortcutsAccessor virtual void setShortcutAccessingHost(ShortcutAccessingHost* host); virtual void setShortcuts(); //ActiveTabAccessor virtual void setActiveTabAccessingHost(ActiveTabAccessingHost* host); //Tabs virtual void setupChatTab(QWidget* tab, int account, const QString& contact); virtual void setupGCTab(QWidget* tab, int account, const QString& contact); virtual bool appendingChatMessage(int account, const QString& contact, QString& body, QDomElement& html, bool local); virtual QString pluginInfo(); virtual QPixmap icon() const; private slots: void trans(); void addToMap(); void del(); void grep(); void onNewShortcutKey(QKeySequence); void changeItem(int,int); void storeItem(QTableWidgetItem*); void restoreMap(); void hack(); void actionDestroyed(QObject* obj); private: void setupTab(QWidget* tab, const QString& data); bool enabled_; bool notTranslate; QMap map; QMap mapBackup; QTableWidget * table; QLineEdit *shortCutWidget; OptionAccessingHost* psiOptions; ShortcutAccessingHost* psiShortcuts; ActiveTabAccessingHost* activeTab; QString shortCut; QCheckBox *check_button; QString storage; QPointer options_; QList actions_; }; #ifndef HAVE_QT5 Q_EXPORT_PLUGIN(TranslatePlugin); #endif TranslatePlugin::TranslatePlugin() : enabled_(false) , notTranslate(false) , table(0) , shortCutWidget(0) , psiOptions(0) , psiShortcuts(0) , activeTab(0) , shortCut("Alt+Ctrl+t") , check_button(0) { map.insert("~",QString::fromUtf8("Ё")); map.insert(QString::fromUtf8("Ё"),"~"); map.insert("`",QString::fromUtf8("ё")); map.insert(QString::fromUtf8("ё"),"`"); map.insert("#",QString::fromUtf8("№")); map.insert(QString::fromUtf8("№"),"#"); map.insert("q",QString::fromUtf8("й")); map.insert(QString::fromUtf8("й"),"q"); map.insert("w",QString::fromUtf8("ц")); map.insert(QString::fromUtf8("ц"),"w"); map.insert("e",QString::fromUtf8("у")); map.insert(QString::fromUtf8("у"),"e"); map.insert("r",QString::fromUtf8("к")); map.insert(QString::fromUtf8("к"),"r"); map.insert("t",QString::fromUtf8("е")); map.insert(QString::fromUtf8("е"),"t"); map.insert("y",QString::fromUtf8("н")); map.insert(QString::fromUtf8("н"),"y"); map.insert("u",QString::fromUtf8("г")); map.insert(QString::fromUtf8("г"),"u"); map.insert("i",QString::fromUtf8("ш")); map.insert(QString::fromUtf8("ш"),"i"); map.insert("o",QString::fromUtf8("щ")); map.insert(QString::fromUtf8("щ"),"o"); map.insert("p",QString::fromUtf8("з")); map.insert(QString::fromUtf8("з"),"p"); map.insert("a",QString::fromUtf8("ф")); map.insert(QString::fromUtf8("ф"),"a"); map.insert("s",QString::fromUtf8("ы")); map.insert(QString::fromUtf8("ы"),"s"); map.insert("d",QString::fromUtf8("в")); map.insert(QString::fromUtf8("в"),"d"); map.insert("f",QString::fromUtf8("а")); map.insert(QString::fromUtf8("а"),"f"); map.insert("g",QString::fromUtf8("п")); map.insert(QString::fromUtf8("п"),"g"); map.insert("h",QString::fromUtf8("р")); map.insert(QString::fromUtf8("р"),"h"); map.insert("j",QString::fromUtf8("о")); map.insert(QString::fromUtf8("о"),"j"); map.insert("k",QString::fromUtf8("л")); map.insert(QString::fromUtf8("л"),"k"); map.insert("l",QString::fromUtf8("д")); map.insert(QString::fromUtf8("д"),"l"); map.insert("z",QString::fromUtf8("я")); map.insert(QString::fromUtf8("я"),"z"); map.insert("x",QString::fromUtf8("ч")); map.insert(QString::fromUtf8("ч"),"x"); map.insert("c",QString::fromUtf8("с")); map.insert(QString::fromUtf8("с"),"c"); map.insert("v",QString::fromUtf8("м")); map.insert(QString::fromUtf8("м"),"v"); map.insert("b",QString::fromUtf8("и")); map.insert(QString::fromUtf8("и"),"b"); map.insert("n",QString::fromUtf8("т")); map.insert(QString::fromUtf8("т"),"n"); map.insert("m",QString::fromUtf8("ь")); map.insert(QString::fromUtf8("ь"),"m"); map.insert("Q",QString::fromUtf8("Й")); map.insert(QString::fromUtf8("Й"),"Q"); map.insert("W",QString::fromUtf8("Ц")); map.insert(QString::fromUtf8("Ц"),"W"); map.insert("E",QString::fromUtf8("У")); map.insert(QString::fromUtf8("У"),"E"); map.insert("R",QString::fromUtf8("К")); map.insert(QString::fromUtf8("К"),"R"); map.insert("T",QString::fromUtf8("Е")); map.insert(QString::fromUtf8("Е"),"T"); map.insert("Y",QString::fromUtf8("Н")); map.insert(QString::fromUtf8("Н"),"Y"); map.insert("U",QString::fromUtf8("Г")); map.insert(QString::fromUtf8("Г"),"U"); map.insert("I",QString::fromUtf8("Ш")); map.insert(QString::fromUtf8("Ш"),"I"); map.insert("O",QString::fromUtf8("Щ")); map.insert(QString::fromUtf8("Щ"),"O"); map.insert("P",QString::fromUtf8("З")); map.insert(QString::fromUtf8("З"),"P"); map.insert("A",QString::fromUtf8("Ф")); map.insert(QString::fromUtf8("Ф"),"A"); map.insert("S",QString::fromUtf8("Ы")); map.insert(QString::fromUtf8("Ы"),"S"); map.insert("D",QString::fromUtf8("В")); map.insert(QString::fromUtf8("В"),"D"); map.insert("F",QString::fromUtf8("А")); map.insert(QString::fromUtf8("А"),"F"); map.insert("G",QString::fromUtf8("П")); map.insert(QString::fromUtf8("П"),"G"); map.insert("H",QString::fromUtf8("Р")); map.insert(QString::fromUtf8("Р"),"H"); map.insert("J",QString::fromUtf8("О")); map.insert(QString::fromUtf8("О"),"J"); map.insert("K",QString::fromUtf8("Л")); map.insert(QString::fromUtf8("Л"),"K"); map.insert("L",QString::fromUtf8("Д")); map.insert(QString::fromUtf8("Д"),"L"); map.insert("Z",QString::fromUtf8("Я")); map.insert(QString::fromUtf8("Я"),"Z"); map.insert("X",QString::fromUtf8("Ч")); map.insert(QString::fromUtf8("Ч"),"X"); map.insert("C",QString::fromUtf8("С")); map.insert(QString::fromUtf8("С"),"C"); map.insert("V",QString::fromUtf8("М")); map.insert(QString::fromUtf8("М"),"V"); map.insert("B",QString::fromUtf8("И")); map.insert(QString::fromUtf8("И"),"B"); map.insert("N",QString::fromUtf8("Т")); map.insert(QString::fromUtf8("Т"),"N"); map.insert("M",QString::fromUtf8("Ь")); map.insert(QString::fromUtf8("Ь"),"M"); map.insert("[",QString::fromUtf8("х")); map.insert(QString::fromUtf8("х"),"["); map.insert("{",QString::fromUtf8("Х")); map.insert(QString::fromUtf8("Х"),"{"); map.insert("]",QString::fromUtf8("ъ")); map.insert(QString::fromUtf8("ъ"),"]"); map.insert("}",QString::fromUtf8("Ъ")); map.insert(QString::fromUtf8("Ъ"),"}"); map.insert("$",QString::fromUtf8(";")); map.insert(QString::fromUtf8(";"),"$"); map.insert(";",QString::fromUtf8("ж")); map.insert(QString::fromUtf8("ж"),";"); map.insert("^",QString::fromUtf8(":")); map.insert(QString::fromUtf8(":"),"^"); map.insert(":",QString::fromUtf8("Ж")); map.insert(QString::fromUtf8("Ж"),":"); map.insert("'",QString::fromUtf8("э")); map.insert(QString::fromUtf8("э"),"'"); map.insert("@",QString::fromUtf8("\"")); map.insert(QString::fromUtf8("\""),"@"); map.insert("\"",QString::fromUtf8("Э")); map.insert(QString::fromUtf8("Э"),"\""); map.insert("<",QString::fromUtf8("Б")); map.insert(QString::fromUtf8("Б"),"<"); map.insert(">",QString::fromUtf8("Ю")); map.insert(QString::fromUtf8("Ю"),">"); map.insert("&",QString::fromUtf8("?")); map.insert(QString::fromUtf8("?"),"&"); map.insert("?",QString::fromUtf8(",")); map.insert(QString::fromUtf8(","),"?"); map.insert(",",QString::fromUtf8("б")); map.insert(QString::fromUtf8("б"),","); map.insert("|",QString::fromUtf8("/")); map.insert(QString::fromUtf8("/"),"|"); map.insert("/",QString::fromUtf8(".")); map.insert(QString::fromUtf8("."),"/"); map.insert(".",QString::fromUtf8("ю")); map.insert(QString::fromUtf8("ю"),"."); mapBackup = map; } QString TranslatePlugin::name() const { return "Translate Plugin"; } QString TranslatePlugin::shortName() const { return "Translate"; } QString TranslatePlugin::version() const { return constVersion; } QWidget* TranslatePlugin::options() { if (!enabled_) { return 0; } options_ = new QWidget(); table = new QTableWidget(options_); table->setColumnCount(2); QStringList header; header <setHorizontalHeaderLabels(header); table->verticalHeader()->setVisible(false); table->setTextElideMode(Qt::ElideMiddle); table->setSelectionBehavior(QAbstractItemView::SelectRows); table->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); table->setEditTriggers(QAbstractItemView::DoubleClicked); table->verticalHeader()->setDefaultSectionSize(20); table->verticalHeader()->setMinimumSectionSize(20); table->horizontalHeader()->setDefaultSectionSize(50); table->horizontalHeader()->setMinimumSectionSize(20); table->setColumnWidth(0,50); table->setColumnWidth(1,50); table->setMaximumWidth(120); QHBoxLayout *hBox = new QHBoxLayout(options_); QVBoxLayout *leftSide = new QVBoxLayout; leftSide->addWidget(table); QHBoxLayout *buttonLayout = new QHBoxLayout; QPushButton *addButton = new QPushButton(tr("Add"), options_); QPushButton *delButton = new QPushButton(tr("Delete"), options_); buttonLayout->addWidget(addButton); buttonLayout->addWidget(delButton); leftSide->addLayout(buttonLayout); hBox->addLayout(leftSide); QVBoxLayout *rightSide = new QVBoxLayout; rightSide->addWidget(new QLabel(tr("ShortCut:")),5,Qt::AlignTop); QHBoxLayout *shortBox = new QHBoxLayout; shortCutWidget = new QLineEdit(options_); shortCutWidget->setFixedWidth(100); shortCutWidget->setText(shortCut); shortCutWidget->setDisabled(true); QPushButton * modShortCut = new QPushButton(tr("Modify"), options_); shortBox->addWidget(shortCutWidget,0,Qt::AlignLeft); shortBox->addWidget(modShortCut,200,Qt::AlignLeft); rightSide->addLayout(shortBox,30); check_button = new QCheckBox(tr("Not translating \"Nickname:\""), options_); check_button->setChecked(notTranslate); check_button->setProperty("isOption",true); rightSide->addWidget(check_button,30,Qt::AlignTop); QPushButton *restoreButton = new QPushButton(tr("Restore Defaults Settings"), options_); restoreButton->setFixedWidth(220); rightSide->addWidget(restoreButton,30,Qt::AlignBottom); if (!map.isEmpty()) { foreach(QString symbol, map.keys()){ table->insertRow(table->rowCount()); table->setItem(table->rowCount()-1,0,new QTableWidgetItem(symbol)); table->setItem(table->rowCount()-1,1,new QTableWidgetItem(map.value(symbol))); } } hBox->addLayout(rightSide); connect(delButton,SIGNAL(clicked()),this,SLOT(del())); connect(addButton,SIGNAL(clicked()),this,SLOT(addToMap())); connect(modShortCut,SIGNAL(clicked()),this,SLOT(grep())); connect(restoreButton,SIGNAL(clicked()),this,SLOT(restoreMap())); connect(table,SIGNAL(cellChanged(int,int)),this,SLOT(changeItem(int,int))); connect(table,SIGNAL(itemDoubleClicked(QTableWidgetItem*)),this,SLOT(storeItem(QTableWidgetItem*))); return options_; } bool TranslatePlugin::enable() { enabled_ = true; shortCut = psiOptions->getPluginOption(constShortCut, shortCut).toString(); notTranslate = psiOptions->getPluginOption(constNotTranslate, notTranslate).toBool(); // psiShortcuts->connectShortcut(QKeySequence(shortCut),this, SLOT(trans())); foreach(QAction* act, actions_) { act->setShortcut(QKeySequence(shortCut)); } QStringList oldList = psiOptions->getPluginOption(constOld, QStringList(map.keys())).toStringList(); QStringList newList = psiOptions->getPluginOption(constNew, QStringList(map.values())).toStringList(); int iterator = 0; map.clear(); foreach(const QString& symbol, oldList){ map.insert(symbol, newList.at(iterator++)); } return true; } bool TranslatePlugin::disable() { enabled_ = false; foreach(QAction* act, actions_) { act->disconnect(this, SLOT(trans())); } // psiShortcuts->disconnectShortcut(QKeySequence(shortCut),this, SLOT(trans())); return true; } void TranslatePlugin::trans() { if(!enabled_) return; QTextEdit * ed = activeTab->getEditBox(); if (!ed) { return; } QTextCursor c = ed->textCursor(); static QRegExp link("(xmpp:|mailto:|http://|https://|ftp://|news://|ed2k://|www.|ftp.)\\S+", Qt::CaseInsensitive); QStringList newStrings; bool isMuc = false; QAction* act = dynamic_cast(sender()); if(act && act->data().toString() == mucData) isMuc = true; QString toReverse = c.selectedText(); bool isSelect = true; QString nick(""); if (toReverse.isEmpty()) { toReverse = ed->toPlainText(); if (notTranslate && isMuc) { int index = toReverse.indexOf(":") + 1; nick = toReverse.left(index); toReverse = toReverse.right(toReverse.size() - index); } isSelect = false; } if(!nick.isEmpty()) newStrings.append(nick); //запоминаем позицию курсора int pos = c.position(); int index = link.indexIn(toReverse); while(index != -1 && !isSelect) { QString newStr; QString oldStr = toReverse.left(index); foreach(const QString& symbol, oldStr) { newStr.append(map.value(symbol,symbol)); } newStrings << newStr << link.cap(); toReverse = toReverse.right(toReverse.size() - (index + link.matchedLength())); index = link.indexIn(toReverse); } QString newStr; foreach(const QString& symbol, toReverse) { newStr.append(map.value(symbol,symbol)); } newStrings << newStr; QString newString = newStrings.join(""); if (!isSelect) { ed->setPlainText(newString); //восстанавливаем позицию курсора c.setPosition( pos ); ed->setTextCursor( c ); } else { int end = c.selectionEnd(); int start = c.selectionStart(); ed->textCursor().clearSelection(); ed->textCursor().insertText(newString); c = ed->textCursor(); if (pos == start) { c.setPosition(end); c.movePosition(QTextCursor::Left, QTextCursor::KeepAnchor, end-start); } else { c.setPosition(start); c.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, end-start); } ed->setTextCursor( c ); } } void TranslatePlugin::addToMap() { if (options_) { int curRow = table->currentRow(); if (curRow == -1) { curRow = 0; } table->insertRow(curRow); table->setItem(curRow,0,new QTableWidgetItem()); table->setItem(curRow,1,new QTableWidgetItem()); hack(); } } void TranslatePlugin::setOptionAccessingHost(OptionAccessingHost* host) { psiOptions = host; } void TranslatePlugin::optionChanged(const QString& option) { Q_UNUSED(option); } void TranslatePlugin::setShortcutAccessingHost(ShortcutAccessingHost* host) { psiShortcuts = host; } void TranslatePlugin::setShortcuts() { // if (enabled_) { // psiShortcuts->connectShortcut(QKeySequence(shortCut), this, SLOT(trans())); // } } void TranslatePlugin::applyOptions() { if (!options_) return; // psiShortcuts->disconnectShortcut(QKeySequence(shortCut), this, SLOT(trans())); shortCut = shortCutWidget->text(); psiOptions->setPluginOption(constShortCut, shortCut); foreach(QAction* act, actions_) { act->setShortcut(QKeySequence(shortCut)); } // psiShortcuts->connectShortcut(QKeySequence(shortCut), this, SLOT(trans())); notTranslate = check_button->isChecked(); psiOptions->setPluginOption(constNotTranslate, notTranslate); map.clear(); int count = table->rowCount(); for (int row = 0 ; row < count; row++) { if (!table->item(row,0)->text().isEmpty() && !table->item(row,1)->text().isEmpty()) { map.insert(table->item(row,0)->text().left(1),table->item(row,1)->text()); } } psiOptions->setPluginOption(constOld, QStringList(map.keys())); psiOptions->setPluginOption(constNew, QStringList(map.values())); } void TranslatePlugin::restoreOptions() { if (!options_) return; shortCutWidget->setText(shortCut); check_button->setChecked(notTranslate); foreach(const QString& symbol, map.keys()) { table->insertRow(table->rowCount()); table->setItem(table->rowCount()-1,0,new QTableWidgetItem(symbol)); table->setItem(table->rowCount()-1,1,new QTableWidgetItem(map.value(symbol))); } } void TranslatePlugin::del() { if (table->currentRow() == -1) { return; } table->removeRow(table->currentRow()); hack(); } void TranslatePlugin::grep() { psiShortcuts->requestNewShortcut(this, SLOT(onNewShortcutKey(QKeySequence))); } void TranslatePlugin::onNewShortcutKey(QKeySequence ks) { shortCutWidget->setText(ks.toString(QKeySequence::NativeText)); } void TranslatePlugin::changeItem(int row,int column) { if (column == 0 && !storage.isEmpty()) { //если первая колонка, то её менять нельзя, возвращаем старое значение table->item(row,column)->setText(storage); } else { //иначе приравниваем ячейке значение первого символа if (table->item(row,column)->text().isEmpty()) { table->item(row,column)->setText(storage); } else { table->item(row,column)->setText(table->item(row,column)->text().left(1)); } } hack(); } void TranslatePlugin::storeItem(QTableWidgetItem* item) { storage = item->text(); } void TranslatePlugin::restoreMap() { disconnect(table,SIGNAL(cellChanged(int,int)),this,SLOT(changeItem(int,int))); table->clear(); table->setRowCount(0); foreach(const QString& symbol, mapBackup.keys()){ table->insertRow(table->rowCount()); table->setItem(table->rowCount()-1,0,new QTableWidgetItem(symbol)); table->setItem(table->rowCount()-1,1,new QTableWidgetItem(mapBackup.value(symbol))); } connect(table,SIGNAL(cellChanged(int,int)),this,SLOT(changeItem(int,int))); hack(); } void TranslatePlugin::setActiveTabAccessingHost(ActiveTabAccessingHost* host) { activeTab = host; } void TranslatePlugin::hack() { check_button->toggle(); check_button->toggle(); } void TranslatePlugin::setupTab(QWidget* tab, const QString& data) { QAction* act = new QAction(tab); tab->addAction(act); act->setData(data); act->setShortcut(QKeySequence(shortCut)); act->setShortcutContext(Qt::WindowShortcut); connect(act, SIGNAL(triggered()), SLOT(trans())); connect(act, SIGNAL(destroyed(QObject*)), SLOT(actionDestroyed(QObject*))); actions_.append(act); } void TranslatePlugin::setupChatTab(QWidget* tab, int /*account*/, const QString& /*contact*/) { setupTab(tab, chatData); } void TranslatePlugin::setupGCTab(QWidget* tab, int /*account*/, const QString& /*contact*/) { setupTab(tab, mucData); } bool TranslatePlugin::appendingChatMessage(int/* account*/, const QString &/*contact*/, QString &/*body*/, QDomElement &/*html*/, bool /*local*/) { return false; } void TranslatePlugin::actionDestroyed(QObject *obj) { QAction* act = static_cast(obj); actions_.removeAll(act); } QString TranslatePlugin::pluginInfo() { return tr("Author: ") + "VampiRUS\n\n" + trUtf8("This plugin allows you to convert selected text into another language.\n"); } QPixmap TranslatePlugin::icon() const { return QPixmap(":/icons/translate.png"); } #include "translateplugin.moc" plugins-1.5/generic/translateplugin/translateplugin.pro000066400000000000000000000002441336777360500236470ustar00rootroot00000000000000isEmpty(PSISDK) { include(../../psiplugin.pri) } else { include($$PSISDK/plugins/psiplugin.pri) } SOURCES += translateplugin.cpp RESOURCES += resources.qrc plugins-1.5/generic/videostatusplugin/000077500000000000000000000000001336777360500202665ustar00rootroot00000000000000plugins-1.5/generic/videostatusplugin/CMakeLists.txt000066400000000000000000000035561336777360500230370ustar00rootroot00000000000000unset(_HDRS) unset(_UIS) unset(_SRCS) unset(_RSCS) unset(PLUGIN) set( PLUGIN videostatusplugin ) project(${PLUGIN}) cmake_minimum_required(VERSION 3.1.0) set( CMAKE_AUTOMOC TRUE ) IF( NOT WIN32 ) set( LIB_SUFFIX "" CACHE STRING "Define suffix of directory name (32/64)" ) set( PLUGINS_PATH "lib${LIB_SUFFIX}/psi-plus/plugins" CACHE STRING "Install suffix for plugins" ) ELSE() set( PLUGINS_PATH "psi-plus/plugins" CACHE STRING "Install suffix for plugins" ) ENDIF() add_definitions( -DQT_PLUGIN -DHAVE_QT5 ) if( NOT WIN32 ) add_definitions( -Ddbus -DHAVE_DBUS ) find_package( X11 REQUIRED ) else() add_definitions( -DQ_OS_WIN ) endif() include_directories( ${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ../../include . ) if( NOT WIN32 ) set( x11_SRCS x11info.cpp ) set( x11_HDRS x11info.h ) endif() set( _SRCS ${PLUGIN}.cpp ${x11_SRCS} ) set( _UIS options.ui ) set( _RSCS resources.qrc ) find_package( Qt5 COMPONENTS Widgets Xml REQUIRED ) set(QT_DEPLIBS Qt5::Widgets Qt5::Xml ) IF( UNIX AND NOT( APPLE OR CYGWIN ) ) find_package( Qt5 COMPONENTS DBus X11Extras REQUIRED ) find_package( XCB REQUIRED ) add_definitions( -DHAVE_DBUS ) set(QT_DEPLIBS ${QT_DEPLIBS} Qt5::DBus Qt5::X11Extras ${XCB_LIBRARY} ) ENDIF() qt5_wrap_ui(UIS ${_UIS}) qt5_add_resources(RSCS ${_RSCS}) add_library( ${PLUGIN} MODULE ${_SRCS} ${UIS} ${RSCS} ) if( UNIX AND NOT( APPLE OR CYGWIN ) ) target_link_libraries( ${PLUGIN} ${X11_LIBRARIES} ${QT_DEPLIBS} ) install( TARGETS ${PLUGIN} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} ) endif() if( WIN32 ) target_link_libraries( ${PLUGIN} ${QT_DEPLIBS} ) install( TARGETS ${PLUGIN} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} ) endif() plugins-1.5/generic/videostatusplugin/changelog.txt000066400000000000000000000112751336777360500227640ustar00rootroot000000000000002018-01-14 v0.2.8 + Added SMPlayer support via DBUS (OS Linux) 2017-07-02 v0.2.7 + Fixed detection of fullscreen application in OS Windows 2015-04-22 v0.2.6 + Fixed build with Qt5 on Linux 2014-03-19 v0.2.5 + Добавлен плеер Dragon Player 2013-08-13 v0.2.4 - taurus + Иконка плагина 2012-03-14 v0.2.3 + Переделано автоматическое размещениее чекбоксов в опциях для OS Linux 2012-03-12 v0.2.2 + Небольшое исправление в работе чекбоксов для OS Linux 2012-02-23 v0.2.1 + Исправлена работа с плеером GNOME Mplayer 2012-02-23 v0.2.0 + Переделан механизм работы с плеерами для OS Linux 2012-02-22 v0.1.9 + Добавлена поддержка плеера vlc версии 2.0 2012-01-07 v0.1.8 + попытка исправить не срабатывание определения полноэкранного режима после запуска плеера vlc 2011-12-05 v0.1.7 + добавлено исключение на сборку под MacOS 2011-12-05 v0.1.6 + исключено определение композитного слоя рабочего стола OS Windows 7 2011-12-03 v0.1.5 + переделан механизм определения полноэкранного режима (OS Windows) + устранены ложные срабатывания в OS Windows 7 2011-12-01 v0.1.4 + исправлено ложное срабатывание при активном рабочем столе (OS Windows) + попытка исправить ложные срабатывания при разворачивании окон в (OS Windows) + добавлена поддержка плеера Totem для Gnome3 (Linux) 2011-11-25 v0.1.3 + оптимизация кода плагина с объединением кода в одном модуле 2011-11-25 v0.1.2 + добавлена поддержка определения полноэкранного режима для OS Windows 2011-11-03 v0.1.1 + попытка исправить падение Psi+ при определении полноэкранного режима + убраны лишние инклюды 2011-11-03 v0.1.0 + исправлена совместная работа детекта полноэкранных приложений и видео в окне + исправлена работа чекбокса "Detect full screen applications" 2011-11-02 v0.0.9 + добавлен детект полноэкранных приложений (протестировано только на Gnome + Compize) 2011-11-01 v0.0.8 * плагин практически полностью переписан * работа без таймера по которому опрашиваются плееры * работа с плеерами начинается непосредственно при их запуске * проверка статусов видеоплееров MPRIS происходит при помощи сигналов * Gnome Mplayer порверяется по старому алгоритму 2011-05-25 v0.0.7 * добавлен таймер на установку статуса после начала проигрывания * увеличен интервал таймеров на установку и возвращение статуса до 300 сек 2010-09-11 v0.0.6 * обновлена ссылка на wiki ( http://psi-plus.com/wiki/plugins#video_status_changer_plugin ) 2010-08-02 v0.0.5 * обновлена информация о плагине 2010-07-27 v0.0.4 * небольшие исправления 2010-07-23 v0.0.3 + теперь после остановки проигрывания плагин возвращает старый статус и статусное сообщение 2010-06-11 v0.0.2 * интервал опроса проигрывателей увеличен до 10 секунд + добавлена возможность задать интервал перед установкой статуса "Онлайн" 2010-06-09 v0.0.1 ! initial version Плагин предназначен для установки заданного статуса, когда вы смотрите видео в указанном видеопроигрывателе. Связь с проигрывателями осуществляется посредством D-Bus. Плагин предназначен только для работы в операционных системах семейства Linux plugins-1.5/generic/videostatusplugin/options.ui000066400000000000000000000121271336777360500223230ustar00rootroot00000000000000 OptionsWidget 0 0 424 351 Form Enable for players: Detect full screen applications Set status: Qt::Horizontal 0 0 Status message: Qt::Horizontal 0 0 Restore old status if player stops QLayout::SetDefaultConstraint Delay before setting status, sec 1 300 Qt::Horizontal 40 20 Delay before restoring status, sec 1 300 Qt::Horizontal 0 0 <a href="http://psi-plus.com/wiki/plugins#video_status_changer_plugin">Wiki (Online)</a> true Qt::Vertical 0 0 cb_online toggled(bool) sb_restoreDelay setEnabled(bool) 195 181 340 213 plugins-1.5/generic/videostatusplugin/resources.qrc000066400000000000000000000001431336777360500230050ustar00rootroot00000000000000 videostatus.png plugins-1.5/generic/videostatusplugin/videostatus.png000066400000000000000000000002661336777360500233520ustar00rootroot00000000000000PNG  IHDRatEXtSoftwareAdobe ImageReadyqe<XIDATxb?%B@,0FFFN̘1PM!@bLOO'LDjfJ?%#5\l#96C?3(PIENDB`plugins-1.5/generic/videostatusplugin/videostatusplugin.cpp000077500000000000000000000527631336777360500246030ustar00rootroot00000000000000/* * videostatusplugin.cpp - plugin * Copyright (C) 2010 KukuRuzo, Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "psiplugin.h" #include "plugininfoprovider.h" #include "optionaccessinghost.h" #include "optionaccessor.h" #include "accountinfoaccessinghost.h" #include "accountinfoaccessor.h" #include "psiaccountcontroller.h" #include "psiaccountcontrollinghost.h" #include "ui_options.h" #ifdef Q_OS_WIN #include "windows.h" #elif defined (HAVE_DBUS) #include #include #include #include #include #include #include #include "x11info.h" #include static const QString MPRIS_PREFIX = "org.mpris"; static const QString MPRIS2_PREFIX = "org.mpris.MediaPlayer2"; static const QString GMP_PREFIX = "com.gnome"; static const int StatusPlaying = 0; static const int gmpStatusPlaying = 3; typedef QList WindowList; typedef QPair StringMap; //имена сервисов. Для добавления нового плеера дописываем имя сервиса static const QList players = QList() << StringMap("vlc", "VLC") << StringMap("Totem", "Totem (>=2.30.2)") << StringMap("kaffeine", "Kaffeine (>=1.0)") << StringMap("mplayer", "GNOME MPlayer") << StringMap("dragonplayer", "Dragon Player") << StringMap("smplayer", "SMPlayer"); struct PlayerStatus { int playStatus; int playOrder; int playRepeat; int stopOnce; }; Q_DECLARE_METATYPE(PlayerStatus); static const QDBusArgument & operator<<(QDBusArgument &arg, const PlayerStatus &ps) { arg.beginStructure(); arg << ps.playStatus << ps.playOrder << ps.playRepeat << ps.stopOnce; arg.endStructure(); return arg; } static const QDBusArgument & operator>>(const QDBusArgument &arg, PlayerStatus &ps) { arg.beginStructure(); arg >> ps.playStatus >> ps.playOrder >> ps.playRepeat >> ps.stopOnce; arg.endStructure(); return arg; } #endif #define constVersion "0.2.8" #define constStatus "status" #define constStatusMessage "statusmessage" #define constSetOnline "setonline" #define constRestoreDelay "restoredelay" #define constSetDelay "setdelay" #define constFullScreen "fullscreen" static const int timeout = 10000; class VideoStatusChanger : public QObject, public PsiPlugin, public PluginInfoProvider, public OptionAccessor , public PsiAccountController, public AccountInfoAccessor { Q_OBJECT #ifdef HAVE_QT5 Q_PLUGIN_METADATA(IID "com.psi-plus.VideoStatusChanger") #endif Q_INTERFACES(PsiPlugin PluginInfoProvider OptionAccessor PsiAccountController AccountInfoAccessor) public: VideoStatusChanger(); virtual QString name() const; virtual QString shortName() const; virtual QString version() const; virtual QWidget* options(); virtual bool enable(); virtual bool disable(); virtual void applyOptions(); virtual void restoreOptions(); virtual void optionChanged(const QString&) {}; virtual void setOptionAccessingHost(OptionAccessingHost* host); virtual void setAccountInfoAccessingHost(AccountInfoAccessingHost* host); virtual void setPsiAccountControllingHost(PsiAccountControllingHost* host); virtual QString pluginInfo(); virtual QPixmap icon() const; private: bool enabled; OptionAccessingHost* psiOptions; AccountInfoAccessingHost* accInfo; PsiAccountControllingHost* accControl; QString status, statusMessage; Ui::OptionsWidget ui_; #ifdef HAVE_DBUS bool playerGMPlayer_; //только для не MPRIS плеера GMPlayer QHash playerDictList; QPointer checkTimer; //Таймер Gnome Mplayer QStringList validPlayers_; //список включенных плееров QStringList services_; //очередь плееров которые слушает плагин void connectToBus(const QString &service_); void disconnectFromBus(const QString &service_); void startCheckTimer(); bool isPlayerValid(const QString &service); #endif QTimer fullST; bool isStatusSet; // здесь храним информацию, установлен ли уже статус (чтобы не устанавливать повторно при каждом срабатывании таймера) bool setOnline; int restoreDelay; //задержка восстановления статуса int setDelay; //задержка установки статуса bool fullScreen; struct StatusString { QString status; QString message; }; QHash statuses_; #ifdef Q_OS_WIN bool isFullscreenWindow(); #endif void setPsiGlobalStatus(const bool set); void setStatusTimer(const int delay, const bool isStart); private slots: #ifdef HAVE_DBUS void checkMprisService(const QString &name, const QString &oldOwner, const QString &newOwner); void onPlayerStatusChange(const PlayerStatus &ps); void onPropertyChange(const QDBusMessage &msg); void timeOut(); //здесь проверяем проигрыватель Gnome Mplayer void asyncCallFinished(QDBusPendingCallWatcher *watcher); #endif void delayTimeout(); void fullSTTimeout(); }; #ifndef HAVE_QT5 Q_EXPORT_PLUGIN(VideoStatusChanger); #endif VideoStatusChanger::VideoStatusChanger() { enabled = false; #ifdef HAVE_DBUS playerGMPlayer_ = false; foreach (StringMap item, players) { playerDictList.insert(item.first, false); } #endif status = "dnd"; statusMessage = ""; psiOptions = 0; accInfo = 0; accControl = 0; isStatusSet = false; setOnline = true; restoreDelay = 20; setDelay = 10; fullScreen = false; } QString VideoStatusChanger::name() const { return "Video Status Changer Plugin"; } QString VideoStatusChanger::shortName() const { return "videostatus"; } QString VideoStatusChanger::version() const { return constVersion; } void VideoStatusChanger::setOptionAccessingHost(OptionAccessingHost* host) { psiOptions = host; } void VideoStatusChanger::setAccountInfoAccessingHost(AccountInfoAccessingHost* host) { accInfo = host; } void VideoStatusChanger::setPsiAccountControllingHost(PsiAccountControllingHost* host) { accControl = host; } bool VideoStatusChanger::enable() { if(psiOptions) { enabled = true; #ifdef HAVE_DBUS qDBusRegisterMetaType(); services_ = QDBusConnection::sessionBus().interface()->registeredServiceNames().value(); //проверка на наличие уже запущенных плееров foreach (const QString& item, playerDictList.keys()) { bool option = psiOptions->getPluginOption(item, QVariant(playerDictList.value(item))).toBool(); playerDictList[item] = option; if (item.contains("mplayer")) { playerGMPlayer_ = option; } foreach (const QString& service, services_){ if (service.contains(item, Qt::CaseInsensitive)) { connectToBus(service); } } } #endif statuses_.clear(); status = psiOptions->getPluginOption(constStatus, QVariant(status)).toString(); statusMessage = psiOptions->getPluginOption(constStatusMessage, QVariant(statusMessage)).toString(); setOnline = psiOptions->getPluginOption(constSetOnline, QVariant(setOnline)).toBool(); restoreDelay = psiOptions->getPluginOption(constRestoreDelay, QVariant(restoreDelay)).toInt(); setDelay = psiOptions->getPluginOption(constSetDelay, QVariant(setDelay)).toInt(); fullScreen = psiOptions->getPluginOption(constFullScreen, fullScreen).toBool(); #ifdef HAVE_DBUS //цепляем сигнал появления новых плееров QDBusConnection::sessionBus().connect(QLatin1String("org.freedesktop.DBus"), QLatin1String("/org/freedesktop/DBus"), QLatin1String("org.freedesktop.DBus"), QLatin1String("NameOwnerChanged"), this, SLOT(checkMprisService(QString, QString, QString))); #endif fullST.setInterval(timeout); connect(&fullST, SIGNAL(timeout()), SLOT(fullSTTimeout())); if(fullScreen) fullST.start(); } return enabled; } bool VideoStatusChanger::disable() { enabled = false; fullST.stop(); #ifdef HAVE_DBUS //отключаем прослушку активных плееров foreach(const QString& player, services_) { disconnectFromBus(player); } //отключаеся от шины QDBusConnection::sessionBus().disconnect(QLatin1String("org.freedesktop.DBus"), QLatin1String("/org/freedesktop/DBus"), QLatin1String("org.freedesktop.DBus"), QLatin1String("NameOwnerChanged"), this, SLOT(checkMprisService(QString, QString, QString))); //убиваем таймер если он есть if(checkTimer) { checkTimer->stop(); disconnect(checkTimer, SIGNAL(timeout()), this, SLOT(timeOut())); delete(checkTimer); } #endif return true; } void VideoStatusChanger::applyOptions() { #ifdef HAVE_DBUS //читаем состояние плееров if (playerDictList.size() > 0) { foreach (const QString& item, playerDictList.keys()) { QCheckBox *cb = ui_.groupBox->findChild(item); if (cb) { playerDictList[item] = cb->isChecked(); if (item.contains("mplayer")) { playerGMPlayer_ = cb->isChecked(); } psiOptions->setPluginOption(item, QVariant(cb->isChecked())); } } } #endif status = ui_.cb_status->currentText(); psiOptions->setPluginOption(constStatus, QVariant(status)); statusMessage = ui_.le_message->text(); psiOptions->setPluginOption(constStatusMessage, QVariant(statusMessage)); setOnline = ui_.cb_online->isChecked(); psiOptions->setPluginOption(constSetOnline, QVariant(setOnline)); restoreDelay = ui_.sb_restoreDelay->value(); psiOptions->setPluginOption(constRestoreDelay, QVariant(restoreDelay)); setDelay = ui_.sb_setDelay->value(); psiOptions->setPluginOption(constSetDelay, QVariant(setDelay)); fullScreen = ui_.cb_fullScreen->isChecked(); psiOptions->setPluginOption(constFullScreen, fullScreen); if(fullScreen) { fullST.start(); } else if (fullST.isActive()) { fullST.stop(); } } void VideoStatusChanger::restoreOptions() { #ifdef HAVE_DBUS //читаем состояние плееров if (playerDictList.size() > 0) { foreach (const QString& item, playerDictList.keys()) { bool option = psiOptions->getPluginOption(item, QVariant(playerDictList.value(item))).toBool(); QCheckBox *cb = ui_.groupBox->findChild(item); if (cb) { cb->setChecked(option); } } } #elif defined (Q_OS_WIN) ui_.groupBox->hide(); #endif QStringList list; list << "away" << "xa" << "dnd"; ui_.cb_status->addItems(list); ui_.cb_status->setCurrentIndex(ui_.cb_status->findText(status)); ui_.le_message->setText(statusMessage); ui_.cb_online->setChecked(setOnline); ui_.sb_restoreDelay->setValue(restoreDelay); ui_.sb_setDelay->setValue(setDelay); ui_.cb_fullScreen->setChecked(fullScreen); } QWidget* VideoStatusChanger::options() { if (!enabled) { return 0; } QWidget *optionsWid = new QWidget(); ui_.setupUi(optionsWid); #ifdef HAVE_DBUS //добавляем чекбоксы плееров int i = 0; int columns = (players.length() < 5) ? 2 : 3; foreach (StringMap item, players) { i = players.indexOf(item); if (i != -1) { QCheckBox *cb = new QCheckBox(item.second); cb->setObjectName(item.first); cb->setChecked(false); int row = (i - columns) < 0 ? 0 : i/columns; ui_.gridLayout->addWidget(cb,row,i%columns); } } #endif restoreOptions(); return optionsWid; } QString VideoStatusChanger::pluginInfo() { return tr("Authors: ") + "Dealer_WeARE, KukuRuzo\n\n" + trUtf8("This plugin is designed to set the custom status when you watching the video in selected video players. \n" "Note: This plugin is designed to work in Linux family operating systems and in Windows OS. \n\n" "In Linux plugin uses DBUS to work with video players and X11 functions to detect fullscreen applications. \n" "In Windows plugin uses WinAPI functions to detect fullscreen applications. \n\n" "To work with Totem player you need to enable appropriate plugin in this player (Edit\\Plugins\\D-Bus);\n\n" "To work with VLC player you need to enable the option \"Control Interface D-Bus\" in the Advanced Settings tab on \"Interface\\Control Interface\" section of the player settings; \n\n" "To work with Kaffeine player you must have player version (>= 1.0), additional configuration is not needed; \n\n" "To work with GNOME MPlayer additional configuration is not needed."); } QPixmap VideoStatusChanger::icon() const { return QPixmap(":/icons/videostatus.png"); } #ifdef HAVE_DBUS bool VideoStatusChanger::isPlayerValid(const QString &service) //проверка является ли плеер разрешенным { foreach (const QString& item, playerDictList.keys()) { if (service.contains(item, Qt::CaseInsensitive) && playerDictList.value(item)) { return true; } } return false; } void VideoStatusChanger::checkMprisService(const QString &name, const QString &oldOwner, const QString &newOwner) { //слот вызывается при изменении имён сервисов в шине Q_UNUSED(oldOwner); if ((name.startsWith(MPRIS_PREFIX) || name.startsWith(GMP_PREFIX)) && isPlayerValid(name)) { int playerIndex = services_.indexOf(name); if (playerIndex == -1) { if (!newOwner.isEmpty()) { //если сервис только появился добавляем его в очередь и подключаемся к нему services_.append(name); connectToBus(name); } } else if (newOwner.isEmpty()) { //если сервис был то отключаемся от него и удаляем из очереди disconnectFromBus(name); services_.removeAt(playerIndex); } } } void VideoStatusChanger::startCheckTimer() { //работа с таймером для плеера Gnome MPlayer if(!checkTimer) { checkTimer = new QTimer(); checkTimer->setInterval(timeout); connect(checkTimer, SIGNAL(timeout()), this, SLOT(timeOut())); checkTimer->setInterval(timeout); checkTimer->start(); } else { checkTimer->stop(); disconnect(checkTimer); delete(checkTimer); setStatusTimer(restoreDelay, false); } } void VideoStatusChanger::connectToBus(const QString &service_) { if (service_.contains(MPRIS_PREFIX) && !service_.contains(MPRIS2_PREFIX)) { QDBusConnection::sessionBus().connect(service_, QLatin1String("/Player"), QLatin1String("org.freedesktop.MediaPlayer"), QLatin1String("StatusChange"), QLatin1String("(iiii)"), this, SLOT(onPlayerStatusChange(PlayerStatus))); } else if (service_.contains(MPRIS2_PREFIX)) { QDBusConnection::sessionBus().connect(service_, QLatin1String("/org/mpris/MediaPlayer2"), QLatin1String("org.freedesktop.DBus.Properties"), QLatin1String("PropertiesChanged"), this, SLOT(onPropertyChange(QDBusMessage))); } else if (service_.contains(GMP_PREFIX)) { startCheckTimer(); } } void VideoStatusChanger::disconnectFromBus(const QString &service_) { if (service_.contains(MPRIS_PREFIX) && !service_.contains(MPRIS2_PREFIX)) { QDBusConnection::sessionBus().disconnect(MPRIS_PREFIX + "." + service_, QLatin1String("/Player"), QLatin1String("org.freedesktop.MediaPlayer"), QLatin1String("StatusChange"), QLatin1String("(iiii)"), this, SLOT(onPlayerStatusChange(PlayerStatus))); if (isStatusSet) { setStatusTimer(restoreDelay, false); } } else if (service_.contains(MPRIS2_PREFIX)) { QDBusConnection::sessionBus().disconnect(MPRIS2_PREFIX + "." + service_.toLower(), QLatin1String("/org/mpris/MediaPlayer2"), QLatin1String("org.freedesktop.DBus.Properties"), QLatin1String("PropertiesChanged"), this, SLOT(onPropertyChange(QDBusMessage))); } else if (service_.contains("mplayer")) { startCheckTimer(); } if (!fullST.isActive() && fullScreen) { fullST.start(); } } void VideoStatusChanger::onPlayerStatusChange(const PlayerStatus &st) { if (st.playStatus == StatusPlaying) { fullST.stop(); setStatusTimer(setDelay, true); } else { setStatusTimer(restoreDelay, false); fullST.start(); } } void VideoStatusChanger::onPropertyChange(const QDBusMessage &msg) { QDBusArgument arg = msg.arguments().at(1).value(); QVariantMap map = qdbus_cast(arg); QVariant v = map.value(QLatin1String("PlaybackStatus")); if (v.isValid()) { if (v.toString() == QLatin1String("Playing")) { fullST.stop(); setStatusTimer(setDelay, true); } else if (v.toString() == QLatin1String("Paused") || v.toString() == QLatin1String("Stopped")) { setStatusTimer(restoreDelay, false); fullST.start(); } } } void VideoStatusChanger::timeOut() { if(playerGMPlayer_) { QString gmplayerService = GMP_PREFIX + ".mplayer"; QDBusMessage msg = QDBusMessage::createMethodCall(gmplayerService, "/", gmplayerService, "GetPlayState"); QDBusPendingCall call = QDBusConnection::sessionBus().asyncCall(msg); QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this); connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(asyncCallFinished(QDBusPendingCallWatcher*))); } } static WindowList getWindows(Atom prop) { WindowList res; Atom type = 0; int format = 0; uchar* data = 0; ulong count, after; Display* display = X11Info::display(); Window window = X11Info::appRootWindow(); if (XGetWindowProperty(display, window, prop, 0, 1024 * sizeof(Window) / 4, False, AnyPropertyType, &type, &format, &count, &after, &data) == Success) { Window* list = reinterpret_cast(data); for (uint i = 0; i < count; ++i) res += list[i]; if (data) XFree(data); } return res; } static Window activeWindow() { static Atom net_active = 0; if (!net_active) net_active = XInternAtom(X11Info::display(), "_NET_ACTIVE_WINDOW", True); return getWindows(net_active).value(0); } void VideoStatusChanger::asyncCallFinished(QDBusPendingCallWatcher *watcher) { watcher->deleteLater(); QDBusMessage msg = watcher->reply(); if (msg.type() == QDBusMessage::InvalidMessage || msg.arguments().isEmpty()) { return; } QVariant reply = msg.arguments().first(); if (reply.type() != QVariant::Int) { return; } else { int stat = reply.toInt(); if (stat == gmpStatusPlaying && (!isStatusSet)) { fullST.stop(); setStatusTimer(setDelay, true); } if(stat != gmpStatusPlaying && isStatusSet) { setStatusTimer(restoreDelay, false); fullST.start(); } } } #endif void VideoStatusChanger::fullSTTimeout() { #ifdef HAVE_DBUS Window w = activeWindow(); Display *display = X11Info::display(); bool full = false; static Atom state = XInternAtom(display, "_NET_WM_STATE", False); static Atom fullScreen = XInternAtom(display, "_NET_WM_STATE_FULLSCREEN", False); Atom actual_type; int actual_format; unsigned long nitems; unsigned long bytes; unsigned char *data = 0; if (XGetWindowProperty(display, w, state, 0, (~0L), False, AnyPropertyType, &actual_type, &actual_format, &nitems, &bytes, &data) == Success) { if(nitems != 0) { Atom *atom = reinterpret_cast(data); for (ulong i = 0; i < nitems; i++) { if(atom[i] == fullScreen) { full = true; break; } } } } if(data) XFree(data); #elif defined (Q_OS_WIN) bool full = isFullscreenWindow(); #endif if(full) { if(!isStatusSet) { setStatusTimer(setDelay, true); } } else if(isStatusSet) { setStatusTimer(restoreDelay, false); } } #ifdef Q_OS_WIN bool VideoStatusChanger::isFullscreenWindow() { HWND hWnd = GetForegroundWindow(); RECT appBounds; RECT rc; if (GetWindowRect(GetDesktopWindow(), &rc)) { if(hWnd != GetDesktopWindow() && hWnd != GetShellWindow()) { if (GetWindowRect(hWnd, &appBounds)) { return (appBounds.bottom == rc.bottom && appBounds.left == rc.left && appBounds.right == rc.right && appBounds.top == rc.top); } } } return false; } #endif void VideoStatusChanger::setStatusTimer(const int delay, const bool isStart) { //запуск таймера установки / восстановления статуса if ((isStart | setOnline) != 0) { QTimer::singleShot(delay*1000, this, SLOT(delayTimeout())); isStatusSet = isStart; } } void VideoStatusChanger::delayTimeout() { setPsiGlobalStatus(!isStatusSet); } void VideoStatusChanger::setPsiGlobalStatus(const bool set) { if (!enabled) return; int account = 0; StatusString s; while (accInfo->getJid(account) != "-1") { QString accStatus = accInfo->getStatus(account); if(accStatus != "offline" && accStatus != "invisible") { if(set) { if(statuses_.contains(account)) { s = statuses_.value(account); accControl->setStatus(account, s.status, s.message); } else accControl->setStatus(account, "online", ""); } else { s.status = accStatus; s.message = accInfo->getStatusMessage(account); if(s.status != status || s.message != statusMessage) statuses_.insert(account, s); accControl->setStatus(account, status, statusMessage); } } ++account; } } #include "videostatusplugin.moc" plugins-1.5/generic/videostatusplugin/videostatusplugin.pro000066400000000000000000000005351336777360500246040ustar00rootroot00000000000000isEmpty(PSISDK) { include(../../psiplugin.pri) } else { include($$PSISDK/plugins/psiplugin.pri) } !mac { RESOURCES += resources.qrc SOURCES += videostatusplugin.cpp FORMS += options.ui } unix: ! mac { CONFIG += X11 QT += dbus DEFINES += HAVE_DBUS SOURCES += x11info.cpp HEADERS += x11info.h } win32:LIBS += -luser32 plugins-1.5/generic/videostatusplugin/x11info.cpp000066400000000000000000000031001336777360500222510ustar00rootroot00000000000000/* * Copyright (C) 2013 Sergey Ilinykh (rion) * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include "x11info.h" #ifdef HAVE_QT5 # include # include # include #else # include #endif Display* X11Info::display() { #ifdef HAVE_QT5 if (!_display) { _display = XOpenDisplay(NULL); } return _display; #else return QX11Info::display(); #endif } unsigned long X11Info::appRootWindow(int screen) { #ifdef HAVE_QT5 return screen == -1? XDefaultRootWindow(display()) : XRootWindowOfScreen(XScreenOfDisplay(display(), screen)); #else return QX11Info::appRootWindow(screen); #endif } #ifdef HAVE_QT5 xcb_connection_t *X11Info::xcbConnection() { if (!_xcb) { _xcb = xcb_connect(NULL, &_xcbPreferredScreen); Q_ASSERT(_xcb); } return _xcb; } xcb_connection_t* X11Info::_xcb = 0; #endif Display* X11Info::_display = 0; int X11Info::_xcbPreferredScreen = 0; plugins-1.5/generic/videostatusplugin/x11info.h000066400000000000000000000024301336777360500217230ustar00rootroot00000000000000/* * Copyright (C) 2013 Sergey Ilinykh (rion) * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef X11INFO_H #define X11INFO_H typedef struct _XDisplay Display; #ifdef HAVE_QT5 typedef struct xcb_connection_t xcb_connection_t; #endif class X11Info { static Display *_display; #ifdef HAVE_QT5 static xcb_connection_t *_xcb; #endif static int _xcbPreferredScreen; public: static Display* display(); static unsigned long appRootWindow(int screen = -1); #ifdef HAVE_QT5 static xcb_connection_t* xcbConnection(); static inline int xcbPreferredScreen() { return _xcbPreferredScreen; } #endif }; #endif // X11INFO_H plugins-1.5/generic/watcherplugin/000077500000000000000000000000001336777360500173515ustar00rootroot00000000000000plugins-1.5/generic/watcherplugin/CMakeLists.txt000066400000000000000000000027321336777360500221150ustar00rootroot00000000000000unset(_HDRS) unset(_UIS) unset(_SRCS) unset(_RSCS) unset(PLUGIN) set( PLUGIN watcherplugin ) project(${PLUGIN}) cmake_minimum_required(VERSION 3.1.0) set( CMAKE_AUTOMOC TRUE ) IF( NOT WIN32 ) set( LIB_SUFFIX "" CACHE STRING "Define suffix of directory name (32/64)" ) set( PLUGINS_PATH "lib${LIB_SUFFIX}/psi-plus/plugins" CACHE STRING "Install suffix for plugins" ) ELSE() set( PLUGINS_PATH "psi-plus/plugins" CACHE STRING "Install suffix for plugins" ) ENDIF() add_definitions( -DQT_PLUGIN -DHAVE_QT5 ) include_directories( ${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ../../include . ) set( _HDRS view.h model.h delegate.h watcheditem.h edititemdlg.h ) set( _SRCS ${PLUGIN}.cpp view.cpp model.cpp delegate.cpp watcheditem.cpp edititemdlg.cpp ) set( _UIS options.ui edititemdlg.ui ) set ( _RSCS resources.qrc ) find_package( Qt5 COMPONENTS Widgets Xml REQUIRED ) set(QT_DEPLIBS Qt5::Widgets Qt5::Xml ) qt5_wrap_ui(UIS ${_UIS}) qt5_add_resources(RSCS ${_RSCS}) add_library( ${PLUGIN} MODULE ${_SRCS} ${UIS} ${RSCS} ) target_link_libraries( ${PLUGIN} ${QT_DEPLIBS} ) if( UNIX AND NOT( APPLE OR CYGWIN ) ) install( TARGETS ${PLUGIN} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} ) endif() if( WIN32 ) install( TARGETS ${PLUGIN} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${PLUGINS_PATH} ) endif() plugins-1.5/generic/watcherplugin/changelog.txt000066400000000000000000000157221336777360500220500ustar00rootroot000000000000002013-10-13 tehnick v0.4.6 ! исправлена ошибка сегментации, добавленная в v0.4.3 2013-09-27 taurus v0.4.5 - убрана опция отображать на панели чата 2013-08-13 taurus v0.4.4 + добавлена иконка плагина 2013-08-10 taurus v0.4.3 + добавлена кнопка в панель инструментов чата для добавления контакта в список слежения ! изменена иконка в контекстном меню контакта ! в настройках 1-ая колонка теперь используется для включения правила + добавлены настройка для отобржанеие кнопок "Следить за JID'ом" 2013-08-08 taurus v0.4.2 * исправлен выбор Jid'а для удаления из списка наблюдения 2012-02-20 v0.4.1 * исправления для нового попап-интерфейса 2011-10-25 v0.4.0 * улучшен пункт меню контакта * небольшие оптимизации 2011-02-08 v0.3.9 * для проигрывания звука теперь используется новый плагинный интерфейс * настройки времени показа всплывающих уведомлений перенесены в основные настройки приложения 2011-01-26 v0.3.8 + добавлена возможность отключить всплывающие уведомления если статус DND + во всплывающем уведомлении показывается статусное сообщение + во всплывающем уведомлении показывается ресурс * исправлен показ ошибочных уведомлений от мрим и асько контактов 2011-01-15 v0.3.7 * исправлена статусная иконка во всплывающем уведомлении 2011-01-13 v0.3.6 + во всплывающем уведомлении теперь показывается аватарка и иконка статуса контакта + щелчок мыши на всплывающем уведомлении вызывает теперь окно чата с данным контактом 2010-11-12 v0.3.5 + теперь во всплывающем уведомлении показывается ник контакта 2010-09-11 v0.3.4 *обновлена ссылка на wiki ( http://psi-plus.com/wiki/plugins#watcher_plugin ) 2010-08-12 v0.3.3 * небольшие исправления 2010-08-02 v0.3.2 * обновлена информация о плагине 2010-07-27 v0.3.1 + добавлена возможность раздельной настройки правил для конференций и обычных сообщений + добавлена возможность отключить звуки для активной вкладки/чата + теперь запоминается путь к последнему открытому звуковому файлу 2010-07-26 v0.3.0 + добавлена возможность настроить различные звуковые оповещения для различных групп контактов или для различного содержания входящих сообщений 2010-06-05 v0.2.7 * исправлено ложное срабатывание плагина 2010-06-02 v0.2.6 * некоторые исправления, увеличивающие стабильность 2010-05-31 v0.2.5 + добавлена возможность выставить -1 для времени показа всплывающего уведомления + добавлена возможность включить слежение за участниками конференции * немного исправлено определение геометрии таблицы в опциях плагина 2010-05-17 v0.2.4 + добавлена информация о плагине * исправлено падение приложения при отключении плагина 2010-05-04 v0.2.3 * исправлена ссылка на wiki 2010-04-30 v0.2.2 * исправлено падение приложения при отключении плагина 2010-04-13 v0.2.1 + в настройки по-умолчанию добавлен звуковой файл watcher.wav 2010-03-12 v0.2.0 * переписана большая часть кода плагина + возможность установить наблюдение за контактом из контекстного меню + более удобное управление списком контактов для наблюдения ВНИМАНИЕ! В связи с существенными изменениями в коде плагина некоторая часть настроек будет утеряна. Необходимо заново настроить список контактов для наблюдения! 2010-03-11 v0.1.3 * исправлено отображение опций плагина в различных локализациях 2010-01-29 v0.1.2 * последнюю строку нельзя удалить * исправлено появление нижнего скроллбара 2010-01-28 v0.1.1 + добавлена возможность установить для каждого контакта свою мелодию если мелодия не установлена - используется мелодия по умолчанию * исправлено окно настроек 2010-01-05 v0.0.2 + воспроизведение звука теперь зависит от глобальных настроек (глобальное отключение звука отключит звуковые уведомления в плагине) + добавлена возможность задать время, в течение которого будет показываться всплывающее уведомление + включение/выключение всплывающих уведомлений больше не зависит от глобальных настроек 2010-01-04 v0.0.1 ! initial version Данный плагин предназначен для наблюдения за статусом определённых пользователей в вашем ростере. При смене статуса таких контактов будет показываться всплывающее окно, а при смене статуса на онлайн - ещё и проигрываться указанный звук. plugins-1.5/generic/watcherplugin/delegate.cpp000066400000000000000000000054221336777360500216320ustar00rootroot00000000000000/* * delegate.cpp - plugin * Copyright (C) 2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "delegate.h" #include "iconfactoryaccessinghost.h" #include QSize IconDelegate::sizeHint(const QStyleOptionViewItem& /*option*/, const QModelIndex& index) const { if(index.isValid()) { return QSize (18,18); } return QSize(0, 0); } void IconDelegate::paint ( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const { QRect rect = option.rect; painter->save(); QPalette palette = option.palette; QColor c = (option.state & QStyle::State_Selected) ? palette.color(QPalette::Highlight) : palette.color(QPalette::Base); painter->fillRect(rect, c); QPalette::ColorGroup cg = option.state & QStyle::State_Enabled ? QPalette::Normal : QPalette::Disabled; if (option.state & QStyle::State_Selected) { painter->setPen(palette.color(cg, QPalette::HighlightedText)); } else { painter->setPen(palette.color(cg, QPalette::Text)); } QPixmap pix; if(index.column() == 3) { pix = iconHost_->getIcon("psi/browse").pixmap(QSize(16,16)); } else if(index.column() == 4) { pix = iconHost_->getIcon("psi/play").pixmap(QSize(16,16)); } QRect r(rect); r.translate(4,5); r.setSize(pix.size()); painter->drawPixmap(r, pix); painter->restore(); } //----------------------------------- //--------LineEditDelegate----------- //----------------------------------- QWidget * LineEditDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &/*option*/, const QModelIndex &/*index*/) const { QLineEdit *editor = new QLineEdit(parent); return editor; } void LineEditDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const { QString value = index.model()->data(index, Qt::DisplayRole).toString(); QLineEdit *lineEdit = static_cast(editor); lineEdit->setText(value); } void LineEditDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const { QLineEdit *lineEdit = static_cast(editor); QString value = lineEdit->text(); model->setData(index, value, Qt::EditRole); } plugins-1.5/generic/watcherplugin/delegate.h000066400000000000000000000040041336777360500212720ustar00rootroot00000000000000/* * delegate.h - plugin * Copyright (C) 2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef DELEGATE_H #define DELEGATE_H #include #include class IconFactoryAccessingHost; class IconDelegate : public QItemDelegate { Q_OBJECT public: IconDelegate(IconFactoryAccessingHost *iconHost, QObject * parent = 0) : QItemDelegate(parent), iconHost_(iconHost) {}; virtual QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const; virtual void drawDisplay(QPainter * /*painter*/, const QStyleOptionViewItem & /*option*/, const QRect & /*rect*/, const QString & /*text*/) const {}; void paint ( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const; private: IconFactoryAccessingHost *iconHost_; }; class LineEditDelegate : public QItemDelegate { Q_OBJECT public: LineEditDelegate(QObject * parent = 0) : QItemDelegate(parent) {}; QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const; void setEditorData(QWidget *editor, const QModelIndex &index) const; void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const; // void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const; }; #endif // DELEGATE_H plugins-1.5/generic/watcherplugin/edititemdlg.cpp000066400000000000000000000056271336777360500223620ustar00rootroot00000000000000/* * edititemdlg.cpp - plugin * Copyright (C) 2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "edititemdlg.h" #include "iconfactoryaccessinghost.h" #include "optionaccessinghost.h" #include static const QString splitStr = "&split&"; EditItemDlg::EditItemDlg(IconFactoryAccessingHost* icoHost, OptionAccessingHost *psiOptions_, QWidget *p) : QDialog(p, Qt::Window) , psiOptions(psiOptions_) { setAttribute(Qt::WA_DeleteOnClose); //setModal(true); ui_.setupUi(this); ui_.tb_open->setIcon(icoHost->getIcon("psi/browse")); ui_.tb_test->setIcon(icoHost->getIcon("psi/play")); connect(ui_.tb_test, SIGNAL(pressed()), SLOT(doTestSound())); connect(ui_.tb_open, SIGNAL(pressed()), SLOT(getFileName())); } void EditItemDlg::init(const QString &settings) { QStringList l = settings.split(splitStr); if(!l.isEmpty()) { ui_.le_jid->setText(l.takeFirst()); ui_.le_jid->setEnabled(!ui_.le_jid->text().isEmpty()); ui_.rb_text->setChecked(ui_.le_jid->text().isEmpty()); } if(!l.isEmpty()) { ui_.te_text->setText(l.takeFirst()); ui_.te_text->setEnabled(!ui_.te_text->toPlainText().isEmpty()); ui_.rb_jid->setChecked(ui_.te_text->toPlainText().isEmpty()); } if(!l.isEmpty()) ui_.le_sound->setText(l.takeFirst()); if(!l.isEmpty()) ui_.cb_always_play->setChecked(l.takeFirst().toInt()); if(!l.isEmpty()) ui_.rb_groupchat->setChecked(l.takeFirst().toInt()); } void EditItemDlg::getFileName() { QString fileName = QFileDialog::getOpenFileName(0,tr("Choose a sound file"), psiOptions->getPluginOption(constLastFile, QVariant("")).toString(), tr("Sound (*.wav)")); if(fileName.isEmpty()) return; QFileInfo fi(fileName); psiOptions->setPluginOption(constLastFile, QVariant(fi.absolutePath())); ui_.le_sound->setText(fileName); } void EditItemDlg::doTestSound() { emit testSound(ui_.le_sound->text()); } void EditItemDlg::accept() { QString str = (ui_.rb_jid->isChecked() ? ui_.le_jid->text() : "") + splitStr; str += (ui_.rb_text->isChecked() ? ui_.te_text->toPlainText() : "") + splitStr; str += ui_.le_sound->text() + splitStr; str += (ui_.cb_always_play->isChecked() ? "1" : "0") + splitStr; str += ui_.rb_groupchat->isChecked() ? "1" : "0"; emit dlgAccepted(str); close(); } plugins-1.5/generic/watcherplugin/edititemdlg.h000066400000000000000000000025731336777360500220240ustar00rootroot00000000000000/* * edititemdlg.h - plugin * Copyright (C) 2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef EDITITEMDLG_H #define EDITITEMDLG_H #include "ui_edititemdlg.h" class OptionAccessingHost; class IconFactoryAccessingHost; #define constLastFile "lastfile" class EditItemDlg : public QDialog { Q_OBJECT public: EditItemDlg(IconFactoryAccessingHost* icoHost, OptionAccessingHost *psiOptions_, QWidget *p = 0); void init(const QString &settings); signals: void dlgAccepted(const QString&); void testSound(const QString&); private slots: void accept(); void getFileName(); void doTestSound(); private: Ui::EditItemDlg ui_; OptionAccessingHost *psiOptions; }; #endif // EDITITEMDLG_H plugins-1.5/generic/watcherplugin/edititemdlg.ui000066400000000000000000000120701336777360500222030ustar00rootroot00000000000000 EditItemDlg 0 0 352 467 Watch For... true JID* true Text** false Andale Mono 8 *Regular expressions can be used Andale Mono 8 **List of words can be used. Each word can use regular expression Use for Chats true Groupchats Always play sound Sound: Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok buttonBox accepted() EditItemDlg accept() 248 254 157 274 buttonBox rejected() EditItemDlg close() 316 260 175 201 rb_jid toggled(bool) le_jid setEnabled(bool) 48 43 210 44 rb_text toggled(bool) te_text setEnabled(bool) 48 159 210 159 plugins-1.5/generic/watcherplugin/model.cpp000066400000000000000000000166301336777360500211630ustar00rootroot00000000000000/* * model.cpp - plugin * Copyright (C) 2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "model.h" Model::Model(const QStringList& watchedJids_, const QStringList& Sounds_, const QStringList& enabledJids_, QObject* parent) : QAbstractTableModel(parent) , watchedJids(watchedJids_) , sounds(Sounds_) , enabledJids(enabledJids_) { headers << tr("") << tr("Watch for JIDs") << tr("Sounds (if empty default sound will be used)") << tr("") << tr(""); tmpWatchedJids_ = watchedJids; tmpSounds_ = sounds; foreach (QString enabledJid, enabledJids_) { tmpEnabledJids_ << (enabledJid == "true" ? true : false); } } QVariant Model::headerData ( int section, Qt::Orientation orientation, int role) const { if (role == Qt::DisplayRole) { if (orientation == Qt::Horizontal) { return headers.at(section); } else { return section+1; } } else return QVariant(); } Qt::ItemFlags Model::flags ( const QModelIndex & index ) const { Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled; int column = index.column(); if(column == 0) flags |= Qt::ItemIsUserCheckable; else if(column == 1 || column == 2) flags |= Qt::ItemIsEditable; return flags; } int Model::columnCount(const QModelIndex & /*parent*/) const { return headers.size(); } int Model::rowCount(const QModelIndex &/* parent*/) const { return tmpWatchedJids_.size(); } QVariant Model::data(const QModelIndex & index, int role) const { if(!index.isValid()) return QVariant(); int i = index.column(); switch(i) { case 0: if (role == Qt::CheckStateRole) { return tmpEnabledJids_.at(index.row()) ? 2:0; } else if (role == Qt::TextAlignmentRole) { return (int)(Qt::AlignRight | Qt::AlignVCenter); } else if (role == Qt::DisplayRole) return QVariant(""); case 1: if (role == Qt::TextAlignmentRole) { return (int)(Qt::AlignRight | Qt::AlignVCenter); } else if (role == Qt::DisplayRole) return QVariant(tmpWatchedJids_.at(index.row())); case 2: if (role == Qt::TextAlignmentRole) { return (int)(Qt::AlignRight | Qt::AlignVCenter); } else if (role == Qt::DisplayRole) return QVariant(tmpSounds_.at(index.row())); case 3: if (role == Qt::TextAlignmentRole) { return (int)(Qt::AlignRight | Qt::AlignVCenter); } else if (role == Qt::DisplayRole) return QVariant(); case 4: if (role == Qt::TextAlignmentRole) { return (int)(Qt::AlignRight | Qt::AlignVCenter); } else if (role == Qt::DisplayRole) return QVariant(); } return QVariant(); } QString Model::jid(const QModelIndex & index) const { if(!index.isValid()) return QString(); return watchedJids.at(index.row()); } QString Model::soundFile(const QModelIndex & index) const { if(!index.isValid()) return QString(); return sounds.at(index.row()); } QString Model::tmpSoundFile(const QModelIndex & index) const { if(!index.isValid()) return QString(); return tmpSounds_.at(index.row()); } bool Model::setData(const QModelIndex & index, const QVariant & value, int role) { if(!index.isValid() || role != Qt::EditRole) return false; int column = index.column(); if(column == 0) { bool b = tmpEnabledJids_.at( index.row() ); switch(value.toInt()) { case 0: tmpEnabledJids_.replace( index.row(), false); break; case 2: tmpEnabledJids_.replace( index.row(), true); break; case 3: tmpEnabledJids_.replace( index.row(), !b); break; } } else if(column == 1) tmpWatchedJids_.replace( index.row(), value.toString()); else if(column == 2) tmpSounds_.replace( index.row(), value.toString()); emit dataChanged(index, index); return true; } void Model::setStatusForJid(const QString& jid, const QString& status) { statuses.insert(jid, status); } void Model::deleteRows(const QModelIndexList &indexList) { QList selected; for (int i = 0; i < tmpWatchedJids_.size(); i++) { selected << false; } foreach (QModelIndex index, indexList) { selected[index.row()] = true; } QStringList tmpJids, tmpSounds; QList tmpEnabledJids; for (int i = tmpWatchedJids_.size() - 1; i >= 0; i--) { if(selected.at(i)) { removeRow(i); } } } bool Model::removeRows(int row, int count, const QModelIndex &parent) { beginRemoveRows(parent, row, row + count - 1); for (int i = 0; i < count; i++) { tmpWatchedJids_.removeAt(row); tmpSounds_.removeAt(row); tmpEnabledJids_.removeAt(row); } endRemoveRows(); return true; } void Model::reset() { tmpWatchedJids_ = watchedJids; tmpSounds_ = sounds; tmpEnabledJids_.clear(); foreach (QString enabledJid, enabledJids) { tmpEnabledJids_ << (enabledJid == "true" ? true : false); } } void Model::addRow(const QString& jid) { beginInsertRows(QModelIndex(), tmpWatchedJids_.size(), tmpWatchedJids_.size()); tmpWatchedJids_ << jid; tmpSounds_ << ""; if(!jid.isEmpty()) { //вызов происходит из меню контакта watchedJids.append(jid); sounds.append(""); enabledJids.append("true"); } tmpEnabledJids_.append(true); endInsertRows(); } void Model::deleteRow(const QString& jid) { int index = watchedJids.indexOf(QRegExp(jid, Qt::CaseInsensitive)); if(index == -1) return; watchedJids.removeAt(index); sounds.removeAt(index); tmpWatchedJids_.removeAt(index); tmpSounds_.removeAt(index); tmpEnabledJids_.removeAt(index); emit layoutChanged(); } void Model::apply() { watchedJids = tmpWatchedJids_; sounds = tmpSounds_; enabledJids.clear(); foreach (bool enabledJid, tmpEnabledJids_) { enabledJids << (enabledJid ? "true" : "false"); } } QString Model::statusByJid(const QString& jid) const { return statuses.value(jid, "offline"); } QString Model::soundByJid(const QString& jid) const { QString sound; int index = watchedJids.indexOf(QRegExp(jid, Qt::CaseInsensitive)); if(index < sounds.size() && index != -1) sound = sounds.at( index ); return sound; } int Model::indexByJid(const QString& jid) const { return watchedJids.indexOf(QRegExp(jid, Qt::CaseInsensitive)); } QStringList Model::getWatchedJids() const { return watchedJids; } QStringList Model::getSounds() const { return sounds; } QStringList Model::getEnabledJids() const { return enabledJids; } void Model::setJidEnabled(const QString& jid, bool enabled) { // Do nothing if need to disable jid which is not in watcher list if (!getWatchedJids().contains(jid, Qt::CaseInsensitive) && !enabled) { return; } // Before add Jid to watcher list if (!getWatchedJids().contains(jid, Qt::CaseInsensitive)) { addRow(jid); } QModelIndex ind = index(indexByJid(jid), 0); setData(ind, enabled ? 2 : 0); } bool Model::jidEnabled(const QString& jid) { // watcher doesn't applied for this jid if (!getWatchedJids().contains(jid, Qt::CaseInsensitive )) { return false; } QModelIndex ind = index(indexByJid(jid), 0); return (data(ind, Qt::CheckStateRole) == 2) ? true : false; } plugins-1.5/generic/watcherplugin/model.h000066400000000000000000000050431336777360500206240ustar00rootroot00000000000000/* * model.h - plugin * Copyright (C) 2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef MODEL_H #define MODEL_H #include #include #include class Model : public QAbstractTableModel { Q_OBJECT public: Model(const QStringList& watchedJids_, const QStringList& Sounds_, const QStringList& enabledJids_, QObject *parent = 0); ~Model() {}; virtual Qt::ItemFlags flags ( const QModelIndex & index ) const; virtual QVariant headerData ( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const; virtual QVariant data ( const QModelIndex & index, int role = Qt::DisplayRole ) const; virtual int rowCount ( const QModelIndex & parent = QModelIndex() ) const; virtual int columnCount ( const QModelIndex & parent = QModelIndex() ) const; virtual bool setData ( const QModelIndex & index, const QVariant & value, int role = Qt::EditRole ); QString jid(const QModelIndex & index) const; QString soundFile(const QModelIndex & index) const; QString tmpSoundFile(const QModelIndex & index) const; void apply(); void deleteRows(const QModelIndexList &indexList); bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()); void reset(); void addRow(const QString& jid = ""); void deleteRow(const QString& jid); void setStatusForJid(const QString& jid, const QString& status); QString statusByJid(const QString& jid) const; QString soundByJid(const QString& jid) const; int indexByJid(const QString& jid) const; QStringList getWatchedJids() const; QStringList getSounds() const; QStringList getEnabledJids() const; void setJidEnabled(const QString& jid, bool enabled); bool jidEnabled(const QString& jid); private: QStringList headers, watchedJids, tmpWatchedJids_, sounds, tmpSounds_, enabledJids; QMap statuses; QList tmpEnabledJids_; }; #endif // MODEL_H plugins-1.5/generic/watcherplugin/options.ui000066400000000000000000000143441336777360500214110ustar00rootroot00000000000000 Options 0 0 379 339 Options 0 Status Delete selected Qt::Horizontal 40 20 Add row Disable popups if status is DND Default sound: Messages true QAbstractItemView::DragDrop Qt::MoveAction Add Delete Edit Qt::Vertical 20 40 Disable sound if chat window is active Misc Show Watch for JID button in contact context menu Qt::Vertical 20 40 <a href="http://psi-plus.com/wiki/plugins#watcher_plugin">Wiki (Online)</a> true Viewer QTableView
view.h
plugins-1.5/generic/watcherplugin/resources.qrc000066400000000000000000000002031336777360500220650ustar00rootroot00000000000000 watcher_on.png watcher.png plugins-1.5/generic/watcherplugin/view.cpp000066400000000000000000000065541336777360500210410ustar00rootroot00000000000000/* * view.cpp - plugin * Copyright (C) 2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "view.h" #include "model.h" #include #include #include "iconfactoryaccessinghost.h" #include "delegate.h" void Viewer::init(IconFactoryAccessingHost *iconHost) { iconHost_ = iconHost; setSelectionBehavior(QAbstractItemView::SelectRows); setItemDelegateForColumn(3, new IconDelegate(iconHost_, this)); setItemDelegateForColumn(4, new IconDelegate(iconHost_, this)); setItemDelegateForColumn(1, new LineEditDelegate(this)); setItemDelegateForColumn(2, new LineEditDelegate(this)); QHeaderView *header = horizontalHeader(); #ifdef HAVE_QT5 header->setSectionResizeMode(QHeaderView::ResizeToContents); #else header->setResizeMode(QHeaderView::ResizeToContents); #endif verticalHeader()->setDefaultAlignment( Qt::AlignHCenter ); resizeColumnsToContents(); setFixedSize(header->sectionSize(0)+header->sectionSize(1)+header->sectionSize(2)+ header->sectionSize(3)+header->sectionSize(4)+verticalHeader()->width()+5, 300); //не очень красиво, но по-другому не получилось %) connect(this, SIGNAL(clicked(QModelIndex)), this, SLOT(itemClicked(QModelIndex))); } void Viewer::keyPressEvent(QKeyEvent * e) { if (e->key() == Qt::Key_Space) { foreach(const QModelIndex &check, selectionModel()->selectedRows(0)) { model()->setData(check, 3); //invert } } else { QTableView::keyPressEvent(e); } e->accept(); } void Viewer::contextMenuEvent( QContextMenuEvent * e ) { QMenu *popup = new QMenu(this); QList actions; actions <getIcon("psi/cm_check"), tr("Check"), popup) <getIcon("psi/cm_uncheck"), tr("Uncheck"), popup) <getIcon("psi/cm_invertcheck"), tr("Invert"), popup); popup->addActions(actions); QAction *result = popup->exec(e->globalPos()); int iresult; if (result) { iresult = actions.indexOf(result); foreach(const QModelIndex &check, selectionModel()->selectedRows(0)) { switch (iresult) { case 0: //check model()->setData(check, QVariant(2)); break; case 1: //uncheck model()->setData(check, QVariant(0)); break; case 2: //invert model()->setData(check, QVariant(3)); break; } } } delete popup; } void Viewer::itemClicked(const QModelIndex& index) { if(index.column() == 0) { model()->setData(index, 3); //invert } else if(index.column() == 4) { emit checkSound(index); } else if(index.column() == 3) { emit getSound(index); } } void Viewer::deleteSelected() { QItemSelectionModel *selection = selectionModel(); qobject_cast(model())->deleteRows(selection->selectedRows()); } plugins-1.5/generic/watcherplugin/view.h000066400000000000000000000025561336777360500205040ustar00rootroot00000000000000/* * view.h - plugin * Copyright (C) 2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef VIEW_H #define VIEW_H #include #include class IconFactoryAccessingHost; class Viewer : public QTableView { Q_OBJECT public: Viewer(QWidget *parent = 0) : QTableView(parent) {}; void init(IconFactoryAccessingHost *iconHost); void deleteSelected(); private: IconFactoryAccessingHost *iconHost_; protected: void keyPressEvent(QKeyEvent *e); void contextMenuEvent( QContextMenuEvent * e ); private slots: void itemClicked(const QModelIndex& index); signals: void getSound(const QModelIndex&); void checkSound(const QModelIndex&); }; #endif // VIEW_H plugins-1.5/generic/watcherplugin/watcheditem.cpp000066400000000000000000000036671336777360500223670ustar00rootroot00000000000000/* * watcheditem.cpp - plugin * Copyright (C) 2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "watcheditem.h" WatchedItem::WatchedItem(QListWidget *parent) : QListWidgetItem(parent) , jid_("") , text_("") , sFile_("") , aUse_(false) , groupChat_(false) { } WatchedItem::WatchedItem(const QString &jid, const QString &text, const QString &sFile, bool aUse, QListWidget *parent) : QListWidgetItem(parent) , jid_(jid) , text_(text) , sFile_(sFile) , aUse_(aUse) , groupChat_(false) { } QString WatchedItem::settingsString() const { QStringList l = QStringList() << jid_ << text_ << sFile_; l << (aUse_ ? "1" : "0"); l << (groupChat_ ? "1" : "0"); return l.join(splitStr); } void WatchedItem::setSettings(const QString &settings) { QStringList l = settings.split(splitStr); if(!l.isEmpty()) jid_ = l.takeFirst(); if(!l.isEmpty()) text_ = l.takeFirst(); if(!l.isEmpty()) sFile_ = l.takeFirst(); if(!l.isEmpty()) aUse_ = l.takeFirst().toInt(); if(!l.isEmpty()) groupChat_ = l.takeFirst().toInt(); } WatchedItem* WatchedItem::copy() { WatchedItem *wi = new WatchedItem(); wi->setWatchedText(text_); wi->setJid(jid_); wi->setUse(aUse_); wi->setSFile(sFile_); wi->setText(text()); wi->setGroupChat(groupChat_); return wi; } plugins-1.5/generic/watcherplugin/watcheditem.h000066400000000000000000000034331336777360500220230ustar00rootroot00000000000000/* * watcheditem.h - plugin * Copyright (C) 2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef WATCHEDITEM_H #define WATCHEDITEM_H #include const QString splitStr = "&split&"; class WatchedItem : public QListWidgetItem { public: WatchedItem(QListWidget *parent = 0); WatchedItem(const QString& jid, const QString& text = QString(), const QString& sFile = QString(), bool aUse = false, QListWidget *parent = 0); QString settingsString() const; void setSettings(const QString& settings); void setJid(const QString& jid) { jid_ = jid; }; void setWatchedText(const QString& text) { text_ = text; }; void setSFile(const QString& sFile) { sFile_ = sFile; }; void setUse(bool use) { aUse_ = use; }; void setGroupChat(bool gc) { groupChat_ = gc; }; QString jid() const { return jid_; }; QString watchedText() const { return text_; }; QString sFile() const { return sFile_; }; bool alwaysUse() const { return aUse_; }; bool groupChat() const { return groupChat_; }; WatchedItem* copy(); private: QString jid_, text_, sFile_; bool aUse_, groupChat_; }; #endif // WATCHEDITEM_H plugins-1.5/generic/watcherplugin/watcher.png000066400000000000000000000013201336777360500215100ustar00rootroot00000000000000PNG  IHDRatEXtSoftwareAdobe ImageReadyqe<rIDATx|SKOQf:Ӣ4ADMԍi 5.;\]hBHQ7ƸG/Rmu\}$b<;sr3³/Vj* L|C>Y` 0 x=^r\hxr.01#0iת@-xh4jf3}p^ܳ$Yz(u5lܑL Mޞdt[[?(_*~&0@*B&!b@$ij$Xn`kfm E$Tn蘙ƕy@Qp(-q$QReaAtmu5L;bG%M,l}v E J%D"p?~b$pc7fX,}8Nl$6r1;;Y^*/Hh7cݺ5i{#b;@g767׫@]4W ӊHQFX@ex<.T+f~L'kof>R\^ ׋ÃCsȳerv (VHry5ooM`Y+ˌ3;ӣ{? X\?[IENDB`plugins-1.5/generic/watcherplugin/watcher_on.png000066400000000000000000000014101336777360500222040ustar00rootroot00000000000000PNG  IHDRabKGD pHYs  tIMEHIDAT8}=hYs;јdB@X8&Z XIuPp VTR)[Y1*(%)4$3=ήA4D%$zGkbP23*nb6I[jH RUVdY<:V{fXٞUӻ9~DDP8=!^ZqO:SR#4h #mYm|l*C4hz蟶/VĹ_[hn;ƹ/D/zlV};M&={\סUEU #O9rT> !Ac2c~R)l`H&k F82ƐB`* =EMiSM!qTqz9c 'I9B&`(m,_@!_`"_`PĹ\X=wZ̛ɐnQϝ5$CH"w?ۧдô-1bfs01Pc@j`k@'0ع@W~簈aud5 ;{]FVg$S`c%llyEh7##4YWsyƖsKqhk|q%tHq[LcX Z`h_Z-KsQIENDB`plugins-1.5/generic/watcherplugin/watcherplugin.cpp000066400000000000000000000554071336777360500227440ustar00rootroot00000000000000/* * watcherplugin.cpp - plugin * Copyright (C) 2010 Evgeny Khryukin * * 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include #include #include #include #include "view.h" #include "model.h" #include "ui_options.h" #include "watcheditem.h" #include "edititemdlg.h" #include "psiplugin.h" #include "stanzafilter.h" #include "popupaccessor.h" #include "popupaccessinghost.h" #include "optionaccessor.h" #include "optionaccessinghost.h" #include "iconfactoryaccessor.h" #include "iconfactoryaccessinghost.h" #include "menuaccessor.h" #include "applicationinfoaccessor.h" #include "applicationinfoaccessinghost.h" #include "plugininfoprovider.h" #include "activetabaccessinghost.h" #include "activetabaccessor.h" #include "contactinfoaccessinghost.h" #include "contactinfoaccessor.h" #include "accountinfoaccessinghost.h" #include "accountinfoaccessor.h" #include "soundaccessinghost.h" #include "soundaccessor.h" #include "toolbariconaccessor.h" #define constVersion "0.4.6" #define constSoundFile "sndfl" #define constInterval "intrvl" #define constCount "count" #define constSndFiles "sndfiles" #define constJids "jids" #define constEnabledJids "enjids" #define constWatchedItems "watcheditem" #define constDisableSnd "dsblsnd" #define constDisablePopupDnd "dsblpopupdnd" #define constShowInContext "showincontext" #define POPUP_OPTION_NAME "Watcher Plugin" class Watcher : public QObject, public PsiPlugin, public PopupAccessor, public MenuAccessor, public PluginInfoProvider, public OptionAccessor, public StanzaFilter, public IconFactoryAccessor, public ApplicationInfoAccessor, public ActiveTabAccessor, public ContactInfoAccessor, public AccountInfoAccessor, public SoundAccessor, public ToolbarIconAccessor { Q_OBJECT #ifdef HAVE_QT5 Q_PLUGIN_METADATA(IID "com.psi-plus.Watcher") #endif Q_INTERFACES(PsiPlugin PopupAccessor OptionAccessor StanzaFilter IconFactoryAccessor AccountInfoAccessor PluginInfoProvider MenuAccessor ApplicationInfoAccessor ActiveTabAccessor ContactInfoAccessor SoundAccessor ToolbarIconAccessor) public: Watcher(); virtual QString name() const; virtual QString shortName() const; virtual QString version() const; virtual QWidget* options(); virtual bool enable(); virtual bool disable(); virtual void optionChanged(const QString& option); virtual void applyOptions(); virtual void restoreOptions(); virtual QPixmap icon() const; virtual void setPopupAccessingHost(PopupAccessingHost* host); virtual void setOptionAccessingHost(OptionAccessingHost* host); virtual bool incomingStanza(int account, const QDomElement& xml); virtual bool outgoingStanza(int account, QDomElement& xml); virtual void setIconFactoryAccessingHost(IconFactoryAccessingHost* host); QList < QVariantHash > getAccountMenuParam(); QList < QVariantHash > getContactMenuParam(); virtual QAction* getContactAction(QObject* , int , const QString& ); virtual QAction* getAccountAction(QObject* , int ) { return 0; } virtual void setApplicationInfoAccessingHost(ApplicationInfoAccessingHost* host); virtual QString pluginInfo(); virtual void setActiveTabAccessingHost(ActiveTabAccessingHost* host); virtual void setContactInfoAccessingHost(ContactInfoAccessingHost* host); virtual void setAccountInfoAccessingHost(AccountInfoAccessingHost* host); virtual void setSoundAccessingHost(SoundAccessingHost* host); QList getButtonParam() { return QList(); } QAction* getAction(QObject *parent, int account, const QString &contact); QAction* createAction(QObject *parent, const QString &contact); private: OptionAccessingHost *psiOptions; PopupAccessingHost* popup; IconFactoryAccessingHost* icoHost; ApplicationInfoAccessingHost* appInfoHost; ActiveTabAccessingHost* activeTab; ContactInfoAccessingHost* contactInfo; AccountInfoAccessingHost* accInfo; SoundAccessingHost* sound_; bool enabled; QString soundFile; //int Interval; QPointer optionsWid; Model *model_; Ui::Options ui_; QList items_; bool isSndEnable; bool disableSnd; bool disablePopupDnd; int popupId; QHash actions_; bool showInContext_; bool checkWatchedItem(const QString& from, const QString& body, WatchedItem *wi); private slots: void checkSound(QModelIndex index = QModelIndex()); void getSound(QModelIndex index = QModelIndex()); void addLine(); void delSelected(); void Hack(); void onOptionsClose(); void playSound(const QString& soundFile); void showPopup(int account, const QString& jid, QString text); void addItemAct(); void delItemAct(); void editItemAct(); void addNewItem(const QString& settings); void editCurrentItem(const QString& setting); void timeOut(); void actionActivated(); void removeFromActions(QObject *object); }; #ifndef HAVE_QT5 Q_EXPORT_PLUGIN(Watcher) #endif Watcher::Watcher() : psiOptions(0) , popup(0) , icoHost(0) , appInfoHost(0) , activeTab(0) , contactInfo(0) , accInfo(0) , sound_(0) , enabled(false) , soundFile("sound/watcher.wav") //, Interval(2) , model_(0) , isSndEnable(false) , disableSnd(true) , disablePopupDnd(true) , popupId(0) { } QString Watcher::name() const { return "Watcher Plugin"; } QString Watcher::shortName() const { return "watcher"; } QString Watcher::version() const { return constVersion; } bool Watcher::enable() { if(psiOptions) { enabled = true; soundFile = psiOptions->getPluginOption(constSoundFile, QVariant(soundFile)).toString(); disableSnd = psiOptions->getPluginOption(constDisableSnd, QVariant(disableSnd)).toBool(); disablePopupDnd = psiOptions->getPluginOption(constDisablePopupDnd, QVariant(disablePopupDnd)).toBool(); int interval = psiOptions->getPluginOption(constInterval, QVariant(3000)).toInt()/1000; popupId = popup->registerOption(POPUP_OPTION_NAME, interval, "plugins.options."+shortName()+"."+constInterval); QStringList jids = psiOptions->getPluginOption(constJids, QVariant(QStringList())).toStringList(); QStringList soundFiles = psiOptions->getPluginOption(constSndFiles, QVariant(QStringList())).toStringList(); QStringList enabledJids = psiOptions->getPluginOption(constEnabledJids, QVariant(QStringList())).toStringList(); if (enabledJids.isEmpty()) { for (int i = 0; i < jids.size(); i++) { enabledJids << "true"; } } if(!model_) { model_ = new Model(jids, soundFiles, enabledJids, this); connect(model_, SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(Hack())); } items_.clear(); QStringList list = psiOptions->getPluginOption(constWatchedItems).toStringList(); foreach(const QString& settings, list) { WatchedItem* wi = new WatchedItem(); wi->setSettings(settings); items_.push_back(wi); if(!wi->jid().isEmpty()) wi->setText(wi->jid()); else if(!wi->watchedText().isEmpty()) wi->setText(wi->watchedText()); else wi->setText(tr("Empty item")); } QStringList files; files << "watcher_on" << "watcher"; foreach (QString filename, files) { QFile file(":/icons/" + filename + ".png"); file.open(QIODevice::ReadOnly); QByteArray image = file.readAll(); icoHost->addIcon("watcher/" + filename, image); file.close(); } showInContext_ = psiOptions->getPluginOption(constShowInContext, QVariant(true)).toBool(); } return enabled; } bool Watcher::disable() { delete model_; model_ = 0; qDeleteAll(items_); foreach (QAction* action, actions_) { action->disconnect(); action->deleteLater(); } items_.clear(); actions_.clear(); popup->unregisterOption(POPUP_OPTION_NAME); enabled = false; return true; } QWidget* Watcher::options() { if (!enabled) { return 0; } optionsWid = new QWidget(); connect(optionsWid, SIGNAL(destroyed()), this, SLOT(onOptionsClose())); ui_.setupUi(optionsWid); restoreOptions(); ui_.cb_hack->setVisible(false); ui_.tb_open->setIcon(icoHost->getIcon("psi/browse")); ui_.tb_test->setIcon(icoHost->getIcon("psi/play")); ui_.pb_add->setIcon(icoHost->getIcon("psi/addContact")); ui_.pb_del->setIcon(icoHost->getIcon("psi/remove")); ui_.pb_add_item->setIcon(icoHost->getIcon("psi/addContact")); ui_.pb_delete_item->setIcon(icoHost->getIcon("psi/remove")); ui_.pb_edit_item->setIcon(icoHost->getIcon("psi/action_templates_edit")); ui_.tableView->setModel(model_); ui_.tableView->init(icoHost); ui_.cb_showInContext->setChecked(showInContext_); connect(ui_.tableView, SIGNAL(checkSound(QModelIndex)), this, SLOT(checkSound(QModelIndex))); connect(ui_.tableView, SIGNAL(getSound(QModelIndex)), this, SLOT(getSound(QModelIndex))); connect(ui_.tb_test, SIGNAL(pressed()), this, SLOT(checkSound())); connect(ui_.tb_open, SIGNAL(pressed()), this, SLOT(getSound())); connect(ui_.pb_add, SIGNAL(released()), this, SLOT(addLine())); connect(ui_.pb_del, SIGNAL(released()), this, SLOT(delSelected())); connect(ui_.pb_add_item, SIGNAL(clicked()), this, SLOT(addItemAct())); connect(ui_.pb_delete_item, SIGNAL(clicked()), this, SLOT(delItemAct())); connect(ui_.pb_edit_item, SIGNAL(clicked()), this, SLOT(editItemAct())); connect(ui_.listWidget, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(editItemAct())); return optionsWid; } void Watcher::addLine() { model_->addRow(); Hack(); //activate apply button } void Watcher::delSelected() { ui_.tableView->deleteSelected(); Hack(); //activate apply button } void Watcher::applyOptions() { soundFile = ui_.le_sound->text(); psiOptions->setPluginOption(constSoundFile, QVariant(soundFile)); disableSnd = ui_.cb_disable_snd->isChecked(); psiOptions->setPluginOption(constDisableSnd, QVariant(disableSnd)); // Interval = ui_.sb_delay->value(); // psiOptions->setPluginOption(constInterval,QVariant(Interval)); disablePopupDnd = ui_.cb_disableDnd->isChecked(); psiOptions->setPluginOption(constDisablePopupDnd, QVariant(disablePopupDnd)); model_->apply(); psiOptions->setPluginOption(constEnabledJids, QVariant(model_->getEnabledJids())); psiOptions->setPluginOption(constJids, QVariant(model_->getWatchedJids())); psiOptions->setPluginOption(constSndFiles, QVariant(model_->getSounds())); foreach(WatchedItem *wi, items_) delete(wi); items_.clear(); QStringList l; for(int i = 0; i < ui_.listWidget->count(); i++) { WatchedItem *wi = (WatchedItem*)ui_.listWidget->item(i); if(wi) { items_.push_back(wi->copy()); l.push_back(wi->settingsString()); } } psiOptions->setPluginOption(constWatchedItems, QVariant(l)); showInContext_ = ui_.cb_showInContext->isChecked(); psiOptions->setPluginOption(constShowInContext, QVariant(showInContext_)); } void Watcher::restoreOptions() { ui_.le_sound->setText(soundFile); // ui_.sb_delay->setValue(Interval); ui_.cb_disable_snd->setChecked(disableSnd); ui_.cb_disableDnd->setChecked(disablePopupDnd); model_->reset(); foreach(WatchedItem* wi, items_) { ui_.listWidget->addItem(wi->copy()); } } QPixmap Watcher::icon() const { return QPixmap(":/icons/watcher.png"); } bool Watcher::incomingStanza(int acc, const QDomElement &stanza) { if(enabled) { if(stanza.tagName() == "presence") { if(stanza.attribute("type") == "error") return false; QString from = stanza.attribute("from"); if(from.isEmpty()) return false; bool find = false; int index = model_->indexByJid(from); if(index >= 0) { if (model_->getEnabledJids().at(index) == "true") { find = true; } } else { from = from.split("/").takeFirst(); index = model_->indexByJid(from); if(index >= 0) { if (model_->getEnabledJids().at(index) == "true") { find = true; } } } if(find) { QString status = stanza.firstChildElement("show").text(); if(status.isEmpty()) { if(stanza.attribute("type") == "unavailable") { status = "offline"; } else { status = "online"; if(model_->statusByJid(from) != status && psiOptions->getGlobalOption("options.ui.notifications.sounds.enable").toBool()) { QString snd = model_->soundByJid(from); if(snd.isEmpty()) snd = soundFile; playSound(snd); } } } if(model_->statusByJid(from) != status) { model_->setStatusForJid(from, status); status[0] = status[0].toUpper(); from = stanza.attribute("from"); // нужно быть уверенным, что у нас полный джид const QString bare = from.split("/").first(); QString nick = contactInfo->name(acc, bare); QString text; if(!nick.isEmpty()) from = " [" + from + "]"; text = nick + from + tr(" change status to ") + status; QMetaObject::invokeMethod(this, "showPopup", Qt::QueuedConnection, Q_ARG(int, acc), Q_ARG(const QString&, bare), Q_ARG(QString, text)); } } } else if(stanza.tagName() == "message") { QString body = stanza.firstChildElement("body").text(); if(!body.isEmpty()) { QString from = stanza.attribute("from"); QString type = stanza.attribute("type"); if(disableSnd) { QString jid = activeTab->getJid(); if(jid.split("/").first().toLower() == from.split("/").first().toLower()) return false; } if(type == "groupchat") { foreach(WatchedItem *wi, items_) { if(!wi->groupChat()) continue; if(checkWatchedItem(from, body, wi)) break; } } else { foreach(WatchedItem *wi, items_) { if(wi->groupChat()) continue; if(checkWatchedItem(from, body, wi)) break; } } } } } return false; } bool Watcher::outgoingStanza(int /*account*/, QDomElement& /*xml*/) { return false; } bool Watcher::checkWatchedItem(const QString &from, const QString &body, WatchedItem *wi) { if(!wi->jid().isEmpty() && from.contains(QRegExp(wi->jid(),Qt::CaseInsensitive, QRegExp::Wildcard))) { isSndEnable = psiOptions->getGlobalOption("options.ui.notifications.sounds.enable").toBool(); if(wi->alwaysUse() || isSndEnable) { psiOptions->setGlobalOption("options.ui.notifications.sounds.enable", QVariant(false)); playSound(wi->sFile()); QTimer::singleShot(500, this, SLOT(timeOut())); // включаем все звуки через секунду, чтобы не игралось два звука одновременно return true; } } if(!wi->watchedText().isEmpty()) { foreach(QString txt, wi->watchedText().split(QRegExp("\\s+"), QString::SkipEmptyParts)) { if(body.contains(QRegExp(txt, Qt::CaseInsensitive, QRegExp::Wildcard)) ) { psiOptions->setGlobalOption("options.ui.notifications.sounds.enable", QVariant(false)); playSound(wi->sFile()); QTimer::singleShot(500, this, SLOT(timeOut())); // включаем все звуки через секунду, чтобы не игралось два звука одновременно return true; } } } return false; } void Watcher::timeOut() { psiOptions->setGlobalOption("options.ui.notifications.sounds.enable", QVariant(isSndEnable)); } void Watcher::setPopupAccessingHost(PopupAccessingHost* host) { popup = host; } void Watcher::setIconFactoryAccessingHost(IconFactoryAccessingHost* host) { icoHost = host; } void Watcher::setActiveTabAccessingHost(ActiveTabAccessingHost *host) { activeTab = host; } void Watcher::setOptionAccessingHost(OptionAccessingHost *host) { psiOptions = host; } void Watcher::setApplicationInfoAccessingHost(ApplicationInfoAccessingHost* host) { appInfoHost = host; } void Watcher::setContactInfoAccessingHost(ContactInfoAccessingHost *host) { contactInfo = host; } void Watcher::optionChanged(const QString &option) { Q_UNUSED(option); } void Watcher::setAccountInfoAccessingHost(AccountInfoAccessingHost *host) { accInfo = host; } void Watcher::setSoundAccessingHost(SoundAccessingHost *host) { sound_ = host; } QAction* Watcher::createAction(QObject *parent, const QString &contact) { QStringList jids = model_->getWatchedJids(); QAction *action; if (jids.contains(contact, Qt::CaseInsensitive) && model_->jidEnabled(contact)) { action = new QAction(QIcon(":/icons/watcher_on.png"), tr("Don't watch for JID"), parent); action->setProperty("watch", true); } else { action = new QAction(QIcon(":/icons/watcher.png"), tr("Watch for JID"), parent); action->setProperty("watch", false); } action->setProperty("jid", contact); connect(action, SIGNAL(triggered()), SLOT(actionActivated())); return action; } QAction* Watcher::getAction(QObject *parent, int /*account*/, const QString &contact) { if (!enabled) { return 0; } if (!actions_.contains(contact)) { QAction *action = createAction(parent, contact); connect(action, SIGNAL(destroyed(QObject*)), SLOT(removeFromActions(QObject*))); actions_[contact] = action; } return actions_[contact]; } void Watcher::actionActivated() { QAction *action = qobject_cast(sender()); if (action->property("watch").toBool()) { action->setProperty("watch", false); action->setIcon(QIcon(":/icons/watcher.png")); action->setText(tr("Watch for JID")); model_->setJidEnabled(action->property("jid").toString(), false); } else { action->setProperty("watch", true); action->setIcon(QIcon(":/icons/watcher_on.png")); action->setText(tr("Don't watch for JID")); model_->setJidEnabled(action->property("jid").toString(), true); } model_->apply(); psiOptions->setPluginOption(constEnabledJids, QVariant(model_->getEnabledJids())); psiOptions->setPluginOption(constJids, QVariant(model_->getWatchedJids())); psiOptions->setPluginOption(constSndFiles, QVariant(model_->getSounds())); } void Watcher::removeFromActions(QObject *object) { actions_.remove(object->property("jid").toString()); } void Watcher::playSound(const QString& f) { sound_->playSound(f); } void Watcher::getSound(QModelIndex index) { if(ui_.tb_open->isDown()) { QString fileName = QFileDialog::getOpenFileName(0,tr("Choose a sound file"), psiOptions->getPluginOption(constLastFile, QVariant("")).toString(), tr("Sound (*.wav)")); if(fileName.isEmpty()) return; QFileInfo fi(fileName); psiOptions->setPluginOption(constLastFile, QVariant(fi.absolutePath())); ui_.le_sound->setText(fileName); } else { QString fileName = QFileDialog::getOpenFileName(0,tr("Choose a sound file"), psiOptions->getPluginOption(constLastFile, QVariant("")).toString(), tr("Sound (*.wav)")); if(fileName.isEmpty()) return; QFileInfo fi(fileName); psiOptions->setPluginOption(constLastFile, QVariant(fi.absolutePath())); const QModelIndex editIndex = model_->index(index.row(), 2, QModelIndex()); model_->setData(editIndex, QVariant(fileName)); } } void Watcher::checkSound(QModelIndex index) { if(ui_.tb_test->isDown()) { playSound(ui_.le_sound->text()); } else { playSound(model_->tmpSoundFile(index)); } } void Watcher::showPopup(int account, const QString& jid, QString text) { QVariant suppressDnd = psiOptions->getGlobalOption("options.ui.notifications.passive-popups.suppress-while-dnd"); psiOptions->setGlobalOption("options.ui.notifications.passive-popups.suppress-while-dnd", disablePopupDnd); int interval = popup->popupDuration(POPUP_OPTION_NAME); if(interval) { const QString statusMes = contactInfo->statusMessage(account, jid); if(!statusMes.isEmpty()) { text += tr("
Status Message: %1").arg(statusMes); } popup->initPopupForJid(account, jid, text, tr("Watcher Plugin"), "psi/search", popupId); } psiOptions->setGlobalOption("options.ui.notifications.passive-popups.suppress-while-dnd", suppressDnd); } void Watcher::Hack() { if (!optionsWid.isNull()) { ui_.cb_hack->toggle(); } } void Watcher::onOptionsClose() { model_->reset(); } QList < QVariantHash > Watcher::getAccountMenuParam() { return QList < QVariantHash >(); } QList < QVariantHash > Watcher::getContactMenuParam() { return QList < QVariantHash >(); } QAction* Watcher::getContactAction(QObject *p, int /*account*/, const QString &jid) { if (!enabled || !showInContext_) { return 0; } return createAction(p, jid); } void Watcher::addItemAct() { EditItemDlg *eid = new EditItemDlg(icoHost, psiOptions, optionsWid); connect(eid, SIGNAL(testSound(QString)), this, SLOT(playSound(QString))); connect(eid, SIGNAL(dlgAccepted(QString)), this, SLOT(addNewItem(QString))); eid->show(); } void Watcher::addNewItem(const QString& settings) { WatchedItem *wi = new WatchedItem(ui_.listWidget); wi->setSettings(settings); if(!wi->jid().isEmpty()) wi->setText(wi->jid()); else if(!wi->watchedText().isEmpty()) wi->setText(wi->watchedText()); else wi->setText(tr("Empty item")); Hack(); } void Watcher::delItemAct() { WatchedItem *wi = (WatchedItem*)ui_.listWidget->currentItem(); if(wi) { int index = items_.indexOf(wi); if(index != -1) items_.removeAt(index); delete(wi); Hack(); } } void Watcher::editItemAct() { WatchedItem *wi = (WatchedItem*)ui_.listWidget->currentItem(); if(wi) { EditItemDlg *eid = new EditItemDlg(icoHost, psiOptions, optionsWid); eid->init(wi->settingsString()); connect(eid, SIGNAL(testSound(QString)), this, SLOT(playSound(QString))); connect(eid, SIGNAL(dlgAccepted(QString)), this, SLOT(editCurrentItem(QString))); eid->show(); } } void Watcher::editCurrentItem(const QString& settings) { WatchedItem *wi = (WatchedItem*)ui_.listWidget->currentItem(); if(wi) { wi->setSettings(settings); if(!wi->jid().isEmpty()) wi->setText(wi->jid()); else if(!wi->watchedText().isEmpty()) wi->setText(wi->watchedText()); else wi->setText(tr("Empty item")); Hack(); } } QString Watcher::pluginInfo() { return tr("Author: ") + "Dealer_WeARE\n" + tr("Email: ") + "wadealer@gmail.com\n\n" + trUtf8("This plugin is designed to monitor the status of specific roster contacts, as well as for substitution of standard sounds of incoming messages.\n" "On the first tab set up a list of contacts for the status of which is monitored. When the status of such contacts changes a popup window will be shown" " and when the status changes to online a custom sound can be played." "On the second tab is configured list of items, the messages are being monitored. Each element can contain a regular expression" " to check for matches with JID, from which the message arrives, a list of regular expressions to check for matches with the text" " of an incoming message, the path to sound file which will be played in case of coincidence, as well as the setting, whether the sound" " is played always, even if the global sounds off. "); } #include "watcherplugin.moc" plugins-1.5/generic/watcherplugin/watcherplugin.pro000066400000000000000000000006531336777360500227530ustar00rootroot00000000000000isEmpty(PSISDK) { include(../../psiplugin.pri) } else { include($$PSISDK/plugins/psiplugin.pri) } INCLUDEPATH += $$PWD DEPENDPATH += $$PWD SOURCES += watcherplugin.cpp \ view.cpp \ model.cpp \ delegate.cpp \ watcheditem.cpp \ edititemdlg.cpp HEADERS += view.h \ model.h \ delegate.h \ watcheditem.h \ edititemdlg.h FORMS += options.ui \ edititemdlg.ui RESOURCES += resources.qrc plugins-1.5/unix/000077500000000000000000000000001336777360500140445ustar00rootroot00000000000000plugins-1.5/unix/CMakeLists.txt000066400000000000000000000010771336777360500166110ustar00rootroot00000000000000cmake_minimum_required( VERSION 3.1.0 ) #masked as deprecated. #set( plugins_list # gnome3supportplugin #) #if( "${BUILD_PLUGINS}" STREQUAL "ALL" ) # set( plugins ${plugins_list} ) #else( "${BUILD_PLUGINS}" STREQUAL "ALL" ) # set( plugins "${BUILD_PLUGINS}" ) #endif( "${BUILD_PLUGINS}" STREQUAL "ALL" ) #foreach( plugin ${plugins_list} ) # foreach( subdir ${plugins} ) # if( ${plugin} STREQUAL ${subdir} ) # message("Parse subdirectory: ./${plugin}") # add_subdirectory("./${plugin}") # endif( ${plugin} STREQUAL ${subdir} ) # endforeach(subdir) #endforeach(plugin)