diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..55a8406 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "thirdparty/gntp-send"] + path = thirdparty/gntp-send + url = https://github.com/Snorenotify/gntp-send.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 026163b..18b2f33 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -52,9 +52,6 @@ else() endif() -find_package( CryptoPP ) -find_package( Boost COMPONENTS system thread) - find_package(Doxygen) if(DOXYGEN_FOUND) @@ -82,6 +79,7 @@ set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) + add_subdirectory(data) add_subdirectory(share) add_subdirectory(src) diff --git a/src/plugins/backends/growl/CMakeLists.txt b/src/plugins/backends/growl/CMakeLists.txt index 9a2fed2..34beb39 100644 --- a/src/plugins/backends/growl/CMakeLists.txt +++ b/src/plugins/backends/growl/CMakeLists.txt @@ -1,37 +1,23 @@ if( WITH_GROWL_BACKEND ) - if(CRYPTOPP_LIBRARIES AND Boost_SYSTEM_LIBRARY) - message( STATUS "Found Boost and Cryptopp, adding libgrowl backend" ) - if(CMAKE_COMPILER_IS_GNUCXX) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fexceptions") - endif(CMAKE_COMPILER_IS_GNUCXX) - set( GROWL__SRC - growl.cpp - ) + message( STATUS "Adding libgrowl backend" ) - add_library(libsnore_backend_growl MODULE ${GROWL__SRC} ) - target_link_libraries(libsnore_backend_growl snorecore ${QT_QTCORE_LIBRARY} ${CRYPTOPP_LIBRARIES} ${Boost_SYSTEM_LIBRARY} ${Boost_THREAD_LIBRARY}) + find_package(Threads REQUIRED) + include_directories(${CMAKE_SOURCE_DIR}/thirdparty/gntp-send/include) - if(MINGW) - #fiexes a multiple defenition error with static boost - SET_TARGET_PROPERTIES(libsnore_backend_growl PROPERTIES LINK_FLAGS -Wl,--allow-multiple-definition COMPILE_FLAGS - "-Wno-undef -Wno-unused-parameter -Wno-unknown-pragmas -Wno-unused-local-typedefs -Wno-missing-field-initializers -Wno-strict-aliasing -Wno-reorder -Wno-unused-variable -Wno-unused-function" ) - endif(MINGW) + set( GROWL_SRC growlbackend.cpp + ${CMAKE_SOURCE_DIR}/thirdparty/gntp-send/src/tcp.c + ${CMAKE_SOURCE_DIR}/thirdparty/gntp-send/src/md5.c + ${CMAKE_SOURCE_DIR}/thirdparty/gntp-send/src/growl.c + ${CMAKE_SOURCE_DIR}/thirdparty/gntp-send/src/growl.cpp) - if(WIN32) - target_link_libraries(libsnore_backend_growl wsock32 ws2_32) - endif(WIN32) + add_library(libsnore_backend_growl MODULE ${GROWL_SRC} ) + target_link_libraries(libsnore_backend_growl snorecore ${QT_QTCORE_LIBRARY} ${CMAKE_THREAD_LIBS_INIT}) + set_target_properties(libsnore_backend_growl PROPERTIES COMPILE_FLAGS "-DGROWL_DLL -DGROWL_CPP_DLL" ) - if(UNIX) - target_link_libraries(libsnore_backend_growl pthread) - endif(UNIX) + if( WIN32 ) + target_link_libraries(libsnore_backend_growl ws2_32 ) + endif() + + install(TARGETS libsnore_backend_growl ${SNORE_PLUGIN_INSTALL_PATH}) - install(TARGETS libsnore_backend_growl ${SNORE_PLUGIN_INSTALL_PATH}) - else(CRYPTOPP_LIBRARIES AND Boost_SYSTEM_LIBRARY) - if(NOT CRYPTOPP_LIBRARIES) - message(STATUS "Cant build the growl backend because the dependency Cryptopp is missing") - endif(NOT CRYPTOPP_LIBRARIES) - if(NOT Boost_SYSTEM_LIBRARY) - message(STATUS "Cant build the growl backend because the dependency BOOST_SYSTEM is missing") - endif(NOT Boost_SYSTEM_LIBRARY) - endif(CRYPTOPP_LIBRARIES AND Boost_SYSTEM_LIBRARY) endif( WITH_GROWL_BACKEND ) diff --git a/src/plugins/backends/growl/gntp.h b/src/plugins/backends/growl/gntp.h deleted file mode 100644 index 10e246e..0000000 --- a/src/plugins/backends/growl/gntp.h +++ /dev/null @@ -1,315 +0,0 @@ -#ifndef gntp_h -#define gntp_h - -//#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 0 -#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -class gntp { -public: -typedef void (*gntp_callback)(const int& id,const std::string& reason,const std::string& data) ; -private: -class callback_reciver{ -public: - boost::asio::ip::tcp::iostream sock; - boost::thread *thread; - gntp_callback callback; - callback_reciver(std::string host,std::string port,gntp_callback callback): - sock(host, port), - thread(NULL), - callback(callback) - {} - - ~callback_reciver(){ - if(thread) - thread->interrupt(); - delete thread; - sock.close(); - } - - void wait_for_callback(){ - std::string line; - int id = 0; - std::string result; - std::string data; - while (std::getline(sock, line)) { - boost::trim(line); - //std::cout << "[" << line << "]" << std::endl; - if (line.find("Notification-ID: ") == 0) id = atoi(line.substr(17).c_str()); - else if(line.find("Notification-Callback-Result: ") == 0) result = line.substr(30); - else if(line.find("Notification-Callback-Context: ") == 0) data = line.substr(31); - else if(line == "\r")break; - } - //std::cout << "[id: " << id <<" reason: "<< result << " data: " << data << "]" << std::endl; - callback(id,result,data); - delete this; - } - - void run(){ - if(!callback) - return; - thread = new boost::thread( boost::bind(&callback_reciver::wait_for_callback, this) ); - } -}; - - - static inline std::string to_hex(CryptoPP::SecByteBlock& in) { - std::string out; - CryptoPP::HexEncoder hex( NULL, true, 2, "" ); - hex.Attach(new CryptoPP::StringSink(out)); - hex.PutMessageEnd(in.begin(), in.size()); - return out; - } - - static std::string sanitize_text(std::string name) { - std::string::size_type n = 0; - while((n = name.find("\r\n", n)) != std::string::npos) - name.erase(n, 1); - return name; - } - - static std::string sanitize_name(std::string name) { - std::string::size_type n = 0; - while((n = name.find("-", n)) != std::string::npos) - name.erase(n, 1); - return name; - } - - - static void recv(boost::asio::ip::tcp::iostream& sock) throw (std::runtime_error) { - std::string error; - while (1) { - std::string line; - if (!std::getline(sock, line)) break; - - //std::cout << "[" << line << "]" << std::endl; - if (line.find("GNTP/1.0 -ERROR") == 0) error = "unknown error"; - if (line.find("Error-Description: ") == 0) error = line.substr(19); - if (line == "\r") break; - } - if (!error.empty()) throw std::range_error(error); - - - } - - callback_reciver * send(const char* method, std::stringstream& stm) throw (std::runtime_error) { - callback_reciver *cbr = new callback_reciver(hostname_, port_,callback_); - if (!cbr->sock) throw std::range_error("can't connect to host"); - - if (!password_.empty()) { - // initialize salt and iv - CryptoPP::SecByteBlock salt(8); - rng.GenerateBlock(salt.begin(), salt.size()); - - // get digest of password+salt hex encoded - CryptoPP::SecByteBlock passtext(CryptoPP::Weak1::MD5::DIGESTSIZE); - CryptoPP::Weak1::MD5 hash; - hash.Update((byte*)password_.c_str(), password_.size()); - hash.Update(salt.begin(), salt.size()); - hash.Final(passtext); - CryptoPP::SecByteBlock digest(CryptoPP::Weak1::MD5::DIGESTSIZE); - hash.CalculateDigest(digest.begin(), passtext.begin(), passtext.size()); - - cbr->sock << "GNTP/1.0 " - << method - << " NONE " - << " " << - sanitize_name(CryptoPP::Weak1::MD5::StaticAlgorithmName()) - << ":" << to_hex(digest) << "." << to_hex(salt) - << "\r\n" - << stm.str() << "\r\n\r\n"; - } else { - cbr->sock << "GNTP/1.0 " - << method - << " NONE\r\n" - << stm.str() << "\r\n"; - } - recv(cbr->sock); - return cbr; - } - - template - callback_reciver *send(const char* method, std::stringstream& stm) throw (std::runtime_error) { - callback_reciver *cbr = new callback_reciver(hostname_, port_,callback_); - if (!cbr->sock) throw std::range_error("can't connect to host"); - - if (!password_.empty()) { - // initialize salt and iv - CryptoPP::SecByteBlock salt(HASH_TYPE::DIGESTSIZE), iv(CIPHER_TYPE::BLOCKSIZE); - rng.GenerateBlock(salt.begin(), salt.size()); - rng.GenerateBlock(iv.begin(), iv.size()); - - // get digest of password+salt hex encoded - CryptoPP::SecByteBlock passtext(HASH_TYPE::DIGESTSIZE); - HASH_TYPE hash; - hash.Update((byte*)password_.c_str(), password_.size()); - hash.Update(salt.begin(), salt.size()); - hash.Final(passtext); - CryptoPP::SecByteBlock digest(HASH_TYPE::DIGESTSIZE); - hash.CalculateDigest(digest.begin(), passtext.begin(), passtext.size()); - - class CryptoPP::CBC_Mode::Encryption - encryptor(passtext.begin(), iv.size(), iv.begin()); - - std::string cipher_text; - CryptoPP::StringSource(stm.str(), true, - new CryptoPP::StreamTransformationFilter(encryptor, - new CryptoPP::StringSink(cipher_text) - ) // StreamTransformationFilter - ); // StringSource - - cbr->sock << "GNTP/1.0 " - << method - << " " - << sanitize_name(CIPHER_TYPE::StaticAlgorithmName()) - << ":" << to_hex(iv) - << " " - << sanitize_name(HASH_TYPE::StaticAlgorithmName()) - << ":" << to_hex(digest) << "." << to_hex(salt) - << "\r\n" - << cipher_text << "\r\n\r\n"; - } else { - cbr->sock << "GNTP/1.0 " - << method - << " NONE\r\n" - << stm.str() << "\r\n"; - } - recv(cbr->sock); - return cbr; - } - - void make_regist(std::stringstream& stm, const char* name) { - stm << "Notification-Name: " << sanitize_text(name) << "\r\n"; - stm << "Notification-Display-Name: " << sanitize_text(name) << "\r\n"; - stm << "Notification-Enabled: True\r\n"; - stm << "\r\n"; - } - - void make_notify(std::stringstream& stm, const char* name, const int id,const char* title, const char* text, const char* icon = NULL, const char* url = NULL,const char *callbackid = NULL) { - stm << "Application-Name: " << sanitize_text(application_) << "\r\n"; - stm << "Notification-Name: " << sanitize_text(name) << "\r\n"; - stm << "Notification-ID: " << id <<"\r\n"; - if (icon) stm << "Notification-Icon: " << sanitize_text(icon) << "\r\n"; - if (url){ - stm << "Notification-Callback-Target: " << sanitize_text(url) << "\r\n"; - }else if(callbackid){ - stm << "Notification-Callback-Context: "<< sanitize_text(callbackid) <<"\r\n"; - stm << "Notification-Callback-Context-Type: string\r\n"; - } - stm << "Notification-Title: " << sanitize_text(title) << "\r\n"; - stm << "Notification-Text: " << sanitize_text(text) << "\r\n"; - stm << "\r\n"; - } - - std::string application_; - std::string hostname_; - std::string port_; - std::string password_; - std::string icon_; - CryptoPP::AutoSeededRandomPool rng; - gntp_callback callback_; - -public: - - gntp(std::string application = "gntp-send", std::string icon = "" ,std::string password = "", - std::string hostname = "localhost", std::string port = "23053") : - application_(application), - password_(password), - hostname_(hostname), - port_(port), - icon_(icon), - callback_(NULL){ } - - - void set_gntp_callback(gntp_callback callback){ - callback_ = callback; - } - - void regist(const char* name) throw (std::runtime_error) { - std::stringstream stm; - stm << "Application-Name: " << sanitize_text(application_) << "\r\n"; - stm << "Application-Icon: " << sanitize_text(icon_) <<"\r\n"; - stm << "Notifications-Count: 1\r\n"; - stm << "\r\n"; - make_regist(stm, name); - callback_reciver *cbr = send("REGISTER", stm); - delete cbr; - } - - void regist(const std::vector names) throw (std::runtime_error) { - std::stringstream stm; - stm << "Application-Name: " << sanitize_text(application_) << "\r\n"; - stm << "Application-Icon: " << sanitize_text(icon_) <<"\r\n"; - stm << "Notifications-Count: " << names.size() << "\r\n"; - stm << "\r\n"; - std::vector::const_iterator it; - for (it = names.begin(); it != names.end(); it++) { - make_regist(stm, it->c_str()); - } - callback_reciver *cbr = send("REGISTER", stm); - delete cbr; - } - - template - void regist(const char* name) throw (std::runtime_error) { - std::stringstream stm; - stm << "Application-Name: " << sanitize_text(application_) << "\r\n"; - stm << "Application-Icon: " << sanitize_text(icon_) <<"\r\n"; - stm << "Notifications-Count: 1\r\n"; - stm << "\r\n"; - make_regist(stm, name); - callback_reciver *cbr = send("REGISTER", stm); - delete cbr; - } - - template - void regist(const std::vector names) throw (std::runtime_error) { - std::stringstream stm; - stm << "Application-Name: " << sanitize_text(application_) << "\r\n"; - stm << "Application-Icon: " << sanitize_text(icon_) <<"\r\n"; - stm << "Notifications-Count: " << names.size() << "\r\n"; - stm << "\r\n"; - std::vector::const_iterator it; - for (it = names.begin(); it != names.end(); it++) { - make_regist(stm, it->c_str()); - } - callback_reciver *cbr = send("REGISTER", stm); - delete cbr; - } - - void notify(const char* name,const int id, const char* title, const char* text, const char* icon = NULL, const char* url = NULL,const char *callbackid = NULL) throw (std::runtime_error) { - std::stringstream stm; - make_notify(stm, name, id, title, text, icon, url,callbackid); - callback_reciver *cbr = send("NOTIFY", stm); - cbr->run(); - } - - template - void notify(const char* name,const int id, const char* title, const char* text, const char* icon = NULL, const char* url = NULL,const char *callbackid = NULL) throw (std::runtime_error) { - std::stringstream stm; - make_notify(stm, name, id, title, text, icon, url,callbackid); - callback_reciver *cbr = send("NOTIFY", stm); - cbr->run(); - } -}; - -#endif - -// vim:set et: diff --git a/src/plugins/backends/growl/growl.cpp b/src/plugins/backends/growl/growl.cpp deleted file mode 100644 index 330ffbe..0000000 --- a/src/plugins/backends/growl/growl.cpp +++ /dev/null @@ -1,141 +0,0 @@ -/* - SnoreNotify is a Notification Framework based on Qt - Copyright (C) 2013-2014 Patrick von Reth - - - SnoreNotify is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - SnoreNotify 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 Lesser General Public License - along with SnoreNotify. If not, see . -*/ - -#include "growl.h" -#include "gntp.h" - -#include "core/snore.h" -#include "core/snore_p.h" - - -#include -#include - -using namespace Snore; - -Q_EXPORT_PLUGIN2(libsnore_backend_growl,Growl) - -Growl *Growl::s_instance = NULL; - -Growl::Growl(): - SnoreBackend("Growl",false,false), - m_id(0) -{ - s_instance = this; -} - -Growl::~Growl() -{ -} - -bool Growl::initialize(SnoreCore *snore) -{ - - QTcpSocket qsocket; - qsocket.connectToHost("localhost", 23053); - if(qsocket.waitForConnected(100)) - { - qsocket.write(QString("GNTP/1.0\r\n").toUtf8()); - if(qsocket.waitForReadyRead(100)) - { - snoreDebug( SNORE_DEBUG ) << QString::fromUtf8(qsocket.readAll()); - return SnoreBackend::initialize(snore); - } - } - snoreDebug( SNORE_DEBUG ) << "Growl is not running"; - return false; - -} - -void Growl::slotRegisterApplication(const Application &application) -{ - gntp *growl = new gntp(application.name().toUtf8().constData(),application.icon().localUrl().toUtf8().constData()); - - gntp::gntp_callback callback(&Growl::gntpCallback); - growl->set_gntp_callback(callback); - - // snoreDebug( SNORE_DEBUG ) << application.name().toUtf8().constData(); - std::vector alerts; - foreach(const Alert &a,application.alerts()) - { - snoreDebug( SNORE_DEBUG ) << a.name().toUtf8().constData(); - alerts.push_back(a.name().toUtf8().constData()); - } - - try - { - growl->regist(alerts); - }catch(const std::exception& e) - { - snoreDebug( SNORE_WARNING ) << e.what(); - } - m_applications.insert(application.name(),growl); -} - -void Growl::slotDeregisterApplication(const Application &application) -{ - gntp *growl = m_applications.take(application.name()); - if(growl == NULL) - { - return; - } - delete growl; -} - -void Growl::slotNotify(Notification notification) -{ - gntp *growl = m_applications.value(notification.application().name()); - QString alert = notification.alert().name(); - snoreDebug( SNORE_DEBUG ) << "Notify Growl:" <notify(alert.toUtf8().constData(),notification.id(), - Snore::toPlainText(notification.title()).toUtf8().constData(), - Snore::toPlainText(notification.text()).toUtf8().constData(), - notification.icon().localUrl().isEmpty()?NULL:notification.icon().localUrl().toUtf8().constData(),NULL,"1"); - - } - catch(const std::exception& e) - { - snoreDebug( SNORE_WARNING ) << e.what(); - } - startTimeout(notification); -} - -void Growl::gntpCallback(const int &id,const std::string &reason,const std::string &data) -{ - // snoreDebug( SNORE_DEBUG ) << id << QString(reason.c_str()) << QString(data.c_str()); - Notification n = s_instance->snore()->getActiveNotificationByID(id); - Notification::CloseReasons r = Notification::NONE; - if(reason == "TIMEDOUT") - { - r = Notification::TIMED_OUT; - } - else if(reason == "CLOSED") - { - r = Notification::DISMISSED; - } - else if(reason == "CLICK") - { - r = Notification::CLOSED; - s_instance->snore()->d()->notificationActionInvoked(n); - } - s_instance->closeNotification(n,r); -} - diff --git a/src/plugins/backends/growl/growlbackend.cpp b/src/plugins/backends/growl/growlbackend.cpp new file mode 100644 index 0000000..907b6fc --- /dev/null +++ b/src/plugins/backends/growl/growlbackend.cpp @@ -0,0 +1,146 @@ +/* + SnoreNotify is a Notification Framework based on Qt + Copyright (C) 2013-2014 Patrick von Reth + + + SnoreNotify is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + SnoreNotify 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 Lesser General Public License + along with SnoreNotify. If not, see . +*/ + +#include "growlbackend.h" + +#include "core/snore.h" +#include "core/snore_p.h" + + + + +#include +#include + +using namespace Snore; + +Q_EXPORT_PLUGIN2(libsnore_backend_growl,GrowlBackend) + +GrowlBackend *GrowlBackend::s_instance = NULL; + +GrowlBackend::GrowlBackend(): + SnoreBackend("Growl",false,false), + m_id(0) +{ + +} + +GrowlBackend::~GrowlBackend() +{ +} + +bool GrowlBackend::initialize(SnoreCore *snore) +{ + + QTcpSocket qsocket; + qsocket.connectToHost("localhost", 23053); + if(qsocket.waitForConnected(100)) + { + qsocket.write(QString("GNTP/1.0\r\n").toUtf8()); + if(qsocket.waitForReadyRead(100)) + { + snoreDebug( SNORE_DEBUG ) << QString::fromUtf8(qsocket.readAll()); + s_instance = this; + Growl::setCallback((GROWL_CALLBACK)&GrowlBackend::gntpCallback); + return SnoreBackend::initialize(snore); + } + } + snoreDebug( SNORE_DEBUG ) << "Growl is not running"; + return false; + +} + +bool GrowlBackend::deinitialize() +{ + s_instance = NULL; + return SnoreBackend::deinitialize(); +} + +void GrowlBackend::slotRegisterApplication(const Application &application) +{ + // snoreDebug( SNORE_DEBUG ) << application.name().toUtf8().constData(); + std::vector alerts; + foreach(const Alert &a,application.alerts()) + { + snoreDebug( SNORE_DEBUG ) << a.name().toUtf8().constData(); + alerts.push_back(a.name().toUtf8().constData()); + } + + Growl *growl = new Growl(GROWL_TCP, "", application.name().toUtf8().constData()); + growl->Register(alerts,application.icon().localUrl().toUtf8().constData()); + + m_applications.insert(application.name(),growl); +} + +void GrowlBackend::slotDeregisterApplication(const Application &application) +{ + Growl *growl = m_applications.take(application.name()); + if(growl == NULL) + { + return; + } + delete growl; +} + +void GrowlBackend::slotNotify(Notification notification) +{ + Growl *growl = m_applications.value(notification.application().name()); + QString alert = notification.alert().name(); + snoreDebug( SNORE_DEBUG ) << "Notify Growl:" <Notify(data); + + + startTimeout(notification); +} + +void GrowlBackend::gntpCallback(growl_callback_data *data) +{ + if(s_instance) + { + snoreDebug( SNORE_DEBUG ) << data->id << QString(data->reason) << QString(data->data); + Notification n = s_instance->snore()->getActiveNotificationByID(data->id); + Notification::CloseReasons r = Notification::NONE; + std::string reason(data->reason); + if(reason == "TIMEDOUT") + { + r = Notification::TIMED_OUT; + } + else if(reason == "CLOSED") + { + r = Notification::DISMISSED; + } + else if(reason == "CLICK") + { + r = Notification::CLOSED; + s_instance->snore()->d()->notificationActionInvoked(n); + } + s_instance->closeNotification(n,r); + } +} + diff --git a/src/plugins/backends/growl/growl.h b/src/plugins/backends/growl/growlbackend.h similarity index 83% rename from src/plugins/backends/growl/growl.h rename to src/plugins/backends/growl/growlbackend.h index 05cddf5..3a3fbd1 100644 --- a/src/plugins/backends/growl/growl.h +++ b/src/plugins/backends/growl/growlbackend.h @@ -21,26 +21,28 @@ #define GROWL_BACKEND_H #include "core/plugins/snorebackend.h" +#include #include -class Growl:public Snore::SnoreBackend +class GrowlBackend:public Snore::SnoreBackend { Q_OBJECT Q_INTERFACES(Snore::SnoreBackend) Q_PLUGIN_METADATA(IID "org.Snore.NotificationBackend/1.0") public: - Growl(); - ~Growl(); + GrowlBackend(); + ~GrowlBackend(); virtual bool initialize(Snore::SnoreCore *snore); + virtual bool deinitialize(); - static void gntpCallback(const int &id,const std::string &reason,const std::string &data); + static void gntpCallback(growl_callback_data *data); private: //a static instance for the static callback methode - static Growl *s_instance; + static GrowlBackend *s_instance; uint m_id; - QHash m_applications; + QHash m_applications; public slots: void slotRegisterApplication(const Snore::Application &application); diff --git a/thirdparty/gntp-send b/thirdparty/gntp-send new file mode 160000 index 0000000..81b30b5 --- /dev/null +++ b/thirdparty/gntp-send @@ -0,0 +1 @@ +Subproject commit 81b30b5ec6f0cf61650e8f371a487f2f07af52d1