From 3ce36b764fc55bdfc8fe98395cab072d50855e28 Mon Sep 17 00:00:00 2001 From: Andrew Branson Date: Tue, 1 Mar 2016 09:13:06 +0100 Subject: New managers from javispedro AppFetchManager, BlobDBManager --- daemon/appfetchmanager.cc | 106 -------------------------------- daemon/appfetchmanager.cpp | 106 ++++++++++++++++++++++++++++++++ daemon/appmanager.cpp | 14 ++++- daemon/appmanager.h | 5 +- daemon/blobdbmanager.cc | 99 ------------------------------ daemon/blobdbmanager.cpp | 99 ++++++++++++++++++++++++++++++ daemon/daemon.pro | 148 ++++++++++++++++++++++----------------------- daemon/manager.cpp | 7 ++- daemon/manager.h | 8 +-- daemon/timelineitem.h | 5 +- 10 files changed, 306 insertions(+), 291 deletions(-) delete mode 100644 daemon/appfetchmanager.cc create mode 100644 daemon/appfetchmanager.cpp delete mode 100644 daemon/blobdbmanager.cc create mode 100644 daemon/blobdbmanager.cpp diff --git a/daemon/appfetchmanager.cc b/daemon/appfetchmanager.cc deleted file mode 100644 index 9c58e27..0000000 --- a/daemon/appfetchmanager.cc +++ /dev/null @@ -1,106 +0,0 @@ -#include "appfetchmanager.h" -#include "appmanager.h" -#include "uploadmanager.h" -#include "unpacker.h" -#include "packer.h" - -AppFetchManager::AppFetchManager(WatchConnector *watch, UploadManager *upload, AppManager *apps, QObject *parent) - : QObject(parent), l(metaObject()->className()), - watch(watch), upload(upload), apps(apps) - -{ - watch->setEndpointHandler(WatchConnector::watchAPP_FETCH, - [this](const QByteArray &data) { - switch (data.at(0)) { - case WatchConnector::appfetchREQUEST: - handleAppFetchRequest(data); - break; - } - - return true; - }); -} - -void AppFetchManager::handleAppFetchRequest(const QByteArray &msg) -{ - Unpacker u(msg); - quint8 command = u.readLE(); - QUuid uuid = u.readUuid(); - qint32 appId = u.readLE(); - - Q_ASSERT(command == WatchConnector::appfetchREQUEST); - - uploadApp(uuid, appId); -} - -void AppFetchManager::sendAppFetchResponse(WatchConnector::AppFetchMessage command, WatchConnector::AppFetchStatus status) -{ - QByteArray msg; - Packer p(&msg); - - p.writeLE(command); - p.writeLE(status); - - watch->sendMessage(WatchConnector::watchAPP_FETCH, msg); -} - -void AppFetchManager::uploadApp(const QUuid &uuid, quint32 appId) -{ - AppInfo info = apps->info(uuid); - if (info.uuid() != uuid) { - qCWarning(l) << "uuid" << uuid << "is not installed"; - sendAppFetchResponse(WatchConnector::appfetchREQUEST, WatchConnector::appfetchINVALID_UUID); - return; - } - - qCDebug(l) << "about to upload app" << info.shortName(); - - QSharedPointer binaryFile(info.openFile(AppInfo::APPLICATION)); - if (!binaryFile) { - qCWarning(l) << "failed to open" << info.shortName() << "AppInfo::BINARY"; - sendAppFetchResponse(WatchConnector::appfetchREQUEST, WatchConnector::appfetchINVALID_UUID); - return; - } - - qCDebug(l) << "binary file size is" << binaryFile->size(); - - upload->uploadAppBinaryId(appId, binaryFile.data(), info.crcFile(AppInfo::APPLICATION), - [this, info, binaryFile, appId]() { - qCDebug(l) << "app binary upload succesful"; - binaryFile->close(); - - // Upload worker if present - if (info.type() == "worker") { - QSharedPointer workerFile(info.openFile(AppInfo::WORKER)); - if (workerFile) { - upload->uploadAppWorkerId(appId, workerFile.data(), info.crcFile(AppInfo::WORKER), - [this, workerFile]() { - qCDebug(l) << "app worker upload succesful"; - workerFile->close(); - }, [this, workerFile](int code) { - qCWarning(l) << "app worker upload failed" << code; - workerFile->close(); - }); - } - } - - // Proceed to upload the resource file - QSharedPointer resourceFile(info.openFile(AppInfo::RESOURCES)); - if (resourceFile) { - upload->uploadAppResourcesId(appId, resourceFile.data(), info.crcFile(AppInfo::RESOURCES), - [this, resourceFile]() { - qCDebug(l) << "app resources upload succesful"; - resourceFile->close(); - // Upload succesful - }, [this, resourceFile](int code) { - qCWarning(l) << "app resources upload failed" << code; - resourceFile->close(); - }); - } else { - // No resource file - } - }, [this, binaryFile](int code) { - binaryFile->close(); - qCWarning(l) << "app binary upload failed" << code; - }); -} diff --git a/daemon/appfetchmanager.cpp b/daemon/appfetchmanager.cpp new file mode 100644 index 0000000..9c58e27 --- /dev/null +++ b/daemon/appfetchmanager.cpp @@ -0,0 +1,106 @@ +#include "appfetchmanager.h" +#include "appmanager.h" +#include "uploadmanager.h" +#include "unpacker.h" +#include "packer.h" + +AppFetchManager::AppFetchManager(WatchConnector *watch, UploadManager *upload, AppManager *apps, QObject *parent) + : QObject(parent), l(metaObject()->className()), + watch(watch), upload(upload), apps(apps) + +{ + watch->setEndpointHandler(WatchConnector::watchAPP_FETCH, + [this](const QByteArray &data) { + switch (data.at(0)) { + case WatchConnector::appfetchREQUEST: + handleAppFetchRequest(data); + break; + } + + return true; + }); +} + +void AppFetchManager::handleAppFetchRequest(const QByteArray &msg) +{ + Unpacker u(msg); + quint8 command = u.readLE(); + QUuid uuid = u.readUuid(); + qint32 appId = u.readLE(); + + Q_ASSERT(command == WatchConnector::appfetchREQUEST); + + uploadApp(uuid, appId); +} + +void AppFetchManager::sendAppFetchResponse(WatchConnector::AppFetchMessage command, WatchConnector::AppFetchStatus status) +{ + QByteArray msg; + Packer p(&msg); + + p.writeLE(command); + p.writeLE(status); + + watch->sendMessage(WatchConnector::watchAPP_FETCH, msg); +} + +void AppFetchManager::uploadApp(const QUuid &uuid, quint32 appId) +{ + AppInfo info = apps->info(uuid); + if (info.uuid() != uuid) { + qCWarning(l) << "uuid" << uuid << "is not installed"; + sendAppFetchResponse(WatchConnector::appfetchREQUEST, WatchConnector::appfetchINVALID_UUID); + return; + } + + qCDebug(l) << "about to upload app" << info.shortName(); + + QSharedPointer binaryFile(info.openFile(AppInfo::APPLICATION)); + if (!binaryFile) { + qCWarning(l) << "failed to open" << info.shortName() << "AppInfo::BINARY"; + sendAppFetchResponse(WatchConnector::appfetchREQUEST, WatchConnector::appfetchINVALID_UUID); + return; + } + + qCDebug(l) << "binary file size is" << binaryFile->size(); + + upload->uploadAppBinaryId(appId, binaryFile.data(), info.crcFile(AppInfo::APPLICATION), + [this, info, binaryFile, appId]() { + qCDebug(l) << "app binary upload succesful"; + binaryFile->close(); + + // Upload worker if present + if (info.type() == "worker") { + QSharedPointer workerFile(info.openFile(AppInfo::WORKER)); + if (workerFile) { + upload->uploadAppWorkerId(appId, workerFile.data(), info.crcFile(AppInfo::WORKER), + [this, workerFile]() { + qCDebug(l) << "app worker upload succesful"; + workerFile->close(); + }, [this, workerFile](int code) { + qCWarning(l) << "app worker upload failed" << code; + workerFile->close(); + }); + } + } + + // Proceed to upload the resource file + QSharedPointer resourceFile(info.openFile(AppInfo::RESOURCES)); + if (resourceFile) { + upload->uploadAppResourcesId(appId, resourceFile.data(), info.crcFile(AppInfo::RESOURCES), + [this, resourceFile]() { + qCDebug(l) << "app resources upload succesful"; + resourceFile->close(); + // Upload succesful + }, [this, resourceFile](int code) { + qCWarning(l) << "app resources upload failed" << code; + resourceFile->close(); + }); + } else { + // No resource file + } + }, [this, binaryFile](int code) { + binaryFile->close(); + qCWarning(l) << "app binary upload failed" << code; + }); +} diff --git a/daemon/appmanager.cpp b/daemon/appmanager.cpp index 27e1e3f..4e659d3 100644 --- a/daemon/appmanager.cpp +++ b/daemon/appmanager.cpp @@ -2,9 +2,10 @@ #include #include "appmanager.h" -AppManager::AppManager(QObject *parent) +AppManager::AppManager(BlobDbManager *blobDB, QObject *parent) : QObject(parent), l(metaObject()->className()), - _watcher(new QFileSystemWatcher(this)) + _watcher(new QFileSystemWatcher(this)), + blobDB(blobDB) { connect(_watcher, &QFileSystemWatcher::directoryChanged, this, &AppManager::rescan); @@ -18,6 +19,15 @@ AppManager::AppManager(QObject *parent) rescan(); } +void AppManager::refresh() +{ + qCDebug(l) << "pushing available apps to watch"; + foreach (const QUuid &appUuid, appUuids()) { + qDebug() << "Inserting app" << info(appUuid).shortName() << "into BlobDB"; + //blobDB->insert(info(appUuid)); + } +} + QStringList AppManager::appPaths() const { return QStandardPaths::locateAll(QStandardPaths::DataLocation, diff --git a/daemon/appmanager.h b/daemon/appmanager.h index 9fdb977..6f7bdcc 100644 --- a/daemon/appmanager.h +++ b/daemon/appmanager.h @@ -7,6 +7,7 @@ #include #include #include "appinfo.h" +#include "blobdbmanager.h" class AppManager : public QObject { @@ -14,7 +15,7 @@ class AppManager : public QObject QLoggingCategory l; public: - explicit AppManager(QObject *parent = 0); + explicit AppManager(BlobDbManager *blobDB, QObject *parent = 0); QStringList appPaths() const; QList appUuids() const; @@ -23,6 +24,7 @@ public: AppInfo info(const QString &shortName) const; void insertAppInfo(const AppInfo &info); + void refresh(); public slots: void rescan(); @@ -35,6 +37,7 @@ private: private: QFileSystemWatcher *_watcher; + BlobDbManager *blobDB; QHash _apps; QHash _names; }; diff --git a/daemon/blobdbmanager.cc b/daemon/blobdbmanager.cc deleted file mode 100644 index f7a33dd..0000000 --- a/daemon/blobdbmanager.cc +++ /dev/null @@ -1,99 +0,0 @@ -#include "blobdbmanager.h" -#include "unpacker.h" -#include "packer.h" - -BlobDbManager::BlobDbManager(WatchConnector *watch, QObject *parent) : - QObject(parent), l(metaObject()->className()), watch(watch), - lastCookie(0) -{ - watch->setEndpointHandler(WatchConnector::watchBLOB_DB, - [this](const QByteArray &msg) { - handleMessage(msg); - return true; - }); -} - -void BlobDbManager::insert(BlobDatabase db, const QUuid &key, const QByteArray &data, const SuccessCallback &successCallback, const ErrorCallback &errorCallback) -{ - QByteArray msg; - Packer p(&msg); - PendingTransfer transfer; - transfer.cookie = ++lastCookie; - transfer.successCallback = successCallback; - transfer.errorCallback = errorCallback; - - p.writeLE(WatchConnector::blobdbINSERT); - p.writeLE(transfer.cookie); - p.writeLE(db); - - p.writeLE(16); - p.writeUuid(key); - - p.writeLE(data.size()); - msg.append(data); - - pending.insert(transfer.cookie, transfer); - watch->sendMessage(WatchConnector::watchBLOB_DB, msg); -} - -void BlobDbManager::remove(BlobDatabase db, const QUuid &key, const SuccessCallback &successCallback, const ErrorCallback &errorCallback) -{ - QByteArray msg; - Packer p(&msg); - PendingTransfer transfer; - transfer.cookie = ++lastCookie; - transfer.successCallback = successCallback; - transfer.errorCallback = errorCallback; - - p.writeLE(WatchConnector::blobdbINSERT); - p.writeLE(transfer.cookie); - p.writeLE(db); - - p.writeLE(16); - p.writeUuid(key); - - pending.insert(transfer.cookie, transfer); - watch->sendMessage(WatchConnector::watchBLOB_DB, msg); -} - -void BlobDbManager::clear(BlobDatabase db, const SuccessCallback &successCallback, const ErrorCallback &errorCallback) -{ - QByteArray msg; - Packer p(&msg); - PendingTransfer transfer; - transfer.cookie = ++lastCookie; - transfer.successCallback = successCallback; - transfer.errorCallback = errorCallback; - - p.writeLE(WatchConnector::blobdbINSERT); - p.writeLE(transfer.cookie); - p.writeLE(db); - - pending.insert(transfer.cookie, transfer); - watch->sendMessage(WatchConnector::watchBLOB_DB, msg); -} - -void BlobDbManager::handleMessage(const QByteArray &msg) -{ - Unpacker u(msg); - Cookie cookie = u.readLE(); - quint8 status = u.readLE(); - - PendingTransfer transfer = pending.take(cookie); - if (transfer.cookie != cookie) { - qCWarning(l) << "received a message for a cookie we don't know" << cookie; - return; - } - - if (status == 0 || status == WatchConnector::blobdbSUCCESS) { - qCDebug(l) << "success on cookie" << cookie; - if (transfer.successCallback) { - transfer.successCallback(); - } - } else { - qCWarning(l) << "failure on cookie" << cookie << "with status" << status; - if (transfer.errorCallback) { - transfer.errorCallback(WatchConnector::BlobDbStatus(status)); - } - } -} diff --git a/daemon/blobdbmanager.cpp b/daemon/blobdbmanager.cpp new file mode 100644 index 0000000..f7a33dd --- /dev/null +++ b/daemon/blobdbmanager.cpp @@ -0,0 +1,99 @@ +#include "blobdbmanager.h" +#include "unpacker.h" +#include "packer.h" + +BlobDbManager::BlobDbManager(WatchConnector *watch, QObject *parent) : + QObject(parent), l(metaObject()->className()), watch(watch), + lastCookie(0) +{ + watch->setEndpointHandler(WatchConnector::watchBLOB_DB, + [this](const QByteArray &msg) { + handleMessage(msg); + return true; + }); +} + +void BlobDbManager::insert(BlobDatabase db, const QUuid &key, const QByteArray &data, const SuccessCallback &successCallback, const ErrorCallback &errorCallback) +{ + QByteArray msg; + Packer p(&msg); + PendingTransfer transfer; + transfer.cookie = ++lastCookie; + transfer.successCallback = successCallback; + transfer.errorCallback = errorCallback; + + p.writeLE(WatchConnector::blobdbINSERT); + p.writeLE(transfer.cookie); + p.writeLE(db); + + p.writeLE(16); + p.writeUuid(key); + + p.writeLE(data.size()); + msg.append(data); + + pending.insert(transfer.cookie, transfer); + watch->sendMessage(WatchConnector::watchBLOB_DB, msg); +} + +void BlobDbManager::remove(BlobDatabase db, const QUuid &key, const SuccessCallback &successCallback, const ErrorCallback &errorCallback) +{ + QByteArray msg; + Packer p(&msg); + PendingTransfer transfer; + transfer.cookie = ++lastCookie; + transfer.successCallback = successCallback; + transfer.errorCallback = errorCallback; + + p.writeLE(WatchConnector::blobdbINSERT); + p.writeLE(transfer.cookie); + p.writeLE(db); + + p.writeLE(16); + p.writeUuid(key); + + pending.insert(transfer.cookie, transfer); + watch->sendMessage(WatchConnector::watchBLOB_DB, msg); +} + +void BlobDbManager::clear(BlobDatabase db, const SuccessCallback &successCallback, const ErrorCallback &errorCallback) +{ + QByteArray msg; + Packer p(&msg); + PendingTransfer transfer; + transfer.cookie = ++lastCookie; + transfer.successCallback = successCallback; + transfer.errorCallback = errorCallback; + + p.writeLE(WatchConnector::blobdbINSERT); + p.writeLE(transfer.cookie); + p.writeLE(db); + + pending.insert(transfer.cookie, transfer); + watch->sendMessage(WatchConnector::watchBLOB_DB, msg); +} + +void BlobDbManager::handleMessage(const QByteArray &msg) +{ + Unpacker u(msg); + Cookie cookie = u.readLE(); + quint8 status = u.readLE(); + + PendingTransfer transfer = pending.take(cookie); + if (transfer.cookie != cookie) { + qCWarning(l) << "received a message for a cookie we don't know" << cookie; + return; + } + + if (status == 0 || status == WatchConnector::blobdbSUCCESS) { + qCDebug(l) << "success on cookie" << cookie; + if (transfer.successCallback) { + transfer.successCallback(); + } + } else { + qCWarning(l) << "failure on cookie" << cookie << "with status" << status; + if (transfer.errorCallback) { + transfer.errorCallback(WatchConnector::BlobDbStatus(status)); + } + } +} diff --git a/daemon/daemon.pro b/daemon/daemon.pro index 9bfb6d0..0b8d090 100644 --- a/daemon/daemon.pro +++ b/daemon/daemon.pro @@ -1,74 +1,74 @@ -TARGET = pebbled - -CONFIG += console -CONFIG += link_pkgconfig - -QT += core gui qml bluetooth dbus contacts positioning -PKGCONFIG += mlite5 icu-i18n zlib -LIBS += -lquazip -CONFIG += c++11 - -DEFINES += APP_VERSION=\\\"$$VERSION\\\" - -SOURCES += \ - daemon.cpp \ - manager.cpp \ - voicecallmanager.cpp \ - voicecallhandler.cpp \ - notificationmanager.cpp \ - watchconnector.cpp \ - appmanager.cpp \ - musicmanager.cpp \ - datalogmanager.cpp \ - unpacker.cpp \ - appmsgmanager.cpp \ - jskitmanager.cpp \ - appinfo.cpp \ - jskitobjects.cpp \ - packer.cpp \ - bankmanager.cpp \ - uploadmanager.cpp \ - bundle.cpp \ - appfetchmanager.cc \ - blobdbmanager.cc \ - timelineitem.cpp - -HEADERS += \ - manager.h \ - voicecallmanager.h \ - voicecallhandler.h \ - notificationmanager.h \ - watchconnector.h \ - settings.h \ - appmanager.h \ - musicmanager.h \ - unpacker.h \ - datalogmanager.h \ - appmsgmanager.h \ - jskitmanager.h \ - appinfo.h \ - jskitobjects.h \ - packer.h \ - bankmanager.h \ - uploadmanager.h \ - bundle.h \ - appfetchmanager.h \ - blobdbmanager.h \ - timelineitem.h - -DBUS_ADAPTORS += ../org.pebbled.Watch.xml - -OTHER_FILES += js/typedarray.js - -INSTALLS += target systemd js - -target.path = /usr/bin - -systemd.files = $${TARGET}.service -systemd.path = /usr/lib/systemd/user - -js.files = js/* -js.path = /usr/share/pebble/js - -# unnecesary includes, just so QtCreator could find headers... :-( -INCLUDEPATH += $$[QT_HOST_PREFIX]/include/mlite5 $$[QT_HOST_PREFIX]/include/quazip +TARGET = pebbled + +CONFIG += console +CONFIG += link_pkgconfig + +QT += core gui qml bluetooth dbus contacts positioning +PKGCONFIG += mlite5 icu-i18n zlib +LIBS += -lquazip +CONFIG += c++11 + +DEFINES += APP_VERSION=\\\"$$VERSION\\\" + +SOURCES += \ + daemon.cpp \ + manager.cpp \ + voicecallmanager.cpp \ + voicecallhandler.cpp \ + notificationmanager.cpp \ + watchconnector.cpp \ + appmanager.cpp \ + musicmanager.cpp \ + datalogmanager.cpp \ + unpacker.cpp \ + appmsgmanager.cpp \ + jskitmanager.cpp \ + appinfo.cpp \ + jskitobjects.cpp \ + packer.cpp \ + bankmanager.cpp \ + uploadmanager.cpp \ + bundle.cpp \ + timelineitem.cpp \ + blobdbmanager.cpp \ + appfetchmanager.cpp + +HEADERS += \ + manager.h \ + voicecallmanager.h \ + voicecallhandler.h \ + notificationmanager.h \ + watchconnector.h \ + settings.h \ + appmanager.h \ + musicmanager.h \ + unpacker.h \ + datalogmanager.h \ + appmsgmanager.h \ + jskitmanager.h \ + appinfo.h \ + jskitobjects.h \ + packer.h \ + bankmanager.h \ + uploadmanager.h \ + bundle.h \ + appfetchmanager.h \ + blobdbmanager.h \ + timelineitem.h + +DBUS_ADAPTORS += ../org.pebbled.Watch.xml + +OTHER_FILES += js/typedarray.js + +INSTALLS += target systemd js + +target.path = /usr/bin + +systemd.files = $${TARGET}.service +systemd.path = /usr/lib/systemd/user + +js.files = js/* +js.path = /usr/share/pebble/js + +# unnecesary includes, just so QtCreator could find headers... :-( +INCLUDEPATH += $$[QT_HOST_PREFIX]/include/mlite5 $$[QT_HOST_PREFIX]/include/quazip diff --git a/daemon/manager.cpp b/daemon/manager.cpp index 0b365c3..c2e37e2 100644 --- a/daemon/manager.cpp +++ b/daemon/manager.cpp @@ -11,9 +11,10 @@ Manager::Manager(Settings *settings, QObject *parent) : proxy(new PebbledProxy(this)), watch(new WatchConnector(this)), upload(new UploadManager(watch, this)), - apps(new AppManager(this)), + blobdb(new BlobDbManager(watch, this)), + apps(new AppManager(blobdb, this)), bank(new BankManager(watch, upload, apps, this)), - fetch(new AppFetchManager(watch, upload, apps, this)), + fetch(new AppFetchManager(watch, upload, apps, this)), voice(new VoiceCallManager(settings, this)), notifications(new NotificationManager(settings, this)), music(new MusicManager(watch, settings, this)), @@ -59,7 +60,7 @@ Manager::Manager(Settings *settings, QObject *parent) : connect(notifications, SIGNAL(facebookNotify(const QString &,const QString &)), SLOT(onFacebookNotify(const QString &,const QString &))); connect(notifications, SIGNAL(telegramNotify(const QString &,const QString &)), SLOT(onTelegramNotify(const QString &,const QString &))); connect(notifications, SIGNAL(hangoutsNotify(const QString &,const QString &)), SLOT(onHangoutsNotify(const QString &,const QString &))); - connect(notifications, SIGNAL(whatappNotify(const QString &,const QString &)), SLOT(onWhatsappNotify(const QString &,const QString &))); + connect(notifications, SIGNAL(whatsappNotify(const QString &,const QString &)), SLOT(onWhatsappNotify(const QString &,const QString &))); connect(appmsg, &AppMsgManager::appStarted, this, &Manager::onAppOpened); connect(appmsg, &AppMsgManager::appStopped, this, &Manager::onAppClosed); diff --git a/daemon/manager.h b/daemon/manager.h index 5d3b494..56db7fa 100644 --- a/daemon/manager.h +++ b/daemon/manager.h @@ -10,9 +10,9 @@ #include "appmsgmanager.h" #include "jskitmanager.h" #include "appmanager.h" -#include "blobdbmanager.h" +#include "blobdbmanager.h" #include "bankmanager.h" -#include "appfetchmanager.h" +#include "appfetchmanager.h" #include "settings.h" #include @@ -41,10 +41,10 @@ class Manager : public QObject, protected QDBusContext WatchConnector *watch; UploadManager *upload; + BlobDbManager *blobdb; AppManager *apps; - BlobDbManager *blobdb; BankManager *bank; - AppFetchManager *fetch; + AppFetchManager *fetch; VoiceCallManager *voice; NotificationManager *notifications; MusicManager *music; diff --git a/daemon/timelineitem.h b/daemon/timelineitem.h index 9d7850c..778266d 100644 --- a/daemon/timelineitem.h +++ b/daemon/timelineitem.h @@ -31,12 +31,13 @@ public: IconIDTelegram = 0x07, IconIDHangout = 0x08, IconIDGMail = 0x09, - IconIDFlash = 0x0a, // TODO: what service is this? + IconIDFacebookMessenger = 0x0a, IconIDFacebook = 0x0b, IconIDMusic = 0x0c, IconIDAlarm = 0x0d, IconIDWeather = 0x0e, - IconIDGuess = 0x31 + IconIDEmail = 0x13, + IconIDSMS = 0x2d }; enum Color { -- cgit v1.2.3