blob: 723617a62c13addb717588a89e636820e20c0fe5 [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>
15#include "controller.h"
16
17#ifndef Q_MOC_RUN
18#include <boost/filesystem.hpp>
19#include <boost/lexical_cast.hpp>
20#include <ndn-cpp-dev/util/random.hpp>
21#include <cryptopp/sha.h>
22#include <cryptopp/hex.h>
23#include <cryptopp/files.h>
24#include <cryptopp/filters.h>
25#include "config.pb.h"
26#include "endorse-info.pb.h"
27#include "logging.h"
28#endif
29
30INIT_LOGGER("chronos.Controller");
31
32using namespace ndn;
33
34Q_DECLARE_METATYPE(ndn::Name)
35Q_DECLARE_METATYPE(ndn::IdentityCertificate)
36Q_DECLARE_METATYPE(chronos::EndorseInfo)
37
38namespace chronos {
39
40static const uint8_t ROUTING_PREFIX_SEPARATOR[2] = {0xF0, 0x2E};
41
42// constructor & destructor
43Controller::Controller(shared_ptr<Face> face,
44 QWidget* parent)
45 : QDialog(parent)
46 , m_face(face)
47 , m_invitationListenerId(0)
48 , m_contactManager(m_face)
49 , m_settingDialog(new SettingDialog)
50 , m_startChatDialog(new StartChatDialog)
51 , m_profileEditor(new ProfileEditor)
52 , m_invitationDialog(new InvitationDialog)
53 , m_contactPanel(new ContactPanel)
54 , m_browseContactDialog(new BrowseContactDialog)
55 , m_addContactPanel(new AddContactPanel)
56{
57 qRegisterMetaType<ndn::Name>("ndn.Name");
58 qRegisterMetaType<ndn::IdentityCertificate>("ndn.IdentityCertificate");
59 qRegisterMetaType<chronos::EndorseInfo>("chronos.EndorseInfo");
60
61 connect(this, SIGNAL(localPrefixUpdated(const QString&)),
62 this, SLOT(onLocalPrefixUpdated(const QString&)));
63
64 // Connection to ContactManager
65 connect(this, SIGNAL(identityUpdated(const QString&)),
66 &m_contactManager, SLOT(onIdentityUpdated(const QString&)));
67 connect(&m_contactManager, SIGNAL(warning(const QString&)),
68 this, SLOT(onWarning(const QString&)));
69 connect(this, SIGNAL(refreshBrowseContact()),
70 &m_contactManager, SLOT(onRefreshBrowseContact()));
71 connect(&m_contactManager, SIGNAL(contactInfoFetchFailed(const QString&)),
72 this, SLOT(onWarning(const QString&)));
73 connect(&m_contactManager, SIGNAL(contactIdListReady(const QStringList&)),
74 this, SLOT(onContactIdListReady(const QStringList&)));
75
76 // Connection to SettingDialog
77 connect(this, SIGNAL(identityUpdated(const QString&)),
78 m_settingDialog, SLOT(onIdentityUpdated(const QString&)));
79 connect(m_settingDialog, SIGNAL(identityUpdated(const QString&)),
80 this, SLOT(onIdentityUpdated(const QString&)));
81 connect(m_settingDialog, SIGNAL(nickUpdated(const QString&)),
82 this, SLOT(onNickUpdated(const QString&)));
83
84 // Connection to ProfileEditor
85 connect(this, SIGNAL(closeDBModule()),
86 m_profileEditor, SLOT(onCloseDBModule()));
87 connect(this, SIGNAL(identityUpdated(const QString&)),
88 m_profileEditor, SLOT(onIdentityUpdated(const QString&)));
89 connect(m_profileEditor, SIGNAL(updateProfile()),
90 &m_contactManager, SLOT(onUpdateProfile()));
91
92 // Connection to StartChatDialog
93 connect(m_startChatDialog, SIGNAL(startChatroom(const QString&, bool)),
94 this, SLOT(onStartChatroom(const QString&, bool)));
95
96 // Connection to InvitationDialog
97 connect(m_invitationDialog, SIGNAL(invitationResponded(const ndn::Name&, bool)),
98 this, SLOT(onInvitationResponded(const ndn::Name&, bool)));
99
100 // Connection to AddContactPanel
101 connect(m_addContactPanel, SIGNAL(fetchInfo(const QString&)),
102 &m_contactManager, SLOT(onFetchContactInfo(const QString&)));
103 connect(m_addContactPanel, SIGNAL(addContact(const QString&)),
104 &m_contactManager, SLOT(onAddFetchedContact(const QString&)));
105 connect(&m_contactManager, SIGNAL(contactEndorseInfoReady(const chronos::EndorseInfo&)),
106 m_addContactPanel, SLOT(onContactEndorseInfoReady(const chronos::EndorseInfo&)));
107
108
109 // Connection to BrowseContactDialog
110 connect(m_browseContactDialog, SIGNAL(directAddClicked()),
111 this, SLOT(onDirectAdd()));
112 connect(m_browseContactDialog, SIGNAL(fetchIdCert(const QString&)),
113 &m_contactManager, SLOT(onFetchIdCert(const QString&)));
114 connect(m_browseContactDialog, SIGNAL(addContact(const QString&)),
115 &m_contactManager, SLOT(onAddFetchedContactIdCert(const QString&)));
116 connect(&m_contactManager, SIGNAL(idCertNameListReady(const QStringList&)),
117 m_browseContactDialog, SLOT(onIdCertNameListReady(const QStringList&)));
118 connect(&m_contactManager, SIGNAL(nameListReady(const QStringList&)),
119 m_browseContactDialog, SLOT(onNameListReady(const QStringList&)));
120 connect(&m_contactManager, SIGNAL(idCertReady(const ndn::IdentityCertificate&)),
121 m_browseContactDialog, SLOT(onIdCertReady(const ndn::IdentityCertificate&)));
122
123 // Connection to ContactPanel
124 connect(m_contactPanel, SIGNAL(waitForContactList()),
125 &m_contactManager, SLOT(onWaitForContactList()));
126 connect(m_contactPanel, SIGNAL(waitForContactInfo(const QString&)),
127 &m_contactManager, SLOT(onWaitForContactInfo(const QString&)));
128 connect(m_contactPanel, SIGNAL(removeContact(const QString&)),
129 &m_contactManager, SLOT(onRemoveContact(const QString&)));
130 connect(m_contactPanel, SIGNAL(updateAlias(const QString&, const QString&)),
131 &m_contactManager, SLOT(onUpdateAlias(const QString&, const QString&)));
132 connect(m_contactPanel, SIGNAL(updateIsIntroducer(const QString&, bool)),
133 &m_contactManager, SLOT(onUpdateIsIntroducer(const QString&, bool)));
134 connect(m_contactPanel, SIGNAL(updateEndorseCertificate(const QString&)),
135 &m_contactManager, SLOT(onUpdateEndorseCertificate(const QString&)));
136 connect(m_contactPanel, SIGNAL(warning(const QString&)),
137 this, SLOT(onWarning(const QString&)));
138 connect(this, SIGNAL(closeDBModule()),
139 m_contactPanel, SLOT(onCloseDBModule()));
140 connect(this, SIGNAL(identityUpdated(const QString&)),
141 m_contactPanel, SLOT(onIdentityUpdated(const QString&)));
142 connect(&m_contactManager, SIGNAL(contactAliasListReady(const QStringList&)),
143 m_contactPanel, SLOT(onContactAliasListReady(const QStringList&)));
144 connect(&m_contactManager, SIGNAL(contactIdListReady(const QStringList&)),
145 m_contactPanel, SLOT(onContactIdListReady(const QStringList&)));
146 connect(&m_contactManager, SIGNAL(contactInfoReady(const QString&, const QString&, const QString&, bool)),
147 m_contactPanel, SLOT(onContactInfoReady(const QString&, const QString&, const QString&, bool)));
148
149 initialize();
150
151 createTrayIcon();
152}
153
154Controller::~Controller()
155{
156 saveConf();
157}
158
159// public methods
160
161
162// private methods
163std::string
164Controller::getDBName()
165{
166 std::string dbName("chronos-");
167
168 std::stringstream ss;
169 {
170 using namespace CryptoPP;
171
172 SHA256 hash;
173 StringSource(m_identity.wireEncode().wire(), m_identity.wireEncode().size(), true,
174 new HashFilter(hash, new HexEncoder(new FileSink(ss), false)));
175 }
176 dbName.append(ss.str()).append(".db");
177
178 return dbName;
179}
180
181void
182Controller::openDB()
183{
184 m_db = QSqlDatabase::addDatabase("QSQLITE");
185 QString path = (QDir::home().path());
186 path.append(QDir::separator()).append(".chronos").append(QDir::separator()).append(getDBName().c_str());
187 m_db.setDatabaseName(path);
188 bool ok = m_db.open();
189
190 _LOG_DEBUG("DB opened: " << std::boolalpha << ok );
191}
192
193void
194Controller::initialize()
195{
196 loadConf();
197
198 m_keyChain.createIdentity(m_identity);
199
200 openDB();
201
202 emit identityUpdated(QString(m_identity.toUri().c_str()));
203
204 setInvitationListener();
205}
206
207void
208Controller::setInvitationListener()
209{
210 if(m_invitationListenerId != 0)
211 m_face->unsetInterestFilter(m_invitationListenerId);
212
213 Name invitationPrefix;
214 Name routingPrefix = getInvitationRoutingPrefix();
215 size_t offset = 0;
216 if(!routingPrefix.isPrefixOf(m_identity))
217 {
218 invitationPrefix.append(routingPrefix).append(ROUTING_PREFIX_SEPARATOR, 2);
219 offset = routingPrefix.size() + 1;
220 }
221 invitationPrefix.append(m_identity).append("CHRONOCHAT-INVITATION");
222
223 m_invitationListenerId = m_face->setInterestFilter(invitationPrefix,
224 bind(&Controller::onInvitationInterest, this, _1, _2, offset),
225 bind(&Controller::onInvitationRegisterFailed, this, _1, _2));
226}
227
228void
229Controller::loadConf()
230{
231 namespace fs = boost::filesystem;
232
233 fs::path chronosDir = fs::path(getenv("HOME")) / ".chronos";
234 fs::create_directories (chronosDir);
235
236 std::ifstream is((chronosDir / "config").c_str ());
237 ChronoChat::Conf conf;
238 if(conf.ParseFromIstream(&is))
239 {
240 m_identity.clear();
241 m_identity.append(conf.identity());
242 if(conf.has_nick())
243 m_nick = conf.nick();
244 else
245 m_nick = m_identity.get(-1).toUri();
246 }
247 else
248 {
249 m_identity.clear();
250 // TODO: change below to system default;
251 m_identity.append("chronochat-tmp-identity")
252 .append(boost::lexical_cast<std::string>(random::generateWord64()));
253
254 m_nick = m_identity.get(-1).toUri();
255 }
256}
257
258void
259Controller::saveConf()
260{
261 namespace fs = boost::filesystem;
262
263 fs::path chronosDir = fs::path(getenv("HOME")) / ".chronos";
264 fs::create_directories (chronosDir);
265
266 std::ofstream os((chronosDir / "config").c_str ());
267 ChronoChat::Conf conf;
268 conf.set_identity(m_identity.toUri());
269 if(!m_nick.empty())
270 conf.set_nick(m_nick);
271 conf.SerializeToOstream(&os);
272
273 os.close();
274}
275
276void
277Controller::createActions()
278{
279 m_startChatroom = new QAction(tr("Start new chat"), this);
280 connect(m_startChatroom, SIGNAL(triggered()), this, SLOT(onStartChatAction()));
281
282 m_settingsAction = new QAction(tr("Settings"), this);
283 connect(m_settingsAction, SIGNAL(triggered()), this, SLOT(onSettingsAction()));
284
285 m_editProfileAction = new QAction(tr("Edit profile"), this);
286 connect(m_editProfileAction, SIGNAL(triggered()), this, SLOT(onProfileEditorAction()));
287
288 m_contactListAction = new QAction(tr("Contact List"), this);
289 connect(m_contactListAction, SIGNAL(triggered()), this, SLOT(onContactListAction()));
290
291 m_addContactAction = new QAction(tr("Add contact"), this);
292 connect(m_addContactAction, SIGNAL(triggered()), this, SLOT(onAddContactAction()));
293
294 m_updateLocalPrefixAction = new QAction(tr("Update local prefix"), this);
295 connect(m_updateLocalPrefixAction, SIGNAL(triggered()), this, SLOT(onUpdateLocalPrefixAction()));
296
297 m_minimizeAction = new QAction(tr("Mi&nimize"), this);
298 connect(m_minimizeAction, SIGNAL(triggered()), this, SLOT(onMinimizeAction()));
299
300 m_quitAction = new QAction(tr("Quit"), this);
301 connect(m_quitAction, SIGNAL(triggered()), this, SLOT(onQuitAction()));
302}
303
304void
305Controller::createTrayIcon()
306{
307 createActions();
308
309 m_trayIconMenu = new QMenu(this);
310 m_trayIconMenu->addAction(m_startChatroom);
311 m_trayIconMenu->addSeparator();
312 m_trayIconMenu->addAction(m_settingsAction);
313 m_trayIconMenu->addAction(m_editProfileAction);
314 m_trayIconMenu->addSeparator();
315 m_trayIconMenu->addAction(m_contactListAction);
316 m_trayIconMenu->addAction(m_addContactAction);
317 m_trayIconMenu->addSeparator();
318 m_trayIconMenu->addAction(m_updateLocalPrefixAction);
319 m_trayIconMenu->addSeparator();
320 m_trayIconMenu->addAction(m_minimizeAction);
321 m_closeMenu = m_trayIconMenu->addMenu("Close chatroom");
322 m_closeMenu->setEnabled(false);
323 m_trayIconMenu->addSeparator();
324 m_trayIconMenu->addAction(m_quitAction);
325
326 m_trayIcon = new QSystemTrayIcon(this);
327 m_trayIcon->setContextMenu(m_trayIconMenu);
328
329 m_trayIcon->setIcon(QIcon(":/images/icon_small.png"));
330 m_trayIcon->setToolTip("ChronoChat System Tray Icon");
331 m_trayIcon->setVisible(true);
332}
333
334void
335Controller::updateMenu()
336{
337 QMenu* menu = new QMenu(this);
338 QMenu* closeMenu = 0;
339
340 menu->addAction(m_startChatroom);
341 menu->addSeparator();
342 menu->addAction(m_settingsAction);
343 menu->addAction(m_editProfileAction);
344 menu->addSeparator();
345 menu->addAction(m_addContactAction);
346 menu->addSeparator();
347 {
348 ChatActionList::const_iterator it = m_chatActionList.begin();
349 ChatActionList::const_iterator end = m_chatActionList.end();
350 if(it != end)
351 {
352 for(; it != end; it++)
353 menu->addAction(it->second);
354 menu->addSeparator();
355 }
356 }
357 menu->addAction(m_updateLocalPrefixAction);
358 menu->addSeparator();
359 menu->addAction(m_minimizeAction);
360 closeMenu = menu->addMenu("Close chatroom");
361 {
362 ChatActionList::const_iterator it = m_closeActionList.begin();
363 ChatActionList::const_iterator end = m_closeActionList.end();
364 if(it == end)
365 {
366 closeMenu->setEnabled(false);
367 }
368 else
369 {
370 for(; it != end; it++)
371 closeMenu->addAction(it->second);
372 }
373 }
374 menu->addSeparator();
375 menu->addAction(m_quitAction);
376
377 m_trayIcon->setContextMenu(menu);
378 delete m_trayIconMenu;
379 m_trayIconMenu = menu;
380 m_closeMenu = closeMenu;
381}
382
383void
384Controller::onLocalPrefix(const Interest& interest, Data& data)
385{
386 QString localPrefixStr = QString::fromUtf8
387 (reinterpret_cast<const char*>(data.getContent().value()), data.getContent().value_size())
388 .trimmed();
389
390 Name localPrefix(localPrefixStr.toStdString());
391 if(m_localPrefix.empty() || m_localPrefix != localPrefix)
392 emit localPrefixUpdated(localPrefixStr);
393}
394
395void
396Controller::onLocalPrefixTimeout(const Interest& interest)
397{
398 QString localPrefixStr("/private/local");
399
400 Name localPrefix(localPrefixStr.toStdString());
401 if(m_localPrefix.empty() || m_localPrefix != localPrefix)
402 emit localPrefixUpdated(localPrefixStr);
403}
404
405void
406Controller::onInvitationInterest(const Name& prefix, const Interest& interest, size_t routingPrefixOffset)
407{
408 shared_ptr<Interest> invitationInterest = make_shared<Interest>(boost::cref(interest.getName().getSubName(routingPrefixOffset)));
409
410 // check if the chatroom already exists;
411 try
412 {
413 Invitation invitation(invitationInterest->getName());
414 if(m_chatDialogList.find(invitation.getChatroom()) != m_chatDialogList.end())
415 return;
416 }
417 catch(Invitation::Error& e)
418 {
419 // Cannot parse the invitation;
420 return;
421 }
422
423 OnInterestValidated onValidated = bind(&Controller::onInvitationValidated, this, _1);
424 OnInterestValidationFailed onValidationFailed = bind(&Controller::onInvitationValidationFailed, this, _1, _2);
425 m_validator.validate(*invitationInterest, onValidated, onValidationFailed);
426}
427
428void
429Controller::onInvitationRegisterFailed(const Name& prefix, const std::string& failInfo)
430{
431 std::cerr << "Controller::onInvitationRegisterFailed: " << failInfo << std::endl;
432}
433
434void
435Controller::onInvitationValidated(const shared_ptr<const Interest>& interest)
436{
437 Invitation invitation(interest->getName());
438 std::string alias = invitation.getInviterCertificate().getPublicKeyName().getPrefix(-1).toUri(); // Should be obtained via a method of ContactManager.
439
440 m_invitationDialog->setInvitation(alias, invitation.getChatroom(), interest->getName());
441 m_invitationDialog->show();
442}
443
444void
445Controller::onInvitationValidationFailed(const shared_ptr<const Interest>& interest, std::string failureInfo)
446{
447 std::cerr << "Invitation: " << interest->getName() << " cannot not be validated due to: " << failureInfo << std::endl;
448}
449
450std::string
451Controller::getRandomString()
452{
453 uint32_t r = random::generateWord32();
454 std::stringstream ss;
455 {
456 using namespace CryptoPP;
457 StringSource(reinterpret_cast<uint8_t*>(&r), 4, true,
458 new HexEncoder(new FileSink(ss), false));
459
460 }
461 // for(int i = 0; i < 8; i++)
462 // {
463 // uint32_t t = r & mask;
464 // if(t < 10)
465 // ss << static_cast<char>(t + 0x30);
466 // else
467 // ss << static_cast<char>(t + 0x57);
468 // r = r >> 4;
469 // }
470
471 return ss.str();
472}
473
474ndn::Name
475Controller::getInvitationRoutingPrefix()
476{
477 return Name("/ndn/broadcast");
478}
479
480void
481Controller::addChatDialog(const QString& chatroomName, ChatDialog* chatDialog)
482{
483 m_chatDialogList[chatroomName.toStdString()] = chatDialog;
484 connect(chatDialog, SIGNAL(closeChatDialog(const QString&)),
485 this, SLOT(onRemoveChatDialog(const QString&)));
486 connect(chatDialog, SIGNAL(showChatMessage(const QString&, const QString&, const QString&)),
487 this, SLOT(onShowChatMessage(const QString&, const QString&, const QString&)));
488 connect(this, SIGNAL(localPrefixUpdated(const QString&)),
489 chatDialog, SLOT(onLocalPrefixUpdated(const QString&)));
490
491 QAction* chatAction = new QAction(chatroomName, this);
492 m_chatActionList[chatroomName.toStdString()] = chatAction;
493 connect(chatAction, SIGNAL(triggered()), chatDialog, SLOT(showNormal()));
494
495 QAction* closeAction = new QAction(chatroomName, this);
496 m_closeActionList[chatroomName.toStdString()] = closeAction;
497 connect(closeAction, SIGNAL(triggered()), chatDialog, SLOT(onClose()));
498
499 updateMenu();
500}
501
502// private slots:
503void
504Controller::onIdentityUpdated(const QString& identity)
505{
506 Name identityName(identity.toStdString());
507
508 while(!m_chatDialogList.empty())
509 {
510 ChatDialogList::const_iterator it = m_chatDialogList.begin();
511 onRemoveChatDialog(QString::fromStdString(it->first));
512 }
513
514 m_identity = identityName;
515 m_keyChain.createIdentity(m_identity);
516
517 emit closeDBModule();
518
519 QTimer::singleShot(500, this, SLOT(onIdentityUpdatedContinued()));
520
521}
522
523void
524Controller::onIdentityUpdatedContinued()
525{
526 QString connection = m_db.connectionName();
527 // _LOG_DEBUG("connection name: " << connection.toStdString());
528 QSqlDatabase::removeDatabase(connection);
529 m_db.close();
530
531 openDB();
532
533 emit identityUpdated(QString(m_identity.toUri().c_str()));
534}
535
536void
537Controller::onContactIdListReady(const QStringList& list)
538{
539 ContactList contactList;
540
541 m_contactManager.getContactList(contactList);
542 m_validator.cleanTrustAnchor();
543
544 ContactList::const_iterator it = contactList.begin();
545 ContactList::const_iterator end = contactList.end();
546
547 for(; it != end; it++)
548 m_validator.addTrustAnchor((*it)->getPublicKeyName(), (*it)->getPublicKey());
549
550}
551
552void
553Controller::onNickUpdated(const QString& nick)
554{
555 m_nick = nick.toStdString();
556}
557
558void
559Controller::onLocalPrefixUpdated(const QString& localPrefix)
560{
561 m_localPrefix = Name(localPrefix.toStdString());
562}
563
564void
565Controller::onStartChatAction()
566{
567 std::string chatroom = "chatroom-" + getRandomString();
568
569 m_startChatDialog->setChatroom(chatroom);
570 m_startChatDialog->show();
571 m_startChatDialog->raise();
572}
573
574void
575Controller::onSettingsAction()
576{
577 m_settingDialog->setNick(QString(m_nick.c_str()));
578 m_settingDialog->show();
579 m_settingDialog->raise();
580}
581
582void
583Controller::onProfileEditorAction()
584{
585 m_profileEditor->show();
586 m_profileEditor->raise();
587}
588
589void
590Controller::onAddContactAction()
591{
592 emit refreshBrowseContact();
593 m_browseContactDialog->show();
594 m_browseContactDialog->raise();
595}
596
597void
598Controller::onContactListAction()
599{
600 m_contactPanel->show();
601 m_contactPanel->raise();
602}
603
604void
605Controller::onDirectAdd()
606{
607 m_addContactPanel->show();
608 m_addContactPanel->raise();
609}
610
611void
612Controller::onUpdateLocalPrefixAction()
613{
614 // Name interestName();
615 Interest interest("/local/ndn/prefix");
616 interest.setInterestLifetime(1000);
617 interest.setMustBeFresh(true);
618
619 m_face->expressInterest(interest,
620 bind(&Controller::onLocalPrefix, this, _1, _2),
621 bind(&Controller::onLocalPrefixTimeout, this, _1));
622}
623
624void
625Controller::onMinimizeAction()
626{
627 m_settingDialog->hide();
628 m_startChatDialog->hide();
629 m_profileEditor->hide();
630 m_invitationDialog->hide();
631 m_addContactPanel->hide();
632
633 ChatDialogList::iterator it = m_chatDialogList.begin();
634 ChatDialogList::iterator end = m_chatDialogList.end();
635 for(; it != end; it++)
636 it->second->hide();
637}
638
639void
640Controller::onQuitAction()
641{
642 while(!m_chatDialogList.empty())
643 {
644 ChatDialogList::const_iterator it = m_chatDialogList.begin();
645 onRemoveChatDialog(QString::fromStdString(it->first));
646 }
647
648 delete m_settingDialog;
649 delete m_startChatDialog;
650 delete m_profileEditor;
651 delete m_invitationDialog;
652 delete m_addContactPanel;
653 // TODO: clean up all the dialog.
654
655 QApplication::quit();
656}
657
658void
659Controller::onStartChatroom(const QString& chatroomName, bool secured)
660{
661 Name chatroomPrefix;
662 chatroomPrefix.append("ndn")
663 .append("broadcast")
664 .append("ChronoChat")
665 .append(chatroomName.toStdString());
666
667 // check if the chatroom exists
668 if(m_chatDialogList.find(chatroomName.toStdString()) != m_chatDialogList.end())
669 {
670 QMessageBox::information(this, tr("ChronoChat"),
671 tr("You are creating an existing chatroom."
672 "You can check it in the context memu."));
673 return;
674 }
675
676 // TODO: We should create a chatroom specific key/cert (which should be created in the first half of this method, but let's use the default one for now.
677 shared_ptr<IdentityCertificate> idCert = m_keyChain.getCertificate(m_keyChain.getDefaultCertificateNameForIdentity(m_identity));
678 ChatDialog* chatDialog = new ChatDialog(&m_contactManager, m_face, *idCert, chatroomPrefix, m_localPrefix, m_nick, secured);
679
680 addChatDialog(chatroomName, chatDialog);
681 chatDialog->show();
682}
683
684void
685Controller::onInvitationResponded(const Name& invitationName, bool accepted)
686{
687 Data response;
688 shared_ptr<IdentityCertificate> chatroomCert;
689
690 // generate reply;
691 if(accepted)
692 {
693 Name responseName = invitationName;
694 responseName.append(m_localPrefix.wireEncode());
695
696 response.setName(responseName);
697
698 // We should create a particular certificate for this chatroom, but let's use default one for now.
699 chatroomCert = m_keyChain.getCertificate(m_keyChain.getDefaultCertificateNameForIdentity(m_identity));
700
701 response.setContent(chatroomCert->wireEncode());
702 response.setFreshnessPeriod(1000);
703 }
704 else
705 {
706 response.setName(invitationName);
707 response.setFreshnessPeriod(1000);
708 }
709
710 // Check if we need a wrapper
711 Name invitationRoutingPrefix = getInvitationRoutingPrefix();
712 if(invitationRoutingPrefix.isPrefixOf(m_identity))
713 {
714 m_keyChain.signByIdentity(response, m_identity);
715 m_face->put(response);
716 }
717 else
718 {
719 Name wrappedName;
720 wrappedName.append(invitationRoutingPrefix).append(ROUTING_PREFIX_SEPARATOR, 2);
721
722 Data wrappedData(wrappedName);
723 wrappedData.setContent(response.wireEncode());
724 wrappedData.setFreshnessPeriod(1000);
725
726 m_keyChain.signByIdentity(response, m_identity);
727 m_face->put(response);
728 }
729
730 // create chatroom
731 if(accepted)
732 {
733 Invitation invitation(invitationName);
734 Name chatroomPrefix;
735 chatroomPrefix.append("ndn")
736 .append("broadcast")
737 .append("ChronoChat")
738 .append(invitation.getChatroom());
739
740 //We should create a chatroom specific key/cert (which should be created in the first half of this method, but let's use the default one for now.
741 shared_ptr<IdentityCertificate> idCert = m_keyChain.getCertificate(m_keyChain.getDefaultCertificateNameForIdentity(m_identity));
742 ChatDialog* chatDialog = new ChatDialog(&m_contactManager, m_face, *idCert, chatroomPrefix, m_localPrefix, m_nick, true);
743
744 addChatDialog(QString::fromStdString(invitation.getChatroom()), chatDialog);
745 chatDialog->addSyncAnchor(invitation);
746 chatDialog->show();
747 }
748}
749
750void
751Controller::onShowChatMessage(const QString& chatroomName, const QString& from, const QString& data)
752{
753 m_trayIcon->showMessage(QString("Chatroom %1 has a new message").arg(chatroomName),
754 QString("<%1>: %2").arg(from).arg(data),
755 QSystemTrayIcon::Information, 20000);
756 m_trayIcon->setIcon(QIcon(":/images/note.png"));
757}
758
759void
760Controller::onRemoveChatDialog(const QString& chatroomName)
761{
762 ChatDialogList::iterator it = m_chatDialogList.find(chatroomName.toStdString());
763
764 if(it != m_chatDialogList.end())
765 {
766 ChatDialog* deletedChat = it->second;
767 if(deletedChat)
768 delete deletedChat;
769 m_chatDialogList.erase(it);
770
771 QAction* chatAction = m_chatActionList[chatroomName.toStdString()];
772 QAction* closeAction = m_closeActionList[chatroomName.toStdString()];
773 if(chatAction)
774 delete chatAction;
775 if(closeAction)
776 delete closeAction;
777
778 m_chatActionList.erase(chatroomName.toStdString());
779 m_closeActionList.erase(chatroomName.toStdString());
780
781 updateMenu();
782 }
783}
784
785void
786Controller::onWarning(const QString& msg)
787{
788 QMessageBox::information(this, tr("ChronoChat"), msg);
789}
790
791void
792Controller::onError(const QString& msg)
793{
794 QMessageBox::critical(this, tr("ChronoChat"), msg, QMessageBox::Ok);
795 exit(1);
796}
797
798} // namespace chronos
799
800#if WAF
801#include "controller.moc"
802#include "controller.cpp.moc"
803#endif