blob: dce0b03c5f4c7c6dd1391a8936a971205ff37554 [file] [log] [blame]
Yingdi Yu348f5ea2014-03-01 14:47:25 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
2/*
3 * Copyright (c) 2013, Regents of the University of California
4 * Yingdi Yu
5 *
6 * BSD license, See the LICENSE file for more information
7 *
8 * Author: Yingdi Yu <yingdi@cs.ucla.edu>
9 */
10
11#include <QApplication>
12#include <QMessageBox>
13#include <QDir>
14#include <QTimer>
Yingdi Yu0b0a7362014-08-05 16:31:30 -070015#include "controller.hpp"
Yingdi Yu348f5ea2014-03-01 14:47:25 -080016
17#ifndef Q_MOC_RUN
18#include <boost/filesystem.hpp>
19#include <boost/lexical_cast.hpp>
Yingdi Yufa0b6a02014-04-30 14:26:42 -070020#include <ndn-cxx/util/random.hpp>
Yingdi Yu0b0a7362014-08-05 16:31:30 -070021#include "cryptopp.hpp"
Yingdi Yu348f5ea2014-03-01 14:47:25 -080022#include "config.pb.h"
23#include "endorse-info.pb.h"
24#include "logging.h"
25#endif
26
Yingdi Yueb692ac2015-02-10 18:46:18 -080027INIT_LOGGER("chronochat.Controller");
Yingdi Yu348f5ea2014-03-01 14:47:25 -080028
29Q_DECLARE_METATYPE(ndn::Name)
30Q_DECLARE_METATYPE(ndn::IdentityCertificate)
Yingdi Yueb692ac2015-02-10 18:46:18 -080031Q_DECLARE_METATYPE(chronochat::EndorseInfo)
Yingdi Yu233a9722014-03-07 15:47:09 -080032Q_DECLARE_METATYPE(ndn::Interest)
33Q_DECLARE_METATYPE(size_t)
Yingdi Yueb692ac2015-02-10 18:46:18 -080034Q_DECLARE_METATYPE(chronochat::ChatroomInfo)
35Q_DECLARE_METATYPE(chronochat::Invitation)
Qiuhan Ding43c8e162015-02-02 15:16:48 -080036Q_DECLARE_METATYPE(std::string)
37Q_DECLARE_METATYPE(ndn::Name::Component)
Yingdi Yu348f5ea2014-03-01 14:47:25 -080038
Yingdi Yueb692ac2015-02-10 18:46:18 -080039namespace chronochat {
Yingdi Yu348f5ea2014-03-01 14:47:25 -080040
Yingdi Yu0b0a7362014-08-05 16:31:30 -070041using std::string;
42
Yingdi Yu348f5ea2014-03-01 14:47:25 -080043// constructor & destructor
Yingdi Yu2c9e7712014-10-20 11:55:05 -070044Controller::Controller(QWidget* parent)
Yingdi Yu348f5ea2014-03-01 14:47:25 -080045 : QDialog(parent)
Yingdi Yubaaaec02014-09-02 22:05:32 -070046 , m_localPrefixDetected(false)
Qiuhan Ding43c8e162015-02-02 15:16:48 -080047 , m_settingDialog(new SettingDialog(this))
48 , m_startChatDialog(new StartChatDialog(this))
49 , m_profileEditor(new ProfileEditor(this))
50 , m_invitationDialog(new InvitationDialog(this))
51 , m_contactPanel(new ContactPanel(this))
52 , m_browseContactDialog(new BrowseContactDialog(this))
53 , m_addContactPanel(new AddContactPanel(this))
54 , m_discoveryPanel(new DiscoveryPanel(this))
Yingdi Yu348f5ea2014-03-01 14:47:25 -080055{
56 qRegisterMetaType<ndn::Name>("ndn.Name");
57 qRegisterMetaType<ndn::IdentityCertificate>("ndn.IdentityCertificate");
Yingdi Yueb692ac2015-02-10 18:46:18 -080058 qRegisterMetaType<chronochat::EndorseInfo>("chronochat.EndorseInfo");
Yingdi Yu233a9722014-03-07 15:47:09 -080059 qRegisterMetaType<ndn::Interest>("ndn.Interest");
60 qRegisterMetaType<size_t>("size_t");
Qiuhan Ding43c8e162015-02-02 15:16:48 -080061 qRegisterMetaType<chronochat::ChatroomInfo>("chronochat.Chatroom");
62 qRegisterMetaType<chronochat::Invitation>("chronochat.Invitation");
63 qRegisterMetaType<std::string>("std.string");
64 qRegisterMetaType<ndn::Name::Component>("ndn.Component");
65
Yingdi Yu348f5ea2014-03-01 14:47:25 -080066
67 // Connection to ContactManager
Yingdi Yu2c9e7712014-10-20 11:55:05 -070068 connect(m_backend.getContactManager(), SIGNAL(warning(const QString&)),
Yingdi Yu348f5ea2014-03-01 14:47:25 -080069 this, SLOT(onWarning(const QString&)));
70 connect(this, SIGNAL(refreshBrowseContact()),
Yingdi Yu2c9e7712014-10-20 11:55:05 -070071 m_backend.getContactManager(), SLOT(onRefreshBrowseContact()));
72 connect(m_backend.getContactManager(), SIGNAL(contactInfoFetchFailed(const QString&)),
Yingdi Yu348f5ea2014-03-01 14:47:25 -080073 this, SLOT(onWarning(const QString&)));
Yingdi Yu348f5ea2014-03-01 14:47:25 -080074
75 // Connection to SettingDialog
76 connect(this, SIGNAL(identityUpdated(const QString&)),
77 m_settingDialog, SLOT(onIdentityUpdated(const QString&)));
78 connect(m_settingDialog, SIGNAL(identityUpdated(const QString&)),
79 this, SLOT(onIdentityUpdated(const QString&)));
80 connect(m_settingDialog, SIGNAL(nickUpdated(const QString&)),
81 this, SLOT(onNickUpdated(const QString&)));
Yingdi Yubaaaec02014-09-02 22:05:32 -070082 connect(m_settingDialog, SIGNAL(prefixUpdated(const QString&)),
83 this, SLOT(onLocalPrefixConfigured(const QString&)));
Yingdi Yu348f5ea2014-03-01 14:47:25 -080084
85 // Connection to ProfileEditor
86 connect(this, SIGNAL(closeDBModule()),
87 m_profileEditor, SLOT(onCloseDBModule()));
88 connect(this, SIGNAL(identityUpdated(const QString&)),
89 m_profileEditor, SLOT(onIdentityUpdated(const QString&)));
90 connect(m_profileEditor, SIGNAL(updateProfile()),
Yingdi Yu2c9e7712014-10-20 11:55:05 -070091 m_backend.getContactManager(), SLOT(onUpdateProfile()));
Yingdi Yu348f5ea2014-03-01 14:47:25 -080092
93 // Connection to StartChatDialog
94 connect(m_startChatDialog, SIGNAL(startChatroom(const QString&, bool)),
95 this, SLOT(onStartChatroom(const QString&, bool)));
96
97 // Connection to InvitationDialog
98 connect(m_invitationDialog, SIGNAL(invitationResponded(const ndn::Name&, bool)),
Yingdi Yu2c9e7712014-10-20 11:55:05 -070099 &m_backend, SLOT(onInvitationResponded(const ndn::Name&, bool)));
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800100
101 // Connection to AddContactPanel
102 connect(m_addContactPanel, SIGNAL(fetchInfo(const QString&)),
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700103 m_backend.getContactManager(), SLOT(onFetchContactInfo(const QString&)));
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800104 connect(m_addContactPanel, SIGNAL(addContact(const QString&)),
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700105 m_backend.getContactManager(), SLOT(onAddFetchedContact(const QString&)));
106 connect(m_backend.getContactManager(),
Yingdi Yueb692ac2015-02-10 18:46:18 -0800107 SIGNAL(contactEndorseInfoReady(const chronochat::EndorseInfo&)),
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700108 m_addContactPanel,
Yingdi Yueb692ac2015-02-10 18:46:18 -0800109 SLOT(onContactEndorseInfoReady(const chronochat::EndorseInfo&)));
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800110
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800111 // Connection to BrowseContactDialog
112 connect(m_browseContactDialog, SIGNAL(directAddClicked()),
113 this, SLOT(onDirectAdd()));
114 connect(m_browseContactDialog, SIGNAL(fetchIdCert(const QString&)),
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700115 m_backend.getContactManager(), SLOT(onFetchIdCert(const QString&)));
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800116 connect(m_browseContactDialog, SIGNAL(addContact(const QString&)),
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700117 m_backend.getContactManager(), SLOT(onAddFetchedContactIdCert(const QString&)));
118 connect(m_backend.getContactManager(), SIGNAL(idCertNameListReady(const QStringList&)),
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800119 m_browseContactDialog, SLOT(onIdCertNameListReady(const QStringList&)));
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700120 connect(m_backend.getContactManager(), SIGNAL(nameListReady(const QStringList&)),
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800121 m_browseContactDialog, SLOT(onNameListReady(const QStringList&)));
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700122 connect(m_backend.getContactManager(), SIGNAL(idCertReady(const ndn::IdentityCertificate&)),
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800123 m_browseContactDialog, SLOT(onIdCertReady(const ndn::IdentityCertificate&)));
124
125 // Connection to ContactPanel
126 connect(m_contactPanel, SIGNAL(waitForContactList()),
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700127 m_backend.getContactManager(), SLOT(onWaitForContactList()));
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800128 connect(m_contactPanel, SIGNAL(waitForContactInfo(const QString&)),
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700129 m_backend.getContactManager(), SLOT(onWaitForContactInfo(const QString&)));
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800130 connect(m_contactPanel, SIGNAL(removeContact(const QString&)),
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700131 m_backend.getContactManager(), SLOT(onRemoveContact(const QString&)));
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800132 connect(m_contactPanel, SIGNAL(updateAlias(const QString&, const QString&)),
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700133 m_backend.getContactManager(), SLOT(onUpdateAlias(const QString&, const QString&)));
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800134 connect(m_contactPanel, SIGNAL(updateIsIntroducer(const QString&, bool)),
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700135 m_backend.getContactManager(), SLOT(onUpdateIsIntroducer(const QString&, bool)));
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800136 connect(m_contactPanel, SIGNAL(updateEndorseCertificate(const QString&)),
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700137 m_backend.getContactManager(), SLOT(onUpdateEndorseCertificate(const QString&)));
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800138 connect(m_contactPanel, SIGNAL(warning(const QString&)),
139 this, SLOT(onWarning(const QString&)));
140 connect(this, SIGNAL(closeDBModule()),
141 m_contactPanel, SLOT(onCloseDBModule()));
142 connect(this, SIGNAL(identityUpdated(const QString&)),
143 m_contactPanel, SLOT(onIdentityUpdated(const QString&)));
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700144 connect(m_backend.getContactManager(), SIGNAL(contactAliasListReady(const QStringList&)),
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800145 m_contactPanel, SLOT(onContactAliasListReady(const QStringList&)));
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700146 connect(m_backend.getContactManager(), SIGNAL(contactIdListReady(const QStringList&)),
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800147 m_contactPanel, SLOT(onContactIdListReady(const QStringList&)));
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700148 connect(m_backend.getContactManager(), SIGNAL(contactInfoReady(const QString&, const QString&,
149 const QString&, bool)),
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700150 m_contactPanel, SLOT(onContactInfoReady(const QString&, const QString&,
151 const QString&, bool)));
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800152
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700153 // Connection to backend thread
154 connect(this, SIGNAL(shutdownBackend()),
155 &m_backend, SLOT(shutdown()));
156 connect(this, SIGNAL(updateLocalPrefix()),
157 &m_backend, SLOT(onUpdateLocalPrefixAction()));
158 connect(this, SIGNAL(identityUpdated(const QString&)),
159 &m_backend, SLOT(onIdentityChanged(const QString&)));
160 connect(this, SIGNAL(addChatroom(QString)),
161 &m_backend, SLOT(addChatroom(QString)));
162 connect(this, SIGNAL(removeChatroom(QString)),
163 &m_backend, SLOT(removeChatroom(QString)));
164
165 // Thread notifications:
166 // on local prefix udpated:
167 connect(&m_backend, SIGNAL(localPrefixUpdated(const QString&)),
168 this, SLOT(onLocalPrefixUpdated(const QString&)));
169 connect(&m_backend, SIGNAL(localPrefixUpdated(const QString&)),
170 m_settingDialog, SLOT(onLocalPrefixUpdated(const QString&)));
171
172 // on invitation validated:
173 connect(&m_backend, SIGNAL(invitaionValidated(QString, QString, ndn::Name)),
174 m_invitationDialog, SLOT(onInvitationReceived(QString, QString, ndn::Name)));
175
176 // on invitation accepted:
Yingdi Yueb692ac2015-02-10 18:46:18 -0800177 connect(&m_backend, SIGNAL(startChatroomOnInvitation(chronochat::Invitation, bool)),
178 this, SLOT(onStartChatroom2(chronochat::Invitation, bool)));
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700179
180 m_backend.start();
Mengjin Yan391d7242014-08-28 20:51:55 -0700181
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800182 initialize();
183
Qiuhan Ding43c8e162015-02-02 15:16:48 -0800184 m_chatroomDiscoveryBackend
185 = new ChatroomDiscoveryBackend(m_localPrefix,
186 m_identity,
187 this);
188
189 // connect to chatroom discovery back end
190 connect(&m_backend, SIGNAL(localPrefixUpdated(const QString&)),
191 m_chatroomDiscoveryBackend, SLOT(updateRoutingPrefix(const QString&)));
192 connect(this, SIGNAL(localPrefixConfigured(const QString&)),
193 m_chatroomDiscoveryBackend, SLOT(updateRoutingPrefix(const QString&)));
194 connect(this, SIGNAL(newChatroomForDiscovery(Name::Component)),
195 m_chatroomDiscoveryBackend, SLOT(onNewChatroomForDiscovery(Name::Component)));
196 connect(m_chatroomDiscoveryBackend, SIGNAL(chatroomInfoRequest(std::string, bool)),
197 this, SLOT(onChatroomInfoRequest(std::string, bool)));
198 connect(this, SIGNAL(respondChatroomInfoRequest(ChatroomInfo, bool)),
199 m_chatroomDiscoveryBackend, SLOT(onRespondChatroomInfoRequest(ChatroomInfo, bool)));
200 connect(this, SIGNAL(shutdownDiscoveryBackend()),
201 m_chatroomDiscoveryBackend, SLOT(shutdown()));
202 connect(this, SIGNAL(identityUpdated(const QString&)),
203 m_chatroomDiscoveryBackend, SLOT(onIdentityUpdated(const QString&)));
204
205 // connect chatroom discovery back end with front end
206 connect(m_discoveryPanel, SIGNAL(waitForChatroomInfo(const QString&)),
207 m_chatroomDiscoveryBackend, SLOT(onWaitForChatroomInfo(const QString&)));
208 connect(m_discoveryPanel, SIGNAL(warning(const QString&)),
209 this, SLOT(onWarning(const QString&)));
210 connect(this, SIGNAL(identityUpdated(const QString&)),
211 m_discoveryPanel, SLOT(onIdentityUpdated(const QString&)));
212 connect(m_chatroomDiscoveryBackend, SIGNAL(chatroomListReady(const QStringList&)),
213 m_discoveryPanel, SLOT(onChatroomListReady(const QStringList&)));
214 connect(m_chatroomDiscoveryBackend, SIGNAL(chatroomInfoReady(const ChatroomInfo&)),
215 m_discoveryPanel, SLOT(onChatroomInfoReady(const ChatroomInfo&)));
216 connect(m_discoveryPanel, SIGNAL(startChatroom(const QString&, bool)),
217 this, SLOT(onStartChatroom(const QString&, bool)));
218
219 m_chatroomDiscoveryBackend->start();
220
Yingdi Yu233a9722014-03-07 15:47:09 -0800221 createTrayIcon();
222
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700223 emit updateLocalPrefix();
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800224}
Yingdi Yufa0b6a02014-04-30 14:26:42 -0700225
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800226Controller::~Controller()
227{
228 saveConf();
229}
230
231// public methods
232
233
234// private methods
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700235string
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800236Controller::getDBName()
237{
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700238 string dbName("chronos-");
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800239
240 std::stringstream ss;
241 {
242 using namespace CryptoPP;
243
244 SHA256 hash;
245 StringSource(m_identity.wireEncode().wire(), m_identity.wireEncode().size(), true,
246 new HashFilter(hash, new HexEncoder(new FileSink(ss), false)));
247 }
248 dbName.append(ss.str()).append(".db");
249
250 return dbName;
251}
252
253void
254Controller::openDB()
255{
256 m_db = QSqlDatabase::addDatabase("QSQLITE");
257 QString path = (QDir::home().path());
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700258 path.append(QDir::separator())
259 .append(".chronos")
260 .append(QDir::separator())
261 .append(getDBName().c_str());
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800262 m_db.setDatabaseName(path);
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800263
Yingdi Yu42125862014-08-07 17:04:28 -0700264 m_db.open();
265
266 // bool ok = m_db.open();
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700267 // _LOG_DEBUG("DB opened: " << std::boolalpha << ok );
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800268}
269
270void
271Controller::initialize()
272{
273 loadConf();
Yingdi Yufa0b6a02014-04-30 14:26:42 -0700274
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800275 openDB();
276
277 emit identityUpdated(QString(m_identity.toUri().c_str()));
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800278}
279
280void
281Controller::loadConf()
282{
283 namespace fs = boost::filesystem;
284
285 fs::path chronosDir = fs::path(getenv("HOME")) / ".chronos";
286 fs::create_directories (chronosDir);
287
288 std::ifstream is((chronosDir / "config").c_str ());
289 ChronoChat::Conf conf;
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700290 if (conf.ParseFromIstream(&is)) {
291 m_identity.clear();
292 m_identity.append(conf.identity());
293 if (conf.has_nick())
294 m_nick = conf.nick();
295 else
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800296 m_nick = m_identity.get(-1).toUri();
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700297 }
298 else {
299 m_identity.clear();
300 // TODO: change below to system default;
301 m_identity.append("chronochat-tmp-identity")
302 .append(getRandomString());
303
304 m_nick = m_identity.get(-1).toUri();
305 }
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800306}
307
Yingdi Yufa0b6a02014-04-30 14:26:42 -0700308void
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800309Controller::saveConf()
310{
311 namespace fs = boost::filesystem;
312
313 fs::path chronosDir = fs::path(getenv("HOME")) / ".chronos";
314 fs::create_directories (chronosDir);
315
316 std::ofstream os((chronosDir / "config").c_str ());
317 ChronoChat::Conf conf;
318 conf.set_identity(m_identity.toUri());
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700319 if (!m_nick.empty())
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800320 conf.set_nick(m_nick);
321 conf.SerializeToOstream(&os);
322
323 os.close();
324}
325
326void
327Controller::createActions()
328{
329 m_startChatroom = new QAction(tr("Start new chat"), this);
330 connect(m_startChatroom, SIGNAL(triggered()), this, SLOT(onStartChatAction()));
331
332 m_settingsAction = new QAction(tr("Settings"), this);
333 connect(m_settingsAction, SIGNAL(triggered()), this, SLOT(onSettingsAction()));
334
335 m_editProfileAction = new QAction(tr("Edit profile"), this);
336 connect(m_editProfileAction, SIGNAL(triggered()), this, SLOT(onProfileEditorAction()));
337
338 m_contactListAction = new QAction(tr("Contact List"), this);
339 connect(m_contactListAction, SIGNAL(triggered()), this, SLOT(onContactListAction()));
340
341 m_addContactAction = new QAction(tr("Add contact"), this);
342 connect(m_addContactAction, SIGNAL(triggered()), this, SLOT(onAddContactAction()));
343
Qiuhan Ding43c8e162015-02-02 15:16:48 -0800344 m_chatroomDiscoveryAction = new QAction(tr("Chatroom Discovery"), this);
345 connect(m_chatroomDiscoveryAction, SIGNAL(triggered()), this, SLOT(onChatroomDiscoveryAction()));
346
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800347 m_updateLocalPrefixAction = new QAction(tr("Update local prefix"), this);
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700348 connect(m_updateLocalPrefixAction, SIGNAL(triggered()),
349 &m_backend, SLOT(onUpdateLocalPrefixAction()));
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800350
351 m_minimizeAction = new QAction(tr("Mi&nimize"), this);
352 connect(m_minimizeAction, SIGNAL(triggered()), this, SLOT(onMinimizeAction()));
353
354 m_quitAction = new QAction(tr("Quit"), this);
355 connect(m_quitAction, SIGNAL(triggered()), this, SLOT(onQuitAction()));
Mengjin Yan391d7242014-08-28 20:51:55 -0700356
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800357}
358
359void
360Controller::createTrayIcon()
361{
362 createActions();
363
364 m_trayIconMenu = new QMenu(this);
365 m_trayIconMenu->addAction(m_startChatroom);
Qiuhan Ding43c8e162015-02-02 15:16:48 -0800366 m_trayIconMenu->addAction(m_chatroomDiscoveryAction);
Mengjin Yan391d7242014-08-28 20:51:55 -0700367
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800368 m_trayIconMenu->addSeparator();
369 m_trayIconMenu->addAction(m_settingsAction);
370 m_trayIconMenu->addAction(m_editProfileAction);
371 m_trayIconMenu->addSeparator();
372 m_trayIconMenu->addAction(m_contactListAction);
373 m_trayIconMenu->addAction(m_addContactAction);
374 m_trayIconMenu->addSeparator();
375 m_trayIconMenu->addAction(m_updateLocalPrefixAction);
376 m_trayIconMenu->addSeparator();
377 m_trayIconMenu->addAction(m_minimizeAction);
378 m_closeMenu = m_trayIconMenu->addMenu("Close chatroom");
379 m_closeMenu->setEnabled(false);
380 m_trayIconMenu->addSeparator();
381 m_trayIconMenu->addAction(m_quitAction);
382
383 m_trayIcon = new QSystemTrayIcon(this);
384 m_trayIcon->setContextMenu(m_trayIconMenu);
385
386 m_trayIcon->setIcon(QIcon(":/images/icon_small.png"));
387 m_trayIcon->setToolTip("ChronoChat System Tray Icon");
388 m_trayIcon->setVisible(true);
389}
390
391void
392Controller::updateMenu()
393{
394 QMenu* menu = new QMenu(this);
395 QMenu* closeMenu = 0;
Yingdi Yufa0b6a02014-04-30 14:26:42 -0700396
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800397 menu->addAction(m_startChatroom);
Qiuhan Ding43c8e162015-02-02 15:16:48 -0800398 menu->addAction(m_chatroomDiscoveryAction);
Mengjin Yan391d7242014-08-28 20:51:55 -0700399
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800400 menu->addSeparator();
401 menu->addAction(m_settingsAction);
402 menu->addAction(m_editProfileAction);
403 menu->addSeparator();
Yingdi Yu233a9722014-03-07 15:47:09 -0800404 menu->addAction(m_contactListAction);
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800405 menu->addAction(m_addContactAction);
406 menu->addSeparator();
407 {
408 ChatActionList::const_iterator it = m_chatActionList.begin();
409 ChatActionList::const_iterator end = m_chatActionList.end();
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700410 if (it != end) {
411 for (; it != end; it++)
412 menu->addAction(it->second);
413 menu->addSeparator();
414 }
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800415 }
416 menu->addAction(m_updateLocalPrefixAction);
417 menu->addSeparator();
418 menu->addAction(m_minimizeAction);
419 closeMenu = menu->addMenu("Close chatroom");
420 {
421 ChatActionList::const_iterator it = m_closeActionList.begin();
422 ChatActionList::const_iterator end = m_closeActionList.end();
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700423 if (it == end)
424 closeMenu->setEnabled(false);
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800425 else
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700426 for (; it != end; it++)
427 closeMenu->addAction(it->second);
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800428 }
429 menu->addSeparator();
430 menu->addAction(m_quitAction);
Yingdi Yufa0b6a02014-04-30 14:26:42 -0700431
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800432 m_trayIcon->setContextMenu(menu);
433 delete m_trayIconMenu;
434 m_trayIconMenu = menu;
435 m_closeMenu = closeMenu;
436}
437
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700438string
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800439Controller::getRandomString()
440{
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700441 uint32_t r = ndn::random::generateWord32();
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800442 std::stringstream ss;
443 {
444 using namespace CryptoPP;
445 StringSource(reinterpret_cast<uint8_t*>(&r), 4, true,
446 new HexEncoder(new FileSink(ss), false));
Yingdi Yufa0b6a02014-04-30 14:26:42 -0700447
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800448 }
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700449 // for (int i = 0; i < 8; i++)
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800450 // {
451 // uint32_t t = r & mask;
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700452 // if (t < 10)
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800453 // ss << static_cast<char>(t + 0x30);
454 // else
455 // ss << static_cast<char>(t + 0x57);
456 // r = r >> 4;
457 // }
458
459 return ss.str();
460}
461
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800462void
463Controller::addChatDialog(const QString& chatroomName, ChatDialog* chatDialog)
464{
465 m_chatDialogList[chatroomName.toStdString()] = chatDialog;
466 connect(chatDialog, SIGNAL(closeChatDialog(const QString&)),
467 this, SLOT(onRemoveChatDialog(const QString&)));
468 connect(chatDialog, SIGNAL(showChatMessage(const QString&, const QString&, const QString&)),
469 this, SLOT(onShowChatMessage(const QString&, const QString&, const QString&)));
Yingdi Yu233a9722014-03-07 15:47:09 -0800470 connect(chatDialog, SIGNAL(resetIcon()),
471 this, SLOT(onResetIcon()));
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700472 connect(&m_backend, SIGNAL(localPrefixUpdated(const QString&)),
Yingdi Yud45777b2014-10-16 23:54:11 -0700473 chatDialog->getBackend(), SLOT(updateRoutingPrefix(const QString&)));
Yingdi Yubaaaec02014-09-02 22:05:32 -0700474 connect(this, SIGNAL(localPrefixConfigured(const QString&)),
Yingdi Yud45777b2014-10-16 23:54:11 -0700475 chatDialog->getBackend(), SLOT(updateRoutingPrefix(const QString&)));
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800476
Qiuhan Ding43c8e162015-02-02 15:16:48 -0800477 // connect chat dialog with discovery backend
478 connect(chatDialog->getBackend(), SIGNAL(addInRoster(ndn::Name, ndn::Name::Component)),
479 m_chatroomDiscoveryBackend, SLOT(onAddInRoster(ndn::Name, ndn::Name::Component)));
480 connect(chatDialog->getBackend(), SIGNAL(eraseInRoster(ndn::Name, ndn::Name::Component)),
481 m_chatroomDiscoveryBackend, SLOT(onEraseInRoster(ndn::Name, ndn::Name::Component)));
482
483
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800484 QAction* chatAction = new QAction(chatroomName, this);
485 m_chatActionList[chatroomName.toStdString()] = chatAction;
Mengjin Yan391d7242014-08-28 20:51:55 -0700486 connect(chatAction, SIGNAL(triggered()),
Yingdi Yue8323b62014-09-02 17:24:15 -0700487 chatDialog, SLOT(onShow()));
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800488
489 QAction* closeAction = new QAction(chatroomName, this);
490 m_closeActionList[chatroomName.toStdString()] = closeAction;
Yingdi Yud45777b2014-10-16 23:54:11 -0700491 connect(closeAction, SIGNAL(triggered()),
492 chatDialog, SLOT(shutdown()));
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800493
494 updateMenu();
Qiuhan Ding43c8e162015-02-02 15:16:48 -0800495 emit newChatroomForDiscovery(Name::Component(chatroomName.toStdString()));
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800496}
497
Mengjin Yan391d7242014-08-28 20:51:55 -0700498void
499Controller::updateDiscoveryList(const ChatroomInfo& info, bool isAdd)
500{
501 emit discoverChatroomChanged(info, isAdd);
502}
503
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800504void
505Controller::onIdentityUpdated(const QString& identity)
506{
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700507 while (!m_chatDialogList.empty()) {
508 ChatDialogList::const_iterator it = m_chatDialogList.begin();
Yingdi Yu1fd4e4a2015-02-02 13:37:50 -0800509 it->second->shutdown();
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700510 }
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800511
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800512 emit closeDBModule();
Yingdi Yufa0b6a02014-04-30 14:26:42 -0700513
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700514 Name identityName(identity.toStdString());
515 m_identity = identityName;
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800516
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700517 QTimer::singleShot(500, this, SLOT(onIdentityUpdatedContinued()));
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800518}
519
520void
521Controller::onIdentityUpdatedContinued()
522{
523 QString connection = m_db.connectionName();
524 // _LOG_DEBUG("connection name: " << connection.toStdString());
525 QSqlDatabase::removeDatabase(connection);
526 m_db.close();
Yingdi Yufa0b6a02014-04-30 14:26:42 -0700527
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800528 openDB();
529
530 emit identityUpdated(QString(m_identity.toUri().c_str()));
531}
532
533void
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800534Controller::onNickUpdated(const QString& nick)
535{
536 m_nick = nick.toStdString();
537}
538
539void
540Controller::onLocalPrefixUpdated(const QString& localPrefix)
541{
Yingdi Yubaaaec02014-09-02 22:05:32 -0700542 QString privateLocalPrefix("/private/local");
543
Yingdi Yubaaaec02014-09-02 22:05:32 -0700544 if (privateLocalPrefix != localPrefix)
545 m_localPrefixDetected = true;
546 else
547 m_localPrefixDetected = false;
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700548
549 m_localPrefix = Name(localPrefix.toStdString());
Yingdi Yubaaaec02014-09-02 22:05:32 -0700550}
551
552void
553Controller::onLocalPrefixConfigured(const QString& prefix)
554{
555 if (!m_localPrefixDetected) {
556 m_localPrefix = Name(prefix.toStdString());
557 emit localPrefixConfigured(prefix);
558 }
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800559}
560
561void
562Controller::onStartChatAction()
563{
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700564 string chatroom = "chatroom-" + getRandomString();
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800565
566 m_startChatDialog->setChatroom(chatroom);
567 m_startChatDialog->show();
568 m_startChatDialog->raise();
569}
570
571void
572Controller::onSettingsAction()
573{
574 m_settingDialog->setNick(QString(m_nick.c_str()));
575 m_settingDialog->show();
576 m_settingDialog->raise();
577}
578
579void
580Controller::onProfileEditorAction()
581{
582 m_profileEditor->show();
583 m_profileEditor->raise();
584}
585
586void
587Controller::onAddContactAction()
588{
589 emit refreshBrowseContact();
590 m_browseContactDialog->show();
591 m_browseContactDialog->raise();
592}
593
594void
595Controller::onContactListAction()
596{
597 m_contactPanel->show();
598 m_contactPanel->raise();
599}
600
601void
Qiuhan Ding43c8e162015-02-02 15:16:48 -0800602Controller::onChatroomDiscoveryAction()
603{
604 m_discoveryPanel->show();
605 m_discoveryPanel->raise();
606}
607
608void
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800609Controller::onDirectAdd()
610{
611 m_addContactPanel->show();
612 m_addContactPanel->raise();
613}
614
615void
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800616Controller::onMinimizeAction()
617{
618 m_settingDialog->hide();
619 m_startChatDialog->hide();
620 m_profileEditor->hide();
621 m_invitationDialog->hide();
622 m_addContactPanel->hide();
Qiuhan Ding43c8e162015-02-02 15:16:48 -0800623 m_discoveryPanel->hide();
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800624
625 ChatDialogList::iterator it = m_chatDialogList.begin();
626 ChatDialogList::iterator end = m_chatDialogList.end();
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700627 for (; it != end; it++)
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800628 it->second->hide();
629}
630
631void
632Controller::onQuitAction()
633{
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700634 while (!m_chatDialogList.empty()) {
635 ChatDialogList::const_iterator it = m_chatDialogList.begin();
Yingdi Yud45777b2014-10-16 23:54:11 -0700636 it->second->shutdown();
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700637 }
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800638
639 delete m_settingDialog;
640 delete m_startChatDialog;
641 delete m_profileEditor;
642 delete m_invitationDialog;
Yingdi Yuf4aaa8b2014-03-10 11:24:31 -0700643 delete m_browseContactDialog;
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800644 delete m_addContactPanel;
Qiuhan Ding43c8e162015-02-02 15:16:48 -0800645 delete m_discoveryPanel;
646 if (m_chatroomDiscoveryBackend->isRunning()) {
647 emit shutdownDiscoveryBackend();
648 m_chatroomDiscoveryBackend->wait();
649 }
650 delete m_chatroomDiscoveryBackend;
Yingdi Yuf4aaa8b2014-03-10 11:24:31 -0700651
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700652 if (m_backend.isRunning()) {
653 emit shutdownBackend();
654 m_backend.wait();
655 }
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800656
657 QApplication::quit();
658}
659
660void
661Controller::onStartChatroom(const QString& chatroomName, bool secured)
662{
663 Name chatroomPrefix;
664 chatroomPrefix.append("ndn")
665 .append("broadcast")
666 .append("ChronoChat")
Qiuhan Ding43c8e162015-02-02 15:16:48 -0800667 .append("Chatroom")
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800668 .append(chatroomName.toStdString());
669
670 // check if the chatroom exists
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700671 if (m_chatDialogList.find(chatroomName.toStdString()) != m_chatDialogList.end()) {
672 QMessageBox::information(this, tr("ChronoChat"),
673 tr("You are creating an existing chatroom."
674 "You can check it in the context memu."));
675 return;
676 }
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800677
Mengjin Yan391d7242014-08-28 20:51:55 -0700678 // TODO: We should create a chatroom specific key/cert
679 //(which should be created in the first half of this method
680 //, but let's use the default one for now.
Yingdi Yud45777b2014-10-16 23:54:11 -0700681 Name chatPrefix;
Qiuhan Ding43c8e162015-02-02 15:16:48 -0800682 chatPrefix.append(m_identity).append("CHRONOCHAT-CHATDATA").append(chatroomName.toStdString());
Yingdi Yud45777b2014-10-16 23:54:11 -0700683
Mengjin Yan391d7242014-08-28 20:51:55 -0700684 ChatDialog* chatDialog
Yingdi Yud45777b2014-10-16 23:54:11 -0700685 = new ChatDialog(chatroomPrefix,
686 chatPrefix,
687 m_localPrefix,
688 chatroomName.toStdString(),
Yingdi Yu45da92a2015-02-02 13:17:03 -0800689 m_nick,
690 true,
Qiuhan Ding43c8e162015-02-02 15:16:48 -0800691 m_identity,
692 this);
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800693
Yingdi Yufa0b6a02014-04-30 14:26:42 -0700694 addChatDialog(chatroomName, chatDialog);
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800695 chatDialog->show();
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700696
697 emit addChatroom(chatroomName);
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800698}
699
700void
Yingdi Yueb692ac2015-02-10 18:46:18 -0800701Controller::onStartChatroom2(chronochat::Invitation invitation, bool secured)
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800702{
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700703 QString chatroomName = QString::fromStdString(invitation.getChatroom());
704 onStartChatroom(chatroomName, secured);
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800705
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700706 ChatDialogList::iterator it = m_chatDialogList.find(chatroomName.toStdString());
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800707
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700708 BOOST_ASSERT(it != m_chatDialogList.end());
709 it->second->addSyncAnchor(invitation);
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800710}
711
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700712
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800713void
714Controller::onShowChatMessage(const QString& chatroomName, const QString& from, const QString& data)
715{
Yingdi Yufa0b6a02014-04-30 14:26:42 -0700716 m_trayIcon->showMessage(QString("Chatroom %1 has a new message").arg(chatroomName),
717 QString("<%1>: %2").arg(from).arg(data),
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800718 QSystemTrayIcon::Information, 20000);
719 m_trayIcon->setIcon(QIcon(":/images/note.png"));
720}
721
722void
Yingdi Yu233a9722014-03-07 15:47:09 -0800723Controller::onResetIcon()
724{
725 m_trayIcon->setIcon(QIcon(":/images/icon_small.png"));
726}
727
728void
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800729Controller::onRemoveChatDialog(const QString& chatroomName)
730{
731 ChatDialogList::iterator it = m_chatDialogList.find(chatroomName.toStdString());
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700732 if (it != m_chatDialogList.end()) {
733 ChatDialog* deletedChat = it->second;
734 if (deletedChat)
735 delete deletedChat;
Qiuhan Ding43c8e162015-02-02 15:16:48 -0800736
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700737 m_chatDialogList.erase(it);
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800738
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700739 QAction* chatAction = m_chatActionList[chatroomName.toStdString()];
740 QAction* closeAction = m_closeActionList[chatroomName.toStdString()];
741 if (chatAction)
742 delete chatAction;
743 if (closeAction)
744 delete closeAction;
Yingdi Yufa0b6a02014-04-30 14:26:42 -0700745
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700746 m_chatActionList.erase(chatroomName.toStdString());
747 m_closeActionList.erase(chatroomName.toStdString());
Yingdi Yufa0b6a02014-04-30 14:26:42 -0700748
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700749 updateMenu();
750 }
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800751}
752
753void
754Controller::onWarning(const QString& msg)
755{
756 QMessageBox::information(this, tr("ChronoChat"), msg);
757}
758
759void
Yingdi Yufa0b6a02014-04-30 14:26:42 -0700760Controller::onError(const QString& msg)
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800761{
762 QMessageBox::critical(this, tr("ChronoChat"), msg, QMessageBox::Ok);
763 exit(1);
764}
765
Yingdi Yu233a9722014-03-07 15:47:09 -0800766void
Qiuhan Ding43c8e162015-02-02 15:16:48 -0800767Controller::onChatroomInfoRequest(std::string chatroomName, bool isManager)
Mengjin Yan391d7242014-08-28 20:51:55 -0700768{
Qiuhan Ding43c8e162015-02-02 15:16:48 -0800769 auto it = m_chatDialogList.find(chatroomName);
770 if (it != m_chatDialogList.end())
771 emit respondChatroomInfoRequest(it->second->getChatroomInfo(), isManager);
Mengjin Yan391d7242014-08-28 20:51:55 -0700772}
773
Yingdi Yueb692ac2015-02-10 18:46:18 -0800774} // namespace chronochat
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800775
776#if WAF
777#include "controller.moc"
Yingdi Yu42125862014-08-07 17:04:28 -0700778// #include "controller.cpp.moc"
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800779#endif