blob: 1b585c135428f0827104ccace9b8998a11632ed4 [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"
Mengjin Yan391d7242014-08-28 20:51:55 -070016//#include "chatroom-discovery.h"
Yingdi Yu348f5ea2014-03-01 14:47:25 -080017
18#ifndef Q_MOC_RUN
19#include <boost/filesystem.hpp>
20#include <boost/lexical_cast.hpp>
Yingdi Yufa0b6a02014-04-30 14:26:42 -070021#include <ndn-cxx/util/random.hpp>
Yingdi Yu0b0a7362014-08-05 16:31:30 -070022#include "cryptopp.hpp"
Yingdi Yu348f5ea2014-03-01 14:47:25 -080023#include "config.pb.h"
24#include "endorse-info.pb.h"
25#include "logging.h"
26#endif
27
Yingdi Yueb692ac2015-02-10 18:46:18 -080028INIT_LOGGER("chronochat.Controller");
Yingdi Yu348f5ea2014-03-01 14:47:25 -080029
30Q_DECLARE_METATYPE(ndn::Name)
31Q_DECLARE_METATYPE(ndn::IdentityCertificate)
Yingdi Yueb692ac2015-02-10 18:46:18 -080032Q_DECLARE_METATYPE(chronochat::EndorseInfo)
Yingdi Yu233a9722014-03-07 15:47:09 -080033Q_DECLARE_METATYPE(ndn::Interest)
34Q_DECLARE_METATYPE(size_t)
Yingdi Yueb692ac2015-02-10 18:46:18 -080035Q_DECLARE_METATYPE(chronochat::ChatroomInfo)
36Q_DECLARE_METATYPE(chronochat::Invitation)
Yingdi Yu348f5ea2014-03-01 14:47:25 -080037
Yingdi Yueb692ac2015-02-10 18:46:18 -080038namespace chronochat {
Yingdi Yu348f5ea2014-03-01 14:47:25 -080039
Yingdi Yu0b0a7362014-08-05 16:31:30 -070040using std::string;
41
Yingdi Yu348f5ea2014-03-01 14:47:25 -080042// constructor & destructor
Yingdi Yu2c9e7712014-10-20 11:55:05 -070043Controller::Controller(QWidget* parent)
Yingdi Yu348f5ea2014-03-01 14:47:25 -080044 : QDialog(parent)
Yingdi Yubaaaec02014-09-02 22:05:32 -070045 , m_localPrefixDetected(false)
Yingdi Yu348f5ea2014-03-01 14:47:25 -080046 , m_settingDialog(new SettingDialog)
47 , m_startChatDialog(new StartChatDialog)
48 , m_profileEditor(new ProfileEditor)
49 , m_invitationDialog(new InvitationDialog)
50 , m_contactPanel(new ContactPanel)
51 , m_browseContactDialog(new BrowseContactDialog)
52 , m_addContactPanel(new AddContactPanel)
53{
54 qRegisterMetaType<ndn::Name>("ndn.Name");
55 qRegisterMetaType<ndn::IdentityCertificate>("ndn.IdentityCertificate");
Yingdi Yueb692ac2015-02-10 18:46:18 -080056 qRegisterMetaType<chronochat::EndorseInfo>("chronochat.EndorseInfo");
Yingdi Yu233a9722014-03-07 15:47:09 -080057 qRegisterMetaType<ndn::Interest>("ndn.Interest");
58 qRegisterMetaType<size_t>("size_t");
Yingdi Yueb692ac2015-02-10 18:46:18 -080059 qRegisterMetaType<chronochat::ChatroomInfo>("chronos.Chatroom");
60 qRegisterMetaType<chronochat::Invitation>("chronos.Invitation");
Yingdi Yu348f5ea2014-03-01 14:47:25 -080061
62 // Connection to ContactManager
Yingdi Yu2c9e7712014-10-20 11:55:05 -070063 connect(m_backend.getContactManager(), SIGNAL(warning(const QString&)),
Yingdi Yu348f5ea2014-03-01 14:47:25 -080064 this, SLOT(onWarning(const QString&)));
65 connect(this, SIGNAL(refreshBrowseContact()),
Yingdi Yu2c9e7712014-10-20 11:55:05 -070066 m_backend.getContactManager(), SLOT(onRefreshBrowseContact()));
67 connect(m_backend.getContactManager(), SIGNAL(contactInfoFetchFailed(const QString&)),
Yingdi Yu348f5ea2014-03-01 14:47:25 -080068 this, SLOT(onWarning(const QString&)));
Yingdi Yu348f5ea2014-03-01 14:47:25 -080069
70 // Connection to SettingDialog
71 connect(this, SIGNAL(identityUpdated(const QString&)),
72 m_settingDialog, SLOT(onIdentityUpdated(const QString&)));
73 connect(m_settingDialog, SIGNAL(identityUpdated(const QString&)),
74 this, SLOT(onIdentityUpdated(const QString&)));
75 connect(m_settingDialog, SIGNAL(nickUpdated(const QString&)),
76 this, SLOT(onNickUpdated(const QString&)));
Yingdi Yubaaaec02014-09-02 22:05:32 -070077 connect(m_settingDialog, SIGNAL(prefixUpdated(const QString&)),
78 this, SLOT(onLocalPrefixConfigured(const QString&)));
Yingdi Yu348f5ea2014-03-01 14:47:25 -080079
80 // Connection to ProfileEditor
81 connect(this, SIGNAL(closeDBModule()),
82 m_profileEditor, SLOT(onCloseDBModule()));
83 connect(this, SIGNAL(identityUpdated(const QString&)),
84 m_profileEditor, SLOT(onIdentityUpdated(const QString&)));
85 connect(m_profileEditor, SIGNAL(updateProfile()),
Yingdi Yu2c9e7712014-10-20 11:55:05 -070086 m_backend.getContactManager(), SLOT(onUpdateProfile()));
Yingdi Yu348f5ea2014-03-01 14:47:25 -080087
88 // Connection to StartChatDialog
89 connect(m_startChatDialog, SIGNAL(startChatroom(const QString&, bool)),
90 this, SLOT(onStartChatroom(const QString&, bool)));
91
92 // Connection to InvitationDialog
93 connect(m_invitationDialog, SIGNAL(invitationResponded(const ndn::Name&, bool)),
Yingdi Yu2c9e7712014-10-20 11:55:05 -070094 &m_backend, SLOT(onInvitationResponded(const ndn::Name&, bool)));
Yingdi Yu348f5ea2014-03-01 14:47:25 -080095
96 // Connection to AddContactPanel
97 connect(m_addContactPanel, SIGNAL(fetchInfo(const QString&)),
Yingdi Yu2c9e7712014-10-20 11:55:05 -070098 m_backend.getContactManager(), SLOT(onFetchContactInfo(const QString&)));
Yingdi Yu348f5ea2014-03-01 14:47:25 -080099 connect(m_addContactPanel, SIGNAL(addContact(const QString&)),
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700100 m_backend.getContactManager(), SLOT(onAddFetchedContact(const QString&)));
101 connect(m_backend.getContactManager(),
Yingdi Yueb692ac2015-02-10 18:46:18 -0800102 SIGNAL(contactEndorseInfoReady(const chronochat::EndorseInfo&)),
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700103 m_addContactPanel,
Yingdi Yueb692ac2015-02-10 18:46:18 -0800104 SLOT(onContactEndorseInfoReady(const chronochat::EndorseInfo&)));
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800105
106
107 // Connection to BrowseContactDialog
108 connect(m_browseContactDialog, SIGNAL(directAddClicked()),
109 this, SLOT(onDirectAdd()));
110 connect(m_browseContactDialog, SIGNAL(fetchIdCert(const QString&)),
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700111 m_backend.getContactManager(), SLOT(onFetchIdCert(const QString&)));
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800112 connect(m_browseContactDialog, SIGNAL(addContact(const QString&)),
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700113 m_backend.getContactManager(), SLOT(onAddFetchedContactIdCert(const QString&)));
114 connect(m_backend.getContactManager(), SIGNAL(idCertNameListReady(const QStringList&)),
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800115 m_browseContactDialog, SLOT(onIdCertNameListReady(const QStringList&)));
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700116 connect(m_backend.getContactManager(), SIGNAL(nameListReady(const QStringList&)),
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800117 m_browseContactDialog, SLOT(onNameListReady(const QStringList&)));
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700118 connect(m_backend.getContactManager(), SIGNAL(idCertReady(const ndn::IdentityCertificate&)),
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800119 m_browseContactDialog, SLOT(onIdCertReady(const ndn::IdentityCertificate&)));
120
121 // Connection to ContactPanel
122 connect(m_contactPanel, SIGNAL(waitForContactList()),
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700123 m_backend.getContactManager(), SLOT(onWaitForContactList()));
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800124 connect(m_contactPanel, SIGNAL(waitForContactInfo(const QString&)),
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700125 m_backend.getContactManager(), SLOT(onWaitForContactInfo(const QString&)));
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800126 connect(m_contactPanel, SIGNAL(removeContact(const QString&)),
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700127 m_backend.getContactManager(), SLOT(onRemoveContact(const QString&)));
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800128 connect(m_contactPanel, SIGNAL(updateAlias(const QString&, const QString&)),
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700129 m_backend.getContactManager(), SLOT(onUpdateAlias(const QString&, const QString&)));
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800130 connect(m_contactPanel, SIGNAL(updateIsIntroducer(const QString&, bool)),
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700131 m_backend.getContactManager(), SLOT(onUpdateIsIntroducer(const QString&, bool)));
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800132 connect(m_contactPanel, SIGNAL(updateEndorseCertificate(const QString&)),
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700133 m_backend.getContactManager(), SLOT(onUpdateEndorseCertificate(const QString&)));
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800134 connect(m_contactPanel, SIGNAL(warning(const QString&)),
135 this, SLOT(onWarning(const QString&)));
136 connect(this, SIGNAL(closeDBModule()),
137 m_contactPanel, SLOT(onCloseDBModule()));
138 connect(this, SIGNAL(identityUpdated(const QString&)),
139 m_contactPanel, SLOT(onIdentityUpdated(const QString&)));
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700140 connect(m_backend.getContactManager(), SIGNAL(contactAliasListReady(const QStringList&)),
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800141 m_contactPanel, SLOT(onContactAliasListReady(const QStringList&)));
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700142 connect(m_backend.getContactManager(), SIGNAL(contactIdListReady(const QStringList&)),
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800143 m_contactPanel, SLOT(onContactIdListReady(const QStringList&)));
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700144 connect(m_backend.getContactManager(), SIGNAL(contactInfoReady(const QString&, const QString&,
145 const QString&, bool)),
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700146 m_contactPanel, SLOT(onContactInfoReady(const QString&, const QString&,
147 const QString&, bool)));
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800148
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700149 // Connection to backend thread
150 connect(this, SIGNAL(shutdownBackend()),
151 &m_backend, SLOT(shutdown()));
152 connect(this, SIGNAL(updateLocalPrefix()),
153 &m_backend, SLOT(onUpdateLocalPrefixAction()));
154 connect(this, SIGNAL(identityUpdated(const QString&)),
155 &m_backend, SLOT(onIdentityChanged(const QString&)));
156 connect(this, SIGNAL(addChatroom(QString)),
157 &m_backend, SLOT(addChatroom(QString)));
158 connect(this, SIGNAL(removeChatroom(QString)),
159 &m_backend, SLOT(removeChatroom(QString)));
160
161 // Thread notifications:
162 // on local prefix udpated:
163 connect(&m_backend, SIGNAL(localPrefixUpdated(const QString&)),
164 this, SLOT(onLocalPrefixUpdated(const QString&)));
165 connect(&m_backend, SIGNAL(localPrefixUpdated(const QString&)),
166 m_settingDialog, SLOT(onLocalPrefixUpdated(const QString&)));
167
168 // on invitation validated:
169 connect(&m_backend, SIGNAL(invitaionValidated(QString, QString, ndn::Name)),
170 m_invitationDialog, SLOT(onInvitationReceived(QString, QString, ndn::Name)));
171
172 // on invitation accepted:
Yingdi Yueb692ac2015-02-10 18:46:18 -0800173 connect(&m_backend, SIGNAL(startChatroomOnInvitation(chronochat::Invitation, bool)),
174 this, SLOT(onStartChatroom2(chronochat::Invitation, bool)));
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700175
176 m_backend.start();
Mengjin Yan391d7242014-08-28 20:51:55 -0700177
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800178 initialize();
179
Yingdi Yu233a9722014-03-07 15:47:09 -0800180 createTrayIcon();
181
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700182 emit updateLocalPrefix();
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800183}
Yingdi Yufa0b6a02014-04-30 14:26:42 -0700184
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800185Controller::~Controller()
186{
187 saveConf();
188}
189
190// public methods
191
192
193// private methods
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700194string
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800195Controller::getDBName()
196{
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700197 string dbName("chronos-");
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800198
199 std::stringstream ss;
200 {
201 using namespace CryptoPP;
202
203 SHA256 hash;
204 StringSource(m_identity.wireEncode().wire(), m_identity.wireEncode().size(), true,
205 new HashFilter(hash, new HexEncoder(new FileSink(ss), false)));
206 }
207 dbName.append(ss.str()).append(".db");
208
209 return dbName;
210}
211
212void
213Controller::openDB()
214{
215 m_db = QSqlDatabase::addDatabase("QSQLITE");
216 QString path = (QDir::home().path());
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700217 path.append(QDir::separator())
218 .append(".chronos")
219 .append(QDir::separator())
220 .append(getDBName().c_str());
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800221 m_db.setDatabaseName(path);
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800222
Yingdi Yu42125862014-08-07 17:04:28 -0700223 m_db.open();
224
225 // bool ok = m_db.open();
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700226 // _LOG_DEBUG("DB opened: " << std::boolalpha << ok );
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800227}
228
229void
230Controller::initialize()
231{
232 loadConf();
Yingdi Yufa0b6a02014-04-30 14:26:42 -0700233
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800234 openDB();
235
236 emit identityUpdated(QString(m_identity.toUri().c_str()));
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800237}
238
239void
240Controller::loadConf()
241{
242 namespace fs = boost::filesystem;
243
244 fs::path chronosDir = fs::path(getenv("HOME")) / ".chronos";
245 fs::create_directories (chronosDir);
246
247 std::ifstream is((chronosDir / "config").c_str ());
248 ChronoChat::Conf conf;
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700249 if (conf.ParseFromIstream(&is)) {
250 m_identity.clear();
251 m_identity.append(conf.identity());
252 if (conf.has_nick())
253 m_nick = conf.nick();
254 else
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800255 m_nick = m_identity.get(-1).toUri();
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700256 }
257 else {
258 m_identity.clear();
259 // TODO: change below to system default;
260 m_identity.append("chronochat-tmp-identity")
261 .append(getRandomString());
262
263 m_nick = m_identity.get(-1).toUri();
264 }
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800265}
266
Yingdi Yufa0b6a02014-04-30 14:26:42 -0700267void
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800268Controller::saveConf()
269{
270 namespace fs = boost::filesystem;
271
272 fs::path chronosDir = fs::path(getenv("HOME")) / ".chronos";
273 fs::create_directories (chronosDir);
274
275 std::ofstream os((chronosDir / "config").c_str ());
276 ChronoChat::Conf conf;
277 conf.set_identity(m_identity.toUri());
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700278 if (!m_nick.empty())
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800279 conf.set_nick(m_nick);
280 conf.SerializeToOstream(&os);
281
282 os.close();
283}
284
285void
286Controller::createActions()
287{
288 m_startChatroom = new QAction(tr("Start new chat"), this);
289 connect(m_startChatroom, SIGNAL(triggered()), this, SLOT(onStartChatAction()));
290
Mengjin Yan391d7242014-08-28 20:51:55 -0700291 m_discoveryAction = new QAction(tr("Ongoing Chatrooms"), this);
292 connect(m_discoveryAction, SIGNAL(triggered()), this, SLOT(onDiscoveryAction()));
293
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800294 m_settingsAction = new QAction(tr("Settings"), this);
295 connect(m_settingsAction, SIGNAL(triggered()), this, SLOT(onSettingsAction()));
296
297 m_editProfileAction = new QAction(tr("Edit profile"), this);
298 connect(m_editProfileAction, SIGNAL(triggered()), this, SLOT(onProfileEditorAction()));
299
300 m_contactListAction = new QAction(tr("Contact List"), this);
301 connect(m_contactListAction, SIGNAL(triggered()), this, SLOT(onContactListAction()));
302
303 m_addContactAction = new QAction(tr("Add contact"), this);
304 connect(m_addContactAction, SIGNAL(triggered()), this, SLOT(onAddContactAction()));
305
306 m_updateLocalPrefixAction = new QAction(tr("Update local prefix"), this);
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700307 connect(m_updateLocalPrefixAction, SIGNAL(triggered()),
308 &m_backend, SLOT(onUpdateLocalPrefixAction()));
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800309
310 m_minimizeAction = new QAction(tr("Mi&nimize"), this);
311 connect(m_minimizeAction, SIGNAL(triggered()), this, SLOT(onMinimizeAction()));
312
313 m_quitAction = new QAction(tr("Quit"), this);
314 connect(m_quitAction, SIGNAL(triggered()), this, SLOT(onQuitAction()));
Mengjin Yan391d7242014-08-28 20:51:55 -0700315
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800316}
317
318void
319Controller::createTrayIcon()
320{
321 createActions();
322
323 m_trayIconMenu = new QMenu(this);
324 m_trayIconMenu->addAction(m_startChatroom);
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700325 // m_trayIconMenu->addAction(m_discoveryAction); // disable discovery temporarily
Mengjin Yan391d7242014-08-28 20:51:55 -0700326
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800327 m_trayIconMenu->addSeparator();
328 m_trayIconMenu->addAction(m_settingsAction);
329 m_trayIconMenu->addAction(m_editProfileAction);
330 m_trayIconMenu->addSeparator();
331 m_trayIconMenu->addAction(m_contactListAction);
332 m_trayIconMenu->addAction(m_addContactAction);
333 m_trayIconMenu->addSeparator();
334 m_trayIconMenu->addAction(m_updateLocalPrefixAction);
335 m_trayIconMenu->addSeparator();
336 m_trayIconMenu->addAction(m_minimizeAction);
337 m_closeMenu = m_trayIconMenu->addMenu("Close chatroom");
338 m_closeMenu->setEnabled(false);
339 m_trayIconMenu->addSeparator();
340 m_trayIconMenu->addAction(m_quitAction);
341
342 m_trayIcon = new QSystemTrayIcon(this);
343 m_trayIcon->setContextMenu(m_trayIconMenu);
344
345 m_trayIcon->setIcon(QIcon(":/images/icon_small.png"));
346 m_trayIcon->setToolTip("ChronoChat System Tray Icon");
347 m_trayIcon->setVisible(true);
348}
349
350void
351Controller::updateMenu()
352{
353 QMenu* menu = new QMenu(this);
354 QMenu* closeMenu = 0;
Yingdi Yufa0b6a02014-04-30 14:26:42 -0700355
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800356 menu->addAction(m_startChatroom);
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700357 // menu->addAction(m_discoveryAction);
Mengjin Yan391d7242014-08-28 20:51:55 -0700358
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800359 menu->addSeparator();
360 menu->addAction(m_settingsAction);
361 menu->addAction(m_editProfileAction);
362 menu->addSeparator();
Yingdi Yu233a9722014-03-07 15:47:09 -0800363 menu->addAction(m_contactListAction);
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800364 menu->addAction(m_addContactAction);
365 menu->addSeparator();
366 {
367 ChatActionList::const_iterator it = m_chatActionList.begin();
368 ChatActionList::const_iterator end = m_chatActionList.end();
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700369 if (it != end) {
370 for (; it != end; it++)
371 menu->addAction(it->second);
372 menu->addSeparator();
373 }
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800374 }
375 menu->addAction(m_updateLocalPrefixAction);
376 menu->addSeparator();
377 menu->addAction(m_minimizeAction);
378 closeMenu = menu->addMenu("Close chatroom");
379 {
380 ChatActionList::const_iterator it = m_closeActionList.begin();
381 ChatActionList::const_iterator end = m_closeActionList.end();
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700382 if (it == end)
383 closeMenu->setEnabled(false);
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800384 else
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700385 for (; it != end; it++)
386 closeMenu->addAction(it->second);
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800387 }
388 menu->addSeparator();
389 menu->addAction(m_quitAction);
Yingdi Yufa0b6a02014-04-30 14:26:42 -0700390
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800391 m_trayIcon->setContextMenu(menu);
392 delete m_trayIconMenu;
393 m_trayIconMenu = menu;
394 m_closeMenu = closeMenu;
395}
396
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700397string
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800398Controller::getRandomString()
399{
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700400 uint32_t r = ndn::random::generateWord32();
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800401 std::stringstream ss;
402 {
403 using namespace CryptoPP;
404 StringSource(reinterpret_cast<uint8_t*>(&r), 4, true,
405 new HexEncoder(new FileSink(ss), false));
Yingdi Yufa0b6a02014-04-30 14:26:42 -0700406
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800407 }
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700408 // for (int i = 0; i < 8; i++)
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800409 // {
410 // uint32_t t = r & mask;
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700411 // if (t < 10)
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800412 // ss << static_cast<char>(t + 0x30);
413 // else
414 // ss << static_cast<char>(t + 0x57);
415 // r = r >> 4;
416 // }
417
418 return ss.str();
419}
420
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800421void
422Controller::addChatDialog(const QString& chatroomName, ChatDialog* chatDialog)
423{
424 m_chatDialogList[chatroomName.toStdString()] = chatDialog;
425 connect(chatDialog, SIGNAL(closeChatDialog(const QString&)),
426 this, SLOT(onRemoveChatDialog(const QString&)));
427 connect(chatDialog, SIGNAL(showChatMessage(const QString&, const QString&, const QString&)),
428 this, SLOT(onShowChatMessage(const QString&, const QString&, const QString&)));
Yingdi Yu233a9722014-03-07 15:47:09 -0800429 connect(chatDialog, SIGNAL(resetIcon()),
430 this, SLOT(onResetIcon()));
Yingdi Yueb692ac2015-02-10 18:46:18 -0800431 connect(chatDialog, SIGNAL(rosterChanged(const chronochat::ChatroomInfo&)),
432 this, SLOT(onRosterChanged(const chronochat::ChatroomInfo&)));
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700433 connect(&m_backend, SIGNAL(localPrefixUpdated(const QString&)),
Yingdi Yud45777b2014-10-16 23:54:11 -0700434 chatDialog->getBackend(), SLOT(updateRoutingPrefix(const QString&)));
Yingdi Yubaaaec02014-09-02 22:05:32 -0700435 connect(this, SIGNAL(localPrefixConfigured(const QString&)),
Yingdi Yud45777b2014-10-16 23:54:11 -0700436 chatDialog->getBackend(), SLOT(updateRoutingPrefix(const QString&)));
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800437
438 QAction* chatAction = new QAction(chatroomName, this);
439 m_chatActionList[chatroomName.toStdString()] = chatAction;
Mengjin Yan391d7242014-08-28 20:51:55 -0700440 connect(chatAction, SIGNAL(triggered()),
Yingdi Yue8323b62014-09-02 17:24:15 -0700441 chatDialog, SLOT(onShow()));
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800442
443 QAction* closeAction = new QAction(chatroomName, this);
444 m_closeActionList[chatroomName.toStdString()] = closeAction;
Yingdi Yud45777b2014-10-16 23:54:11 -0700445 connect(closeAction, SIGNAL(triggered()),
446 chatDialog, SLOT(shutdown()));
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800447
448 updateMenu();
449}
450
Mengjin Yan391d7242014-08-28 20:51:55 -0700451void
452Controller::updateDiscoveryList(const ChatroomInfo& info, bool isAdd)
453{
454 emit discoverChatroomChanged(info, isAdd);
455}
456
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800457void
458Controller::onIdentityUpdated(const QString& identity)
459{
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700460 while (!m_chatDialogList.empty()) {
461 ChatDialogList::const_iterator it = m_chatDialogList.begin();
462 onRemoveChatDialog(QString::fromStdString(it->first));
463 }
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800464
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800465 emit closeDBModule();
Yingdi Yufa0b6a02014-04-30 14:26:42 -0700466
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700467 Name identityName(identity.toStdString());
468 m_identity = identityName;
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800469
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700470 QTimer::singleShot(500, this, SLOT(onIdentityUpdatedContinued()));
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800471}
472
473void
474Controller::onIdentityUpdatedContinued()
475{
476 QString connection = m_db.connectionName();
477 // _LOG_DEBUG("connection name: " << connection.toStdString());
478 QSqlDatabase::removeDatabase(connection);
479 m_db.close();
Yingdi Yufa0b6a02014-04-30 14:26:42 -0700480
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800481 openDB();
482
483 emit identityUpdated(QString(m_identity.toUri().c_str()));
484}
485
486void
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800487Controller::onNickUpdated(const QString& nick)
488{
489 m_nick = nick.toStdString();
490}
491
492void
493Controller::onLocalPrefixUpdated(const QString& localPrefix)
494{
Yingdi Yubaaaec02014-09-02 22:05:32 -0700495 QString privateLocalPrefix("/private/local");
496
Yingdi Yubaaaec02014-09-02 22:05:32 -0700497 if (privateLocalPrefix != localPrefix)
498 m_localPrefixDetected = true;
499 else
500 m_localPrefixDetected = false;
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700501
502 m_localPrefix = Name(localPrefix.toStdString());
Yingdi Yubaaaec02014-09-02 22:05:32 -0700503}
504
505void
506Controller::onLocalPrefixConfigured(const QString& prefix)
507{
508 if (!m_localPrefixDetected) {
509 m_localPrefix = Name(prefix.toStdString());
510 emit localPrefixConfigured(prefix);
511 }
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800512}
513
514void
515Controller::onStartChatAction()
516{
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700517 string chatroom = "chatroom-" + getRandomString();
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800518
519 m_startChatDialog->setChatroom(chatroom);
520 m_startChatDialog->show();
521 m_startChatDialog->raise();
522}
523
524void
Mengjin Yan391d7242014-08-28 20:51:55 -0700525Controller::onDiscoveryAction()
526{
Mengjin Yan391d7242014-08-28 20:51:55 -0700527}
528
529
530void
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800531Controller::onSettingsAction()
532{
533 m_settingDialog->setNick(QString(m_nick.c_str()));
534 m_settingDialog->show();
535 m_settingDialog->raise();
536}
537
538void
539Controller::onProfileEditorAction()
540{
541 m_profileEditor->show();
542 m_profileEditor->raise();
543}
544
545void
546Controller::onAddContactAction()
547{
548 emit refreshBrowseContact();
549 m_browseContactDialog->show();
550 m_browseContactDialog->raise();
551}
552
553void
554Controller::onContactListAction()
555{
556 m_contactPanel->show();
557 m_contactPanel->raise();
558}
559
560void
561Controller::onDirectAdd()
562{
563 m_addContactPanel->show();
564 m_addContactPanel->raise();
565}
566
567void
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800568Controller::onMinimizeAction()
569{
570 m_settingDialog->hide();
571 m_startChatDialog->hide();
572 m_profileEditor->hide();
573 m_invitationDialog->hide();
574 m_addContactPanel->hide();
575
576 ChatDialogList::iterator it = m_chatDialogList.begin();
577 ChatDialogList::iterator end = m_chatDialogList.end();
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700578 for (; it != end; it++)
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800579 it->second->hide();
580}
581
582void
583Controller::onQuitAction()
584{
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700585 while (!m_chatDialogList.empty()) {
586 ChatDialogList::const_iterator it = m_chatDialogList.begin();
Yingdi Yud45777b2014-10-16 23:54:11 -0700587 it->second->shutdown();
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700588 }
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800589
590 delete m_settingDialog;
591 delete m_startChatDialog;
592 delete m_profileEditor;
593 delete m_invitationDialog;
Yingdi Yuf4aaa8b2014-03-10 11:24:31 -0700594 delete m_browseContactDialog;
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800595 delete m_addContactPanel;
Yingdi Yuf4aaa8b2014-03-10 11:24:31 -0700596
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700597 if (m_backend.isRunning()) {
598 emit shutdownBackend();
599 m_backend.wait();
600 }
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800601
602 QApplication::quit();
603}
604
605void
606Controller::onStartChatroom(const QString& chatroomName, bool secured)
607{
608 Name chatroomPrefix;
609 chatroomPrefix.append("ndn")
610 .append("broadcast")
611 .append("ChronoChat")
612 .append(chatroomName.toStdString());
613
614 // check if the chatroom exists
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700615 if (m_chatDialogList.find(chatroomName.toStdString()) != m_chatDialogList.end()) {
616 QMessageBox::information(this, tr("ChronoChat"),
617 tr("You are creating an existing chatroom."
618 "You can check it in the context memu."));
619 return;
620 }
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800621
Mengjin Yan391d7242014-08-28 20:51:55 -0700622 // TODO: We should create a chatroom specific key/cert
623 //(which should be created in the first half of this method
624 //, but let's use the default one for now.
Yingdi Yud45777b2014-10-16 23:54:11 -0700625 Name chatPrefix;
626 chatPrefix.append(m_identity).append("CHRONOCHAT-DATA").append(chatroomName.toStdString());
627
Mengjin Yan391d7242014-08-28 20:51:55 -0700628 ChatDialog* chatDialog
Yingdi Yud45777b2014-10-16 23:54:11 -0700629 = new ChatDialog(chatroomPrefix,
630 chatPrefix,
631 m_localPrefix,
632 chatroomName.toStdString(),
633 m_nick);
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800634
Yingdi Yufa0b6a02014-04-30 14:26:42 -0700635 addChatDialog(chatroomName, chatDialog);
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800636 chatDialog->show();
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700637
638 emit addChatroom(chatroomName);
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800639}
640
641void
Yingdi Yueb692ac2015-02-10 18:46:18 -0800642Controller::onStartChatroom2(chronochat::Invitation invitation, bool secured)
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800643{
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700644 QString chatroomName = QString::fromStdString(invitation.getChatroom());
645 onStartChatroom(chatroomName, secured);
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800646
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700647 ChatDialogList::iterator it = m_chatDialogList.find(chatroomName.toStdString());
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800648
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700649 BOOST_ASSERT(it != m_chatDialogList.end());
650 it->second->addSyncAnchor(invitation);
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800651}
652
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700653
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800654void
655Controller::onShowChatMessage(const QString& chatroomName, const QString& from, const QString& data)
656{
Yingdi Yufa0b6a02014-04-30 14:26:42 -0700657 m_trayIcon->showMessage(QString("Chatroom %1 has a new message").arg(chatroomName),
658 QString("<%1>: %2").arg(from).arg(data),
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800659 QSystemTrayIcon::Information, 20000);
660 m_trayIcon->setIcon(QIcon(":/images/note.png"));
661}
662
663void
Yingdi Yu233a9722014-03-07 15:47:09 -0800664Controller::onResetIcon()
665{
666 m_trayIcon->setIcon(QIcon(":/images/icon_small.png"));
667}
668
669void
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800670Controller::onRemoveChatDialog(const QString& chatroomName)
671{
672 ChatDialogList::iterator it = m_chatDialogList.find(chatroomName.toStdString());
673
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700674 if (it != m_chatDialogList.end()) {
675 ChatDialog* deletedChat = it->second;
676 if (deletedChat)
677 delete deletedChat;
678 m_chatDialogList.erase(it);
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800679
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700680 QAction* chatAction = m_chatActionList[chatroomName.toStdString()];
681 QAction* closeAction = m_closeActionList[chatroomName.toStdString()];
682 if (chatAction)
683 delete chatAction;
684 if (closeAction)
685 delete closeAction;
Yingdi Yufa0b6a02014-04-30 14:26:42 -0700686
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700687 m_chatActionList.erase(chatroomName.toStdString());
688 m_closeActionList.erase(chatroomName.toStdString());
Yingdi Yufa0b6a02014-04-30 14:26:42 -0700689
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700690 updateMenu();
691 }
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800692}
693
694void
695Controller::onWarning(const QString& msg)
696{
697 QMessageBox::information(this, tr("ChronoChat"), msg);
698}
699
700void
Yingdi Yufa0b6a02014-04-30 14:26:42 -0700701Controller::onError(const QString& msg)
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800702{
703 QMessageBox::critical(this, tr("ChronoChat"), msg, QMessageBox::Ok);
704 exit(1);
705}
706
Yingdi Yu233a9722014-03-07 15:47:09 -0800707void
Yingdi Yueb692ac2015-02-10 18:46:18 -0800708Controller::onRosterChanged(const chronochat::ChatroomInfo& info)
Mengjin Yan391d7242014-08-28 20:51:55 -0700709{
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700710
Mengjin Yan391d7242014-08-28 20:51:55 -0700711}
712
Yingdi Yueb692ac2015-02-10 18:46:18 -0800713} // namespace chronochat
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800714
715#if WAF
716#include "controller.moc"
Yingdi Yu42125862014-08-07 17:04:28 -0700717// #include "controller.cpp.moc"
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800718#endif