blob: cd7a7ea166d7463932aded49cdc2357f0f1ab511 [file] [log] [blame]
Alexander Afanasyevb4b92292013-07-09 13:54:59 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
2/*
3 * Copyright (c) 2013, Regents of the University of California
Yingdi Yu5b989132013-10-23 14:03:09 -07004 * Yingdi Yu
Alexander Afanasyevb4b92292013-07-09 13:54:59 -07005 *
Yingdi Yu5b989132013-10-23 14:03:09 -07006 * BSD license, See the LICENSE file for more information
Alexander Afanasyevb4b92292013-07-09 13:54:59 -07007 *
Yingdi Yu7989eb22013-10-31 17:38:22 -07008 * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
9 * Alexander Afanasyev <alexander.afanasyev@ucla.edu>
10 * Yingdi Yu <yingdi@cs.ucla.edu>
Alexander Afanasyevb4b92292013-07-09 13:54:59 -070011 */
12
Zhenkai Zhu6d589aa2012-05-29 17:34:35 -070013#include "chatdialog.h"
Yingdi Yu5b989132013-10-23 14:03:09 -070014#include "ui_chatdialog.h"
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -070015
Yingdi Yu7989eb22013-10-31 17:38:22 -070016#include <QScrollBar>
Yingdi Yu702d6f12013-11-07 17:00:54 -080017#include <QMessageBox>
18#include <QCloseEvent>
Yingdi Yu7989eb22013-10-31 17:38:22 -070019
Yingdi Yueda39aa2013-10-23 23:07:29 -070020#ifndef Q_MOC_RUN
Yingdi Yu7989eb22013-10-31 17:38:22 -070021#include <sync-intro-certificate.h>
22#include <boost/random/random_device.hpp>
23#include <boost/random/uniform_int_distribution.hpp>
Yingdi Yuf8f572d2014-01-13 11:19:47 -080024#include <ndn-cpp/security/signature/signature-sha256-with-rsa.hpp>
Yingdi Yueda39aa2013-10-23 23:07:29 -070025#include "logging.h"
26#endif
27
Yingdi Yu5b989132013-10-23 14:03:09 -070028using namespace std;
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -070029
Yingdi Yueda39aa2013-10-23 23:07:29 -070030INIT_LOGGER("ChatDialog");
31
Yingdi Yu7989eb22013-10-31 17:38:22 -070032static const int HELLO_INTERVAL = FRESHNESS * 3 / 4;
33
34Q_DECLARE_METATYPE(std::vector<Sync::MissingDataInfo> )
35Q_DECLARE_METATYPE(size_t)
36
Yingdi Yu76dd8002013-12-24 11:16:32 +080037ChatDialog::ChatDialog(ndn::ptr_lib::shared_ptr<ContactManager> contactManager,
Yingdi Yu7989eb22013-10-31 17:38:22 -070038 const ndn::Name& chatroomPrefix,
39 const ndn::Name& localPrefix,
40 const ndn::Name& defaultIdentity,
Yingdi Yu46948282013-11-06 18:43:31 -080041 const std::string& nick,
42 bool trial,
Yingdi Yu5b989132013-10-23 14:03:09 -070043 QWidget *parent)
Yingdi Yu7989eb22013-10-31 17:38:22 -070044: QDialog(parent)
45 , ui(new Ui::ChatDialog)
46 , m_contactManager(contactManager)
47 , m_chatroomPrefix(chatroomPrefix)
48 , m_localPrefix(localPrefix)
49 , m_defaultIdentity(defaultIdentity)
Yingdi Yu76dd8002013-12-24 11:16:32 +080050 , m_invitationPolicyManager(new InvitationPolicyManager(m_chatroomPrefix.get(-1).toEscapedString(), m_defaultIdentity))
Yingdi Yuf8f572d2014-01-13 11:19:47 -080051 , m_keyChain(new ndn::KeyChain())
Yingdi Yu46948282013-11-06 18:43:31 -080052 , m_nick(nick)
Yingdi Yu7989eb22013-10-31 17:38:22 -070053 , m_sock(NULL)
54 , m_lastMsgTime(0)
55 // , m_historyInitialized(false)
56 , m_joined(false)
57 , m_inviteListDialog(new InviteListDialog(m_contactManager))
Zhenkai Zhu6d589aa2012-05-29 17:34:35 -070058{
Yingdi Yu7989eb22013-10-31 17:38:22 -070059 qRegisterMetaType<std::vector<Sync::MissingDataInfo> >("std::vector<Sync::MissingDataInfo>");
60 qRegisterMetaType<size_t>("size_t");
61
Yingdi Yueda39aa2013-10-23 23:07:29 -070062 ui->setupUi(this);
63
Yingdi Yufdb8ab82013-11-10 01:38:21 -080064 QString randString = getRandomString();
Yingdi Yu7989eb22013-10-31 17:38:22 -070065 m_localChatPrefix = m_localPrefix;
Yingdi Yu46948282013-11-06 18:43:31 -080066 m_localChatPrefix.append("%F0.").append(m_defaultIdentity);
Yingdi Yufdb8ab82013-11-10 01:38:21 -080067 m_localChatPrefix.append("chronos").append(m_chatroomPrefix.get(-1)).append(randString.toStdString());
Yingdi Yu7989eb22013-10-31 17:38:22 -070068
69 m_session = time(NULL);
70 m_scene = new DigestTreeScene(this);
71
72 initializeSetting();
73 updateLabels();
74
75 ui->treeViewer->setScene(m_scene);
76 ui->treeViewer->hide();
77 m_scene->plot("Empty");
78 QRectF rect = m_scene->itemsBoundingRect();
79 m_scene->setSceneRect(rect);
80
81 m_rosterModel = new QStringListModel(this);
82 ui->listView->setModel(m_rosterModel);
83
Yingdi Yu83eae842013-11-06 22:07:38 -080084 createActions();
85 createTrayIcon();
86
Yingdi Yu7989eb22013-10-31 17:38:22 -070087 m_timer = new QTimer(this);
88
Yingdi Yu6eabbd72013-12-27 08:44:12 +080089 startFace();
90
Yingdi Yuf8f572d2014-01-13 11:19:47 -080091 ndn::Name certificateName = m_keyChain->getDefaultCertificateNameForIdentity(m_defaultIdentity);
92 m_syncPolicyManager = ndn::ptr_lib::make_shared<SyncPolicyManager>(m_defaultIdentity, certificateName, m_chatroomPrefix, m_face);
Yingdi Yu7989eb22013-10-31 17:38:22 -070093
94 connect(ui->inviteButton, SIGNAL(clicked()),
95 this, SLOT(openInviteListDialog()));
96 connect(m_inviteListDialog, SIGNAL(invitionDetermined(QString, bool)),
97 this, SLOT(sendInvitationWrapper(QString, bool)));
98 connect(ui->lineEdit, SIGNAL(returnPressed()),
99 this, SLOT(returnPressed()));
100 connect(ui->treeButton, SIGNAL(pressed()),
101 this, SLOT(treeButtonPressed()));
102 connect(this, SIGNAL(dataReceived(QString, const char *, size_t, bool, bool)),
103 this, SLOT(processData(QString, const char *, size_t, bool, bool)));
104 connect(this, SIGNAL(treeUpdated(const std::vector<Sync::MissingDataInfo>)),
105 this, SLOT(processTreeUpdate(const std::vector<Sync::MissingDataInfo>)));
106 connect(m_timer, SIGNAL(timeout()),
107 this, SLOT(replot()));
108 connect(m_scene, SIGNAL(replot()),
109 this, SLOT(replot()));
Yingdi Yu83eae842013-11-06 22:07:38 -0800110 connect(trayIcon, SIGNAL(messageClicked()),
111 this, SLOT(showNormal()));
112 connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
113 this, SLOT(iconActivated(QSystemTrayIcon::ActivationReason)));
Yingdi Yu7989eb22013-10-31 17:38:22 -0700114 connect(m_scene, SIGNAL(rosterChanged(QStringList)),
115 this, SLOT(updateRosterList(QStringList)));
116
Yingdi Yu7989eb22013-10-31 17:38:22 -0700117
118 initializeSync();
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700119}
120
Yingdi Yu7989eb22013-10-31 17:38:22 -0700121
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700122ChatDialog::~ChatDialog()
123{
Yingdi Yu46948282013-11-06 18:43:31 -0800124 if(m_sock != NULL)
125 {
126 sendLeave();
127 delete m_sock;
128 m_sock = NULL;
129 }
Yingdi Yu6eabbd72013-12-27 08:44:12 +0800130 shutdownFace();
131}
132
133void
134ChatDialog::startFace()
135{
Yingdi Yuf8f572d2014-01-13 11:19:47 -0800136 m_face = ndn::ptr_lib::make_shared<ndn::Face>();
Yingdi Yu6eabbd72013-12-27 08:44:12 +0800137
138 connectToDaemon();
139
140 m_running = true;
141 m_thread = boost::thread (&ChatDialog::eventLoop, this);
142}
143
144void
145ChatDialog::shutdownFace()
146{
147 {
148 boost::unique_lock<boost::recursive_mutex> lock(m_mutex);
149 m_running = false;
150 }
151
152 m_thread.join();
Yingdi Yu76dd8002013-12-24 11:16:32 +0800153 m_face->shutdown();
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700154}
155
Zhenkai Zhu86df7412012-09-27 16:30:20 -0700156void
Yingdi Yu6eabbd72013-12-27 08:44:12 +0800157ChatDialog::eventLoop()
158{
159 while (m_running)
160 {
161 try{
162 m_face->processEvents();
163 usleep(1000);
164 }catch(std::exception& e){
165 _LOG_DEBUG(" " << e.what() );
166 }
167 }
168}
169
170void
Yingdi Yu76dd8002013-12-24 11:16:32 +0800171ChatDialog::connectToDaemon()
Zhenkai Zhucf024442012-10-05 10:33:08 -0700172{
Yingdi Yu76dd8002013-12-24 11:16:32 +0800173 //Hack! transport does not connect to daemon unless an interest is expressed.
174 ndn::Name name("/ndn");
175 ndn::ptr_lib::shared_ptr<ndn::Interest> interest = ndn::ptr_lib::make_shared<ndn::Interest>(name);
176 m_face->expressInterest(*interest,
177 boost::bind(&ChatDialog::onConnectionData, this, _1, _2),
178 boost::bind(&ChatDialog::onConnectionDataTimeout, this, _1));
Zhenkai Zhud13acd02012-06-04 15:25:20 -0700179}
Alexander Afanasyevb4b92292013-07-09 13:54:59 -0700180
Yingdi Yueda39aa2013-10-23 23:07:29 -0700181void
Yingdi Yu76dd8002013-12-24 11:16:32 +0800182ChatDialog::onConnectionData(const ndn::ptr_lib::shared_ptr<const ndn::Interest>& interest,
183 const ndn::ptr_lib::shared_ptr<ndn::Data>& data)
184{ _LOG_DEBUG("onConnectionData"); }
185
186void
187ChatDialog::onConnectionDataTimeout(const ndn::ptr_lib::shared_ptr<const ndn::Interest>& interest)
188{ _LOG_DEBUG("onConnectionDataTimeout"); }
189
190void
Yingdi Yu7989eb22013-10-31 17:38:22 -0700191ChatDialog::initializeSetting()
Yingdi Yueda39aa2013-10-23 23:07:29 -0700192{
Yingdi Yu46948282013-11-06 18:43:31 -0800193 m_user.setNick(QString::fromStdString(m_nick));
Yingdi Yu76dd8002013-12-24 11:16:32 +0800194 m_user.setChatroom(QString::fromStdString(m_chatroomPrefix.get(-1).toEscapedString()));
Yingdi Yu7989eb22013-10-31 17:38:22 -0700195 m_user.setOriginPrefix(QString::fromStdString(m_localPrefix.toUri()));
196 m_user.setPrefix(QString::fromStdString(m_localChatPrefix.toUri()));
197 m_scene->setCurrentPrefix(QString::fromStdString(m_localChatPrefix.toUri()));
198}
Yingdi Yueda39aa2013-10-23 23:07:29 -0700199
Yingdi Yu7989eb22013-10-31 17:38:22 -0700200void
201ChatDialog::updateLabels()
202{
203 QString settingDisp = QString("Chatroom: %1").arg(m_user.getChatroom());
204 ui->infoLabel->setStyleSheet("QLabel {color: #630; font-size: 16px; font: bold \"Verdana\";}");
205 ui->infoLabel->setText(settingDisp);
206 QString prefixDisp;
207 if (m_user.getPrefix().startsWith("/private/local"))
208 {
209 prefixDisp = QString("<Warning: no connection to hub or hub does not support prefix autoconfig.>\n <Prefix = %1>").arg(m_user.getPrefix());
210 ui->prefixLabel->setStyleSheet("QLabel {color: red; font-size: 12px; font: bold \"Verdana\";}");
211 }
212 else
213 {
214 prefixDisp = QString("<Prefix = %1>").arg(m_user.getPrefix());
215 ui->prefixLabel->setStyleSheet("QLabel {color: Green; font-size: 12px; font: bold \"Verdana\";}");
216 }
217 ui->prefixLabel->setText(prefixDisp);
218}
Yingdi Yueda39aa2013-10-23 23:07:29 -0700219
Yingdi Yu7989eb22013-10-31 17:38:22 -0700220void
Yingdi Yu76dd8002013-12-24 11:16:32 +0800221ChatDialog::sendInterest(const ndn::Interest& interest,
222 const ndn::OnVerified& onVerified,
223 const ndn::OnVerifyFailed& onVerifyFailed,
224 const OnEventualTimeout& timeoutNotify,
225 const ndn::ptr_lib::shared_ptr<ndn::PolicyManager>& policyManager,
226 int retry /* = 1 */,
227 int stepCount /* = 0 */)
228{
229 m_face->expressInterest(interest,
230 boost::bind(&ChatDialog::onTargetData,
231 this,
232 _1,
233 _2,
234 stepCount,
235 onVerified,
236 onVerifyFailed,
237 timeoutNotify,
238 policyManager),
239 boost::bind(&ChatDialog::onTargetTimeout,
240 this,
241 _1,
242 retry,
243 stepCount,
244 onVerified,
245 onVerifyFailed,
246 timeoutNotify,
247 policyManager));
248}
249
250void
251ChatDialog::onTargetData(const ndn::ptr_lib::shared_ptr<const ndn::Interest>& interest,
252 const ndn::ptr_lib::shared_ptr<ndn::Data>& data,
253 int stepCount,
254 const ndn::OnVerified& onVerified,
255 const ndn::OnVerifyFailed& onVerifyFailed,
256 const OnEventualTimeout& timeoutNotify,
257 const ndn::ptr_lib::shared_ptr<ndn::PolicyManager>& policyManager)
258{
259 ndn::ptr_lib::shared_ptr<ndn::ValidationRequest> nextStep = policyManager->checkVerificationPolicy(data, stepCount, onVerified, onVerifyFailed);
260
261 if (nextStep)
262 m_face->expressInterest
263 (*nextStep->interest_,
264 boost::bind(&ChatDialog::onCertData, this, _1, _2, nextStep, policyManager),
265 boost::bind(&ChatDialog::onCertTimeout, this, _1, onVerifyFailed, data, nextStep, policyManager));
266}
267
268void
269ChatDialog::onTargetTimeout(const ndn::ptr_lib::shared_ptr<const ndn::Interest>& interest,
270 int retry,
271 int stepCount,
272 const ndn::OnVerified& onVerified,
273 const ndn::OnVerifyFailed& onVerifyFailed,
274 const OnEventualTimeout& timeoutNotify,
275 const ndn::ptr_lib::shared_ptr<ndn::PolicyManager>& policyManager)
276{
277 if(retry > 0)
278 sendInterest(*interest, onVerified, onVerifyFailed, timeoutNotify, policyManager, retry-1, stepCount);
279 else
280 {
281 _LOG_DEBUG("Interest: " << interest->getName().toUri() << " eventually times out!");
282 timeoutNotify();
283 }
284}
285
286void
287ChatDialog::onCertData(const ndn::ptr_lib::shared_ptr<const ndn::Interest>& interest,
288 const ndn::ptr_lib::shared_ptr<ndn::Data>& cert,
289 ndn::ptr_lib::shared_ptr<ndn::ValidationRequest> previousStep,
290 const ndn::ptr_lib::shared_ptr<ndn::PolicyManager>& policyManager)
291{
292 ndn::ptr_lib::shared_ptr<ndn::ValidationRequest> nextStep = policyManager->checkVerificationPolicy(cert,
293 previousStep->stepCount_,
294 previousStep->onVerified_,
295 previousStep->onVerifyFailed_);
296
297 if (nextStep)
298 m_face->expressInterest
299 (*nextStep->interest_,
300 boost::bind(&ChatDialog::onCertData, this, _1, _2, nextStep, policyManager),
301 boost::bind(&ChatDialog::onCertTimeout, this, _1, previousStep->onVerifyFailed_, cert, nextStep, policyManager));
302}
303
304void
305ChatDialog::onCertTimeout(const ndn::ptr_lib::shared_ptr<const ndn::Interest>& interest,
306 const ndn::OnVerifyFailed& onVerifyFailed,
307 const ndn::ptr_lib::shared_ptr<ndn::Data>& data,
308 ndn::ptr_lib::shared_ptr<ndn::ValidationRequest> nextStep,
309 const ndn::ptr_lib::shared_ptr<ndn::PolicyManager>& policyManager)
310{
311 if(nextStep->retry_ > 0)
312 m_face->expressInterest(*interest,
313 boost::bind(&ChatDialog::onCertData,
314 this,
315 _1,
316 _2,
317 nextStep,
318 policyManager),
319 boost::bind(&ChatDialog::onCertTimeout,
320 this,
321 _1,
322 onVerifyFailed,
323 data,
324 nextStep,
325 policyManager));
326 else
327 onVerifyFailed(data);
328}
329
330void
331ChatDialog::sendInvitation(ndn::ptr_lib::shared_ptr<ContactItem> contact, bool isIntroducer)
Yingdi Yu7989eb22013-10-31 17:38:22 -0700332{
333 m_invitationPolicyManager->addTrustAnchor(contact->getSelfEndorseCertificate());
334
Yingdi Yuf8f572d2014-01-13 11:19:47 -0800335 ndn::Name certificateName = m_keyChain->getDefaultCertificateNameForIdentity(m_defaultIdentity);
Yingdi Yu7989eb22013-10-31 17:38:22 -0700336
337 ndn::Name interestName("/ndn/broadcast/chronos/invitation");
Yingdi Yueda39aa2013-10-23 23:07:29 -0700338 interestName.append(contact->getNameSpace());
339 interestName.append("chatroom");
340 interestName.append(m_chatroomPrefix.get(-1));
341 interestName.append("inviter-prefix");
342 interestName.append(m_localPrefix);
343 interestName.append("inviter");
344 interestName.append(certificateName);
345
346 string signedUri = interestName.toUri();
Yingdi Yueda39aa2013-10-23 23:07:29 -0700347
Yingdi Yuf8f572d2014-01-13 11:19:47 -0800348 ndn::Signature sig = m_keyChain->sign(reinterpret_cast<const uint8_t*>(signedUri.c_str()), signedUri.size(), certificateName);
349 const ndn::Block& sigValue = sig.getValue();
Yingdi Yueda39aa2013-10-23 23:07:29 -0700350
Yingdi Yuf8f572d2014-01-13 11:19:47 -0800351 interestName.append(sigValue);
Yingdi Yu6eabbd72013-12-27 08:44:12 +0800352
Yingdi Yu76dd8002013-12-24 11:16:32 +0800353 //TODO... remove version from invitation interest
354 // interestName.appendVersion();
Yingdi Yu46948282013-11-06 18:43:31 -0800355
Yingdi Yu76dd8002013-12-24 11:16:32 +0800356 ndn::Interest interest(interestName);
357 ndn::OnVerified onVerified = boost::bind(&ChatDialog::onInviteReplyVerified,
358 this,
359 _1,
360 contact->getNameSpace(),
361 isIntroducer);
Yingdi Yueda39aa2013-10-23 23:07:29 -0700362
Yingdi Yu76dd8002013-12-24 11:16:32 +0800363 ndn::OnVerifyFailed onVerifyFailed = boost::bind(&ChatDialog::onInviteReplyVerifyFailed,
364 this,
365 _1,
366 contact->getNameSpace());
367
368 OnEventualTimeout timeoutNotify = boost::bind(&ChatDialog::onInviteReplyTimeout,
369 this,
370 contact->getNameSpace());
371
372
373 sendInterest(interest, onVerified, onVerifyFailed, timeoutNotify, m_invitationPolicyManager);
374}
375
376void
377ChatDialog::onInviteReplyVerified(const ndn::ptr_lib::shared_ptr<ndn::Data>& data,
378 const ndn::Name& identity,
379 bool isIntroducer)
380{
Yingdi Yuf8f572d2014-01-13 11:19:47 -0800381 string content(reinterpret_cast<const char*>(data->getContent().value()), data->getContent().value_size());
Yingdi Yu76dd8002013-12-24 11:16:32 +0800382 if(content == string("nack"))
383 invitationRejected(identity);
384 else
385 invitationAccepted(identity, data, content, isIntroducer);
Yingdi Yueda39aa2013-10-23 23:07:29 -0700386}
387
388void
Yingdi Yu76dd8002013-12-24 11:16:32 +0800389ChatDialog::onInviteReplyVerifyFailed(const ndn::ptr_lib::shared_ptr<ndn::Data>& data,
390 const ndn::Name& identity)
Yingdi Yueda39aa2013-10-23 23:07:29 -0700391{
Yingdi Yu76dd8002013-12-24 11:16:32 +0800392 _LOG_DEBUG("Reply from " << identity.toUri() << " cannot be verified!");
393 QString msg = QString::fromUtf8("Reply from ") + QString::fromStdString(identity.toUri()) + " cannot be verified!";
394 emit inivationRejection(msg);
395}
396
397
398void
399ChatDialog::onInviteReplyTimeout(const ndn::Name& identity)
400{
401 _LOG_DEBUG("Your invitation to " << identity.toUri() << " times out!");
402 QString msg = QString::fromUtf8("Your invitation to ") + QString::fromStdString(identity.toUri()) + " times out!";
403 emit inivationRejection(msg);
Yingdi Yueda39aa2013-10-23 23:07:29 -0700404}
405
406void
Yingdi Yu7989eb22013-10-31 17:38:22 -0700407ChatDialog::invitationRejected(const ndn::Name& identity)
408{
Yingdi Yu72781e52013-11-06 23:00:21 -0800409 _LOG_DEBUG(" " << identity.toUri() << " Rejected your invitation!");
Yingdi Yu0aca2652013-11-10 10:47:44 -0800410 QString msg = QString::fromStdString(identity.toUri()) + " Rejected your invitation!";
411 emit inivationRejection(msg);
Yingdi Yu7989eb22013-10-31 17:38:22 -0700412}
413
414void
Yingdi Yu76dd8002013-12-24 11:16:32 +0800415ChatDialog::invitationAccepted(const ndn::Name& identity, ndn::ptr_lib::shared_ptr<ndn::Data> data, const string& inviteePrefix, bool isIntroducer)
Yingdi Yueda39aa2013-10-23 23:07:29 -0700416{
Yingdi Yu72781e52013-11-06 23:00:21 -0800417 _LOG_DEBUG(" " << identity.toUri() << " Accepted your invitation!");
Yingdi Yuf8f572d2014-01-13 11:19:47 -0800418 ndn::SignatureSha256WithRsa sig(data->getSignature());
419 const ndn::Name & keyLocatorName = sig.getKeyLocator().getName();
Yingdi Yu76dd8002013-12-24 11:16:32 +0800420 ndn::ptr_lib::shared_ptr<ndn::IdentityCertificate> dskCertificate = m_invitationPolicyManager->getValidatedDskCertificate(keyLocatorName);
Yingdi Yue6476cd2013-11-06 18:51:19 -0800421 m_syncPolicyManager->addChatDataRule(inviteePrefix, *dskCertificate, isIntroducer);
Yingdi Yu83eae842013-11-06 22:07:38 -0800422 publishIntroCert(*dskCertificate, isIntroducer);
Yingdi Yueda39aa2013-10-23 23:07:29 -0700423}
424
Yingdi Yu76dd8002013-12-24 11:16:32 +0800425void
426ChatDialog::publishIntroCert(const ndn::IdentityCertificate& dskCertificate, bool isIntroducer)
Yingdi Yueda39aa2013-10-23 23:07:29 -0700427{
Yingdi Yu76dd8002013-12-24 11:16:32 +0800428 SyncIntroCertificate syncIntroCertificate(m_chatroomPrefix,
429 dskCertificate.getPublicKeyName(),
Yingdi Yuf8f572d2014-01-13 11:19:47 -0800430 m_keyChain->getDefaultKeyNameForIdentity(m_defaultIdentity),
Yingdi Yu76dd8002013-12-24 11:16:32 +0800431 dskCertificate.getNotBefore(),
432 dskCertificate.getNotAfter(),
433 dskCertificate.getPublicKeyInfo(),
434 (isIntroducer ? SyncIntroCertificate::INTRODUCER : SyncIntroCertificate::PRODUCER));
Yingdi Yuf8f572d2014-01-13 11:19:47 -0800435 ndn::Name certName = m_keyChain->getDefaultCertificateNameForIdentity(m_defaultIdentity);
Yingdi Yu76dd8002013-12-24 11:16:32 +0800436 _LOG_DEBUG("Publish Intro Certificate: " << syncIntroCertificate.getName());
Yingdi Yuf8f572d2014-01-13 11:19:47 -0800437 m_keyChain->sign(syncIntroCertificate, certName);
438 m_face->put(syncIntroCertificate);
Yingdi Yueda39aa2013-10-23 23:07:29 -0700439}
440
Yingdi Yu76dd8002013-12-24 11:16:32 +0800441void
442ChatDialog::addTrustAnchor(const EndorseCertificate& selfEndorseCertificate)
443{ m_invitationPolicyManager->addTrustAnchor(selfEndorseCertificate); }
444
445void
446ChatDialog::addChatDataRule(const ndn::Name& prefix,
447 const ndn::IdentityCertificate& identityCertificate,
448 bool isIntroducer)
449{ m_syncPolicyManager->addChatDataRule(prefix, identityCertificate, isIntroducer); }
450
Yingdi Yueda39aa2013-10-23 23:07:29 -0700451
Yingdi Yu46948282013-11-06 18:43:31 -0800452
453void
Yingdi Yu7989eb22013-10-31 17:38:22 -0700454ChatDialog::initializeSync()
455{
456
457 m_sock = new Sync::SyncSocket(m_chatroomPrefix.toUri(),
458 m_syncPolicyManager,
Yingdi Yu6eabbd72013-12-27 08:44:12 +0800459 m_face,
Yingdi Yu76dd8002013-12-24 11:16:32 +0800460 boost::bind(&ChatDialog::processTreeUpdateWrapper, this, _1, _2),
461 boost::bind(&ChatDialog::processRemoveWrapper, this, _1));
Yingdi Yu7989eb22013-10-31 17:38:22 -0700462
463 usleep(100000);
464
465 QTimer::singleShot(600, this, SLOT(sendJoin()));
466 m_timer->start(FRESHNESS * 1000);
467 disableTreeDisplay();
468 QTimer::singleShot(2200, this, SLOT(enableTreeDisplay()));
469 // Sync::CcnxWrapperPtr handle = boost::make_shared<Sync::CcnxWrapper> ();
470 // handle->setInterestFilter(m_user.getPrefix().toStdString(), bind(&ChatDialog::respondHistoryRequest, this, _1));
Yingdi Yu7989eb22013-10-31 17:38:22 -0700471}
472
473void
474ChatDialog::returnPressed()
475{
476 QString text = ui->lineEdit->text();
477 if (text.isEmpty())
478 return;
479
480 ui->lineEdit->clear();
481
482 if (text.startsWith("boruoboluomi"))
483 {
484 summonReaper ();
485 // reapButton->show();
486 fitView();
487 return;
488 }
489
490 if (text.startsWith("minimanihong"))
491 {
492 // reapButton->hide();
493 fitView();
494 return;
495 }
496
497 SyncDemo::ChatMessage msg;
498 formChatMessage(text, msg);
499
500 appendMessage(msg);
501
502 sendMsg(msg);
503
504 fitView();
505}
506
507void
508ChatDialog::treeButtonPressed()
509{
510 if (ui->treeViewer->isVisible())
511 {
512 ui->treeViewer->hide();
513 ui->treeButton->setText("Show ChronoSync Tree");
514 }
515 else
516 {
517 ui->treeViewer->show();
518 ui->treeButton->setText("Hide ChronoSync Tree");
519 }
520
521 fitView();
522}
523
524void ChatDialog::disableTreeDisplay()
525{
526 ui->treeButton->setEnabled(false);
527 ui->treeViewer->hide();
528 fitView();
529}
530
531void ChatDialog::enableTreeDisplay()
532{
533 ui->treeButton->setEnabled(true);
534 // treeViewer->show();
535 // fitView();
536}
537
538void
539ChatDialog::processTreeUpdateWrapper(const std::vector<Sync::MissingDataInfo> v, Sync::SyncSocket *sock)
540{
541 emit treeUpdated(v);
542 _LOG_DEBUG("<<< Tree update signal emitted");
543}
544
545void
546ChatDialog::processRemoveWrapper(std::string prefix)
547{
548 _LOG_DEBUG("Sync REMOVE signal received for prefix: " << prefix);
549}
550
551void
552ChatDialog::processTreeUpdate(const std::vector<Sync::MissingDataInfo> v)
553{
554 _LOG_DEBUG("<<< processing Tree Update");
555
556 if (v.empty())
557 {
558 return;
559 }
560
561 // reflect the changes on digest tree
562 {
563 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
564 m_scene->processUpdate(v, m_sock->getRootDigest().c_str());
565 }
566
567 int n = v.size();
568 int totalMissingPackets = 0;
569 for (int i = 0; i < n; i++)
570 {
571 totalMissingPackets += v[i].high.getSeq() - v[i].low.getSeq() + 1;
572 }
573
574 for (int i = 0; i < n; i++)
575 {
576 if (totalMissingPackets < 4)
577 {
578 for (Sync::SeqNo seq = v[i].low; seq <= v[i].high; ++seq)
579 {
580 m_sock->fetchData(v[i].prefix, seq, bind(&ChatDialog::processDataWrapper, this, _1), 2);
581 _LOG_DEBUG("<<< Fetching " << v[i].prefix << "/" <<seq.getSession() <<"/" << seq.getSeq());
582 }
583 }
584 else
585 {
586 m_sock->fetchData(v[i].prefix, v[i].high, bind(&ChatDialog::processDataNoShowWrapper, this, _1), 2);
587 }
588 }
589
590 // adjust the view
591 fitView();
592
593}
594
595void
Yingdi Yu76dd8002013-12-24 11:16:32 +0800596ChatDialog::processDataWrapper(const ndn::ptr_lib::shared_ptr<ndn::Data>& data)
Yingdi Yu7989eb22013-10-31 17:38:22 -0700597{
598 string name = data->getName().toUri();
Yingdi Yuf8f572d2014-01-13 11:19:47 -0800599 const char* buf = reinterpret_cast<const char*>(data->getContent().value());
600 size_t len = data->getContent().value_size();
Yingdi Yu7989eb22013-10-31 17:38:22 -0700601
602 char *tempBuf = new char[len];
603 memcpy(tempBuf, buf, len);
604 emit dataReceived(name.c_str(), tempBuf, len, true, false);
605 _LOG_DEBUG("<<< " << name << " fetched");
606}
607
608void
Yingdi Yu76dd8002013-12-24 11:16:32 +0800609ChatDialog::processDataNoShowWrapper(const ndn::ptr_lib::shared_ptr<ndn::Data>& data)
Yingdi Yu7989eb22013-10-31 17:38:22 -0700610{
611 string name = data->getName().toUri();
Yingdi Yuf8f572d2014-01-13 11:19:47 -0800612 const char* buf = reinterpret_cast<const char*>(data->getContent().value());
613 size_t len = data->getContent().value_size();
Yingdi Yu7989eb22013-10-31 17:38:22 -0700614
615 char *tempBuf = new char[len];
616 memcpy(tempBuf, buf, len);
617 emit dataReceived(name.c_str(), tempBuf, len, false, false);
618
619 // if (!m_historyInitialized)
620 // {
621 // fetchHistory(name);
622 // m_historyInitialized = true;
623 // }
624}
625
626// void
627// ChatDialog::fetchHistory(std::string name)
628// {
629
630// /****************************/
631// /* TODO: fix following part */
632// /****************************/
633// string nameWithoutSeq = name.substr(0, name.find_last_of('/'));
634// string prefix = nameWithoutSeq.substr(0, nameWithoutSeq.find_last_of('/'));
635// prefix += "/history";
636// // Ptr<Wrapper>CcnxWrapperPtr handle = boost::make_shared<Sync::CcnxWrapper> ();
637// // QString randomString = getRandomString();
638// // for (int i = 0; i < MAX_HISTORY_ENTRY; i++)
639// // {
640// // QString interest = QString("%1/%2/%3").arg(prefix.c_str()).arg(randomString).arg(i);
641// // handle->sendInterest(interest.toStdString(), bind(&ChatDialog::processDataHistoryWrapper, this, _1, _2, _3));
642// // }
643// }
644
645void
646ChatDialog::processData(QString name, const char *buf, size_t len, bool show, bool isHistory)
647{
648 SyncDemo::ChatMessage msg;
649 bool corrupted = false;
650 if (!msg.ParseFromArray(buf, len))
651 {
652 _LOG_DEBUG("Errrrr.. Can not parse msg with name: " << name.toStdString() << ". what is happening?");
653 // nasty stuff: as a remedy, we'll form some standard msg for inparsable msgs
654 msg.set_from("inconnu");
655 msg.set_type(SyncDemo::ChatMessage::OTHER);
656 corrupted = true;
657 }
658
659 delete [] buf;
660 buf = NULL;
661
662 // display msg received from network
663 // we have to do so; this function is called by ccnd thread
664 // so if we call appendMsg directly
665 // Qt crash as "QObject: Cannot create children for a parent that is in a different thread"
666 // the "cannonical" way to is use signal-slot
667 if (show && !corrupted)
668 {
669 appendMessage(msg, isHistory);
670 }
671
672 if (!isHistory)
673 {
674 // update the tree view
675 std::string stdStrName = name.toStdString();
676 std::string stdStrNameWithoutSeq = stdStrName.substr(0, stdStrName.find_last_of('/'));
677 std::string prefix = stdStrNameWithoutSeq.substr(0, stdStrNameWithoutSeq.find_last_of('/'));
678 _LOG_DEBUG("<<< updating scene for" << prefix << ": " << msg.from());
679 if (msg.type() == SyncDemo::ChatMessage::LEAVE)
680 {
681 processRemove(prefix.c_str());
682 }
683 else
684 {
685 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
686 m_scene->msgReceived(prefix.c_str(), msg.from().c_str());
687 }
688 }
689 fitView();
690}
691
692void
693ChatDialog::processRemove(QString prefix)
694{
695 _LOG_DEBUG("<<< remove node for prefix" << prefix.toStdString());
696
697 bool removed = m_scene->removeNode(prefix);
698 if (removed)
699 {
700 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
701 m_scene->plot(m_sock->getRootDigest().c_str());
702 }
703}
704
705void
706ChatDialog::sendJoin()
707{
708 m_joined = true;
709 SyncDemo::ChatMessage msg;
710 formControlMessage(msg, SyncDemo::ChatMessage::JOIN);
711 sendMsg(msg);
712 boost::random::random_device rng;
713 boost::random::uniform_int_distribution<> uniform(1, FRESHNESS / 5 * 1000);
714 m_randomizedInterval = HELLO_INTERVAL * 1000 + uniform(rng);
715 QTimer::singleShot(m_randomizedInterval, this, SLOT(sendHello()));
716}
717
718void
719ChatDialog::sendHello()
720{
721 time_t now = time(NULL);
722 int elapsed = now - m_lastMsgTime;
723 if (elapsed >= m_randomizedInterval / 1000)
724 {
725 SyncDemo::ChatMessage msg;
726 formControlMessage(msg, SyncDemo::ChatMessage::HELLO);
727 sendMsg(msg);
728 boost::random::random_device rng;
729 boost::random::uniform_int_distribution<> uniform(1, FRESHNESS / 5 * 1000);
730 m_randomizedInterval = HELLO_INTERVAL * 1000 + uniform(rng);
731 QTimer::singleShot(m_randomizedInterval, this, SLOT(sendHello()));
732 }
733 else
734 {
735 QTimer::singleShot((m_randomizedInterval - elapsed * 1000), this, SLOT(sendHello()));
736 }
737}
738
739void
740ChatDialog::sendLeave()
741{
742 SyncDemo::ChatMessage msg;
743 formControlMessage(msg, SyncDemo::ChatMessage::LEAVE);
744 sendMsg(msg);
745 usleep(500000);
746 m_sock->remove(m_user.getPrefix().toStdString());
747 usleep(5000);
748 m_joined = false;
749 _LOG_DEBUG("Sync REMOVE signal sent");
750}
751
752void
753ChatDialog::replot()
754{
755 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
756 m_scene->plot(m_sock->getRootDigest().c_str());
757 fitView();
758}
759
760void
761ChatDialog::summonReaper()
762{
763 Sync::SyncLogic &logic = m_sock->getLogic ();
764 map<string, bool> branches = logic.getBranchPrefixes();
765 QMap<QString, DisplayUserPtr> roster = m_scene->getRosterFull();
766
767 m_zombieList.clear();
768
769 QMapIterator<QString, DisplayUserPtr> it(roster);
770 map<string, bool>::iterator mapIt;
771 while(it.hasNext())
772 {
773 it.next();
774 DisplayUserPtr p = it.value();
775 if (p != DisplayUserNullPtr)
776 {
777 mapIt = branches.find(p->getPrefix().toStdString());
778 if (mapIt != branches.end())
779 {
780 mapIt->second = true;
781 }
782 }
783 }
784
785 for (mapIt = branches.begin(); mapIt != branches.end(); ++mapIt)
786 {
787 // this is zombie. all active users should have been marked true
788 if (! mapIt->second)
789 {
790 m_zombieList.append(mapIt->first.c_str());
791 }
792 }
793
794 m_zombieIndex = 0;
795
796 // start reaping
797 reap();
798}
799
800void
801ChatDialog::reap()
802{
803 if (m_zombieIndex < m_zombieList.size())
804 {
805 string prefix = m_zombieList.at(m_zombieIndex).toStdString();
806 m_sock->remove(prefix);
807 _LOG_DEBUG("Reaped: prefix = " << prefix);
808 m_zombieIndex++;
809 // reap again in 10 seconds
810 QTimer::singleShot(10000, this, SLOT(reap()));
811 }
812}
813
814void
815ChatDialog::updateRosterList(QStringList staleUserList)
816{
817 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
818 QStringList rosterList = m_scene->getRosterList();
819 m_rosterModel->setStringList(rosterList);
820 QString user;
821 QStringListIterator it(staleUserList);
822 while(it.hasNext())
823 {
824 std::string nick = it.next().toStdString();
825 if (nick.empty())
826 continue;
827
828 SyncDemo::ChatMessage msg;
829 formControlMessage(msg, SyncDemo::ChatMessage::LEAVE);
830 msg.set_from(nick);
831 appendMessage(msg);
832 }
833}
834
835void
Yingdi Yufdb8ab82013-11-10 01:38:21 -0800836ChatDialog::settingUpdated(QString nick, QString chatroom, QString originPrefix)
837{
Yingdi Yu1ecf81f2013-11-10 12:25:43 -0800838 _LOG_DEBUG("called");
Yingdi Yufdb8ab82013-11-10 01:38:21 -0800839 QString randString = getRandomString();
840 bool needWrite = false;
841 bool needFresh = false;
842
843 QString oldPrefix = m_user.getPrefix();
844 if (!originPrefix.isEmpty() && originPrefix != m_user.getOriginPrefix()) {
845 m_user.setOriginPrefix(originPrefix);
846
847 m_localPrefix = ndn::Name(originPrefix.toStdString());
848 m_localChatPrefix = m_localPrefix;
849 m_localChatPrefix.append("%F0.").append(m_defaultIdentity);
850 m_localChatPrefix.append("chronos").append(m_chatroomPrefix.get(-1)).append(randString.toStdString());
851 m_user.setPrefix(QString::fromStdString(m_localChatPrefix.toUri()));
852 m_scene->setCurrentPrefix(QString::fromStdString(m_localChatPrefix.toUri()));
853 needWrite = true;
854 needFresh = true;
855 }
856
857 if (needWrite) {
858 updateLabels();
859 }
860
861 if (needFresh && m_sock != NULL)
862 {
863
864 {
865 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
866 m_scene->clearAll();
867 m_scene->plot("Empty");
868 }
869
Yingdi Yua66183f2013-11-10 10:32:18 -0800870 ui->textEdit->clear();
Yingdi Yufdb8ab82013-11-10 01:38:21 -0800871
872 // keep the new prefix
873 QString newPrefix = m_user.getPrefix();
874 // send leave for the old
875 m_user.setPrefix(oldPrefix);
876 // there is no point to send leave if we haven't joined yet
877 if (m_joined)
878 {
879 sendLeave();
880 }
881 // resume new prefix
882 m_user.setPrefix(newPrefix);
883 // Sync::CcnxWrapperPtr handle = Sync::CcnxWrapper::Create();
884 // handle->clearInterestFilter(oldPrefix.toStdString());
885 delete m_sock;
886 m_sock = NULL;
887
888 try
889 {
890 usleep(100000);
891 m_sock = new Sync::SyncSocket(m_chatroomPrefix.toUri(),
892 m_syncPolicyManager,
Yingdi Yu6eabbd72013-12-27 08:44:12 +0800893 m_face,
Yingdi Yufdb8ab82013-11-10 01:38:21 -0800894 bind(&ChatDialog::processTreeUpdateWrapper, this, _1, _2),
895 bind(&ChatDialog::processRemoveWrapper, this, _1));
896 usleep(100000);
897 // Sync::CcnxWrapperPtr handle = boost::make_shared<Sync::CcnxWrapper> ();
898 // handle->setInterestFilter(m_user.getPrefix().toStdString(), bind(&ChatDialog::respondHistoryRequest, this, _1));
Yingdi Yua66183f2013-11-10 10:32:18 -0800899 QTimer::singleShot(600, this, SLOT(sendJoin()));
Yingdi Yufdb8ab82013-11-10 01:38:21 -0800900 m_timer->start(FRESHNESS * 1000);
901 disableTreeDisplay();
Yingdi Yua66183f2013-11-10 10:32:18 -0800902 QTimer::singleShot(2200, this, SLOT(enableTreeDisplay()));
Yingdi Yu76dd8002013-12-24 11:16:32 +0800903 }catch(std::exception& e){
Yingdi Yufdb8ab82013-11-10 01:38:21 -0800904 emit noNdnConnection(QString::fromStdString("Cannot conect to ndnd!\n Have you started your ndnd?"));
905 }
906 }
907 else if (needFresh && m_sock == NULL)
908 {
909 initializeSync();
910 }
911 else if (m_sock == NULL)
912 {
913 initializeSync();
914 }
915 else
916 {
917// #ifdef __DEBUG
918// std::cout << "Just changing nicks, we're good. " << std::endl;
919// #endif
920 }
921
922 fitView();
923}
924
925void
Yingdi Yu83eae842013-11-06 22:07:38 -0800926ChatDialog::iconActivated(QSystemTrayIcon::ActivationReason reason)
927{
928 switch (reason)
929 {
930 case QSystemTrayIcon::Trigger:
931 case QSystemTrayIcon::DoubleClick:
932 break;
933 case QSystemTrayIcon::MiddleClick:
934 // showMessage();
935 break;
936 default:;
937 }
938}
939
940
941void
942ChatDialog::messageClicked()
943{
944 this->showMaximized();
945}
946
947
948void
949ChatDialog::createActions()
950{
Yingdi Yu702d6f12013-11-07 17:00:54 -0800951 minimizeAction = new QAction(tr("Mi&nimize"), this);
952 connect(minimizeAction, SIGNAL(triggered()), this, SLOT(hide()));
Yingdi Yu83eae842013-11-06 22:07:38 -0800953
Yingdi Yu702d6f12013-11-07 17:00:54 -0800954 maximizeAction = new QAction(tr("Ma&ximize"), this);
955 connect(maximizeAction, SIGNAL(triggered()), this, SLOT(showMaximized()));
Yingdi Yu83eae842013-11-06 22:07:38 -0800956
Yingdi Yu702d6f12013-11-07 17:00:54 -0800957 restoreAction = new QAction(tr("&Restore"), this);
958 connect(restoreAction, SIGNAL(triggered()), this, SLOT(showNormal()));
Yingdi Yu83eae842013-11-06 22:07:38 -0800959
960 // settingsAction = new QAction(tr("Settings"), this);
961 // connect (settingsAction, SIGNAL(triggered()), this, SLOT(buttonPressed()));
962
963 // settingsAction->setMenuRole (QAction::PreferencesRole);
964
Yingdi Yufdb8ab82013-11-10 01:38:21 -0800965 updateLocalPrefixAction = new QAction(tr("Update local prefix"), this);
966 connect (updateLocalPrefixAction, SIGNAL(triggered()), this, SLOT(updateLocalPrefix()));
Yingdi Yu83eae842013-11-06 22:07:38 -0800967
Yingdi Yu702d6f12013-11-07 17:00:54 -0800968 quitAction = new QAction(tr("Quit"), this);
969 connect(quitAction, SIGNAL(triggered()), this, SLOT(quit()));
Yingdi Yu83eae842013-11-06 22:07:38 -0800970}
971
972void
973ChatDialog::createTrayIcon()
974{
Yingdi Yu702d6f12013-11-07 17:00:54 -0800975 trayIconMenu = new QMenu(this);
976 trayIconMenu->addAction(minimizeAction);
977 trayIconMenu->addAction(maximizeAction);
978 trayIconMenu->addAction(restoreAction);
Yingdi Yu83eae842013-11-06 22:07:38 -0800979 // trayIconMenu->addSeparator();
980 // trayIconMenu->addAction(settingsAction);
Yingdi Yufdb8ab82013-11-10 01:38:21 -0800981 trayIconMenu->addSeparator();
982 trayIconMenu->addAction(updateLocalPrefixAction);
Yingdi Yu702d6f12013-11-07 17:00:54 -0800983 trayIconMenu->addSeparator();
984 trayIconMenu->addAction(quitAction);
Yingdi Yu83eae842013-11-06 22:07:38 -0800985
986 trayIcon = new QSystemTrayIcon(this);
Yingdi Yu702d6f12013-11-07 17:00:54 -0800987 trayIcon->setContextMenu(trayIconMenu);
Yingdi Yu83eae842013-11-06 22:07:38 -0800988
989 QIcon icon(":/images/icon_small.png");
990 trayIcon->setIcon(icon);
991 setWindowIcon(icon);
992 trayIcon->setToolTip("ChronoChat System Tray Icon");
993 trayIcon->setVisible(true);
Yingdi Yu83eae842013-11-06 22:07:38 -0800994}
995
996
997void
Yingdi Yu7989eb22013-10-31 17:38:22 -0700998ChatDialog::resizeEvent(QResizeEvent *e)
999{
1000 fitView();
1001}
1002
1003void
1004ChatDialog::showEvent(QShowEvent *e)
1005{
1006 fitView();
1007}
1008
1009void
1010ChatDialog::fitView()
1011{
1012 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
1013 QRectF rect = m_scene->itemsBoundingRect();
1014 m_scene->setSceneRect(rect);
1015 ui->treeViewer->fitInView(m_scene->itemsBoundingRect(), Qt::KeepAspectRatio);
1016}
1017
1018void
1019ChatDialog::formChatMessage(const QString &text, SyncDemo::ChatMessage &msg) {
1020 msg.set_from(m_user.getNick().toStdString());
1021 msg.set_to(m_user.getChatroom().toStdString());
1022 msg.set_data(text.toUtf8().constData());
1023 time_t seconds = time(NULL);
1024 msg.set_timestamp(seconds);
1025 msg.set_type(SyncDemo::ChatMessage::CHAT);
1026}
1027
1028void
1029ChatDialog::formControlMessage(SyncDemo::ChatMessage &msg, SyncDemo::ChatMessage::ChatMessageType type)
1030{
1031 msg.set_from(m_user.getNick().toStdString());
1032 msg.set_to(m_user.getChatroom().toStdString());
1033 time_t seconds = time(NULL);
1034 msg.set_timestamp(seconds);
1035 msg.set_type(type);
1036}
1037
1038void
Yingdi Yufdb8ab82013-11-10 01:38:21 -08001039ChatDialog::updateLocalPrefix()
1040{
Yingdi Yua66183f2013-11-10 10:32:18 -08001041 m_newLocalPrefixReady = false;
Yingdi Yu76dd8002013-12-24 11:16:32 +08001042 ndn::Name interestName("/local/ndn/prefix");
1043 ndn::Interest interest(interestName);
Yingdi Yuf8f572d2014-01-13 11:19:47 -08001044 interest.setInterestLifetime(1000);
Yingdi Yufdb8ab82013-11-10 01:38:21 -08001045
Yingdi Yu76dd8002013-12-24 11:16:32 +08001046 m_face->expressInterest(interest,
1047 bind(&ChatDialog::onLocalPrefix, this, _1, _2),
1048 bind(&ChatDialog::onLocalPrefixTimeout, this, _1));
Yingdi Yufdb8ab82013-11-10 01:38:21 -08001049
Yingdi Yua66183f2013-11-10 10:32:18 -08001050 while(m_newLocalPrefixReady == false)
1051 {
1052#if BOOST_VERSION >= 1050000
1053 boost::this_thread::sleep_for(boost::chrono::milliseconds(100));
1054#else
1055 boost::this_thread::sleep(boost::posix_time::milliseconds(100));
1056#endif
1057 }
Yingdi Yu1ecf81f2013-11-10 12:25:43 -08001058 _LOG_DEBUG("now the prefix is " << m_newLocalPrefix.toUri());
Yingdi Yuaf305d72013-11-10 11:54:02 -08001059 _LOG_DEBUG("in use prefix is " << m_user.getOriginPrefix().toStdString());
Yingdi Yua66183f2013-11-10 10:32:18 -08001060 QString originPrefix = QString::fromStdString(m_newLocalPrefix.toUri());
1061
1062 if (originPrefix != "" && m_user.getOriginPrefix () != originPrefix)
1063 emit settingUpdated(m_user.getNick (), m_user.getChatroom (), originPrefix);
Yingdi Yufdb8ab82013-11-10 01:38:21 -08001064}
1065
Yingdi Yu76dd8002013-12-24 11:16:32 +08001066
1067void
1068ChatDialog::onLocalPrefix(const ndn::ptr_lib::shared_ptr<const ndn::Interest>& interest,
1069 const ndn::ptr_lib::shared_ptr<ndn::Data>& data)
1070{
Yingdi Yuf8f572d2014-01-13 11:19:47 -08001071 string dataString(reinterpret_cast<const char*>(data->getContent().value()), data->getContent().value_size());
Yingdi Yu76dd8002013-12-24 11:16:32 +08001072 QString originPrefix = QString::fromStdString (dataString).trimmed ();
1073 string trimmedString = originPrefix.toStdString();
1074 m_newLocalPrefix = ndn::Name(trimmedString);
1075 m_newLocalPrefixReady = true;
1076}
1077
1078void
1079ChatDialog::onLocalPrefixTimeout(const ndn::ptr_lib::shared_ptr<const ndn::Interest>& interest)
1080{
1081 m_newLocalPrefix = m_localPrefix;
1082 m_newLocalPrefixReady = true;
1083}
1084
Yingdi Yufdb8ab82013-11-10 01:38:21 -08001085static std::string chars2("qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM0123456789");
1086
1087QString
1088ChatDialog::getRandomString()
1089{
1090 std::string randStr;
1091 boost::random::random_device rng;
1092 boost::random::uniform_int_distribution<> index_dist(0, chars2.size() - 1);
1093 for (int i = 0; i < 10; i ++)
1094 {
1095 randStr += chars2[index_dist(rng)];
1096 }
1097 return randStr.c_str();
1098}
1099
1100void
Yingdi Yu83eae842013-11-06 22:07:38 -08001101ChatDialog::changeEvent(QEvent *e)
1102{
1103 switch(e->type())
1104 {
1105 case QEvent::ActivationChange:
1106 if (isActiveWindow())
1107 {
1108 trayIcon->setIcon(QIcon(":/images/icon_small.png"));
1109 }
1110 break;
1111 default:
1112 break;
1113 }
1114}
1115
1116void
Yingdi Yu7989eb22013-10-31 17:38:22 -07001117ChatDialog::appendMessage(const SyncDemo::ChatMessage msg, bool isHistory)
1118{
1119 boost::recursive_mutex::scoped_lock lock(m_msgMutex);
1120
1121 if (msg.type() == SyncDemo::ChatMessage::CHAT)
1122 {
1123
1124 if (!msg.has_data())
1125 {
1126 return;
1127 }
1128
1129 if (msg.from().empty() || msg.data().empty())
1130 {
1131 return;
1132 }
1133
1134 if (!msg.has_timestamp())
1135 {
1136 return;
1137 }
1138
1139 // if (m_history.size() == MAX_HISTORY_ENTRY)
1140 // {
1141 // m_history.dequeue();
1142 // }
1143
1144 // m_history.enqueue(msg);
1145
1146 QTextCharFormat nickFormat;
1147 nickFormat.setForeground(Qt::darkGreen);
1148 nickFormat.setFontWeight(QFont::Bold);
1149 nickFormat.setFontUnderline(true);
1150 nickFormat.setUnderlineColor(Qt::gray);
1151
1152 QTextCursor cursor(ui->textEdit->textCursor());
1153 cursor.movePosition(QTextCursor::End);
1154 QTextTableFormat tableFormat;
1155 tableFormat.setBorder(0);
1156 QTextTable *table = cursor.insertTable(1, 2, tableFormat);
1157 QString from = QString("%1 ").arg(msg.from().c_str());
1158 QTextTableCell fromCell = table->cellAt(0, 0);
1159 fromCell.setFormat(nickFormat);
1160 fromCell.firstCursorPosition().insertText(from);
1161
1162 time_t timestamp = msg.timestamp();
1163 printTimeInCell(table, timestamp);
1164
1165 QTextCursor nextCursor(ui->textEdit->textCursor());
1166 nextCursor.movePosition(QTextCursor::End);
1167 table = nextCursor.insertTable(1, 1, tableFormat);
1168 table->cellAt(0, 0).firstCursorPosition().insertText(QString::fromUtf8(msg.data().c_str()));
1169 if (!isHistory)
1170 {
1171 showMessage(from, QString::fromUtf8(msg.data().c_str()));
1172 }
1173 }
1174
1175 if (msg.type() == SyncDemo::ChatMessage::JOIN || msg.type() == SyncDemo::ChatMessage::LEAVE)
1176 {
1177 QTextCharFormat nickFormat;
1178 nickFormat.setForeground(Qt::gray);
1179 nickFormat.setFontWeight(QFont::Bold);
1180 nickFormat.setFontUnderline(true);
1181 nickFormat.setUnderlineColor(Qt::gray);
1182
1183 QTextCursor cursor(ui->textEdit->textCursor());
1184 cursor.movePosition(QTextCursor::End);
1185 QTextTableFormat tableFormat;
1186 tableFormat.setBorder(0);
1187 QTextTable *table = cursor.insertTable(1, 2, tableFormat);
1188 QString action;
1189 if (msg.type() == SyncDemo::ChatMessage::JOIN)
1190 {
1191 action = "enters room";
1192 }
1193 else
1194 {
1195 action = "leaves room";
1196 }
1197
1198 QString from = QString("%1 %2 ").arg(msg.from().c_str()).arg(action);
1199 QTextTableCell fromCell = table->cellAt(0, 0);
1200 fromCell.setFormat(nickFormat);
1201 fromCell.firstCursorPosition().insertText(from);
1202
1203 time_t timestamp = msg.timestamp();
1204 printTimeInCell(table, timestamp);
1205 }
1206
1207 QScrollBar *bar = ui->textEdit->verticalScrollBar();
1208 bar->setValue(bar->maximum());
1209}
1210
1211QString
1212ChatDialog::formatTime(time_t timestamp)
1213{
1214 struct tm *tm_time = localtime(&timestamp);
1215 int hour = tm_time->tm_hour;
1216 QString amOrPM;
1217 if (hour > 12)
1218 {
1219 hour -= 12;
1220 amOrPM = "PM";
1221 }
1222 else
1223 {
1224 amOrPM = "AM";
1225 if (hour == 0)
1226 {
1227 hour = 12;
1228 }
1229 }
1230
1231 char textTime[12];
1232 sprintf(textTime, "%d:%02d:%02d %s", hour, tm_time->tm_min, tm_time->tm_sec, amOrPM.toStdString().c_str());
1233 return QString(textTime);
1234}
1235
1236void
1237ChatDialog::printTimeInCell(QTextTable *table, time_t timestamp)
1238{
1239 QTextCharFormat timeFormat;
1240 timeFormat.setForeground(Qt::gray);
1241 timeFormat.setFontUnderline(true);
1242 timeFormat.setUnderlineColor(Qt::gray);
1243 QTextTableCell timeCell = table->cellAt(0, 1);
1244 timeCell.setFormat(timeFormat);
1245 timeCell.firstCursorPosition().insertText(formatTime(timestamp));
1246}
1247
1248void
1249ChatDialog::showMessage(QString from, QString data)
1250{
1251 if (!isActiveWindow())
1252 {
Yingdi Yu83eae842013-11-06 22:07:38 -08001253 trayIcon->showMessage(QString("Chatroom %1 has a new message").arg(m_user.getChatroom()), QString("<%1>: %2").arg(from).arg(data), QSystemTrayIcon::Information, 20000);
1254 trayIcon->setIcon(QIcon(":/images/note.png"));
Yingdi Yu7989eb22013-10-31 17:38:22 -07001255 }
1256}
1257
1258void
1259ChatDialog::sendMsg(SyncDemo::ChatMessage &msg)
1260{
1261 // send msg
1262 size_t size = msg.ByteSize();
1263 char *buf = new char[size];
1264 msg.SerializeToArray(buf, size);
1265 if (!msg.IsInitialized())
1266 {
1267 _LOG_DEBUG("Errrrr.. msg was not probally initialized "<<__FILE__ <<":"<<__LINE__<<". what is happening?");
1268 abort();
1269 }
1270 m_sock->publishData(m_user.getPrefix().toStdString(), m_session, buf, size, FRESHNESS);
1271
1272 delete buf;
1273
1274 m_lastMsgTime = time(NULL);
1275
1276 int nextSequence = m_sock->getNextSeq(m_user.getPrefix().toStdString(), m_session);
1277 Sync::MissingDataInfo mdi = {m_user.getPrefix().toStdString(), Sync::SeqNo(0), Sync::SeqNo(nextSequence - 1)};
1278 std::vector<Sync::MissingDataInfo> v;
1279 v.push_back(mdi);
1280 {
1281 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
1282 m_scene->processUpdate(v, m_sock->getRootDigest().c_str());
1283 m_scene->msgReceived(m_user.getPrefix(), m_user.getNick());
1284 }
1285}
1286
1287void
1288ChatDialog::openInviteListDialog()
1289{
1290 m_inviteListDialog->setInviteLabel(m_chatroomPrefix.toUri());
1291 m_inviteListDialog->show();
1292}
1293
1294void
1295ChatDialog::sendInvitationWrapper(QString invitee, bool isIntroducer)
1296{
Yingdi Yu76dd8002013-12-24 11:16:32 +08001297 ndn::Name inviteeNamespace(invitee.toStdString());
1298 ndn::ptr_lib::shared_ptr<ContactItem> inviteeItem = m_contactManager->getContact(inviteeNamespace);
Yingdi Yu7989eb22013-10-31 17:38:22 -07001299 sendInvitation(inviteeItem, isIntroducer);
1300}
1301
Yingdi Yu46948282013-11-06 18:43:31 -08001302void
1303ChatDialog::closeEvent(QCloseEvent *e)
1304{
Yingdi Yu702d6f12013-11-07 17:00:54 -08001305 if (trayIcon->isVisible())
1306 {
1307 QMessageBox::information(this, tr("Chronos"),
1308 tr("The program will keep running in the "
1309 "system tray. To terminate the program"
1310 "choose <b>Quit</b> in the context memu"
1311 "of the system tray entry."));
1312 hide();
1313 e->ignore();
1314 }
1315}
1316
1317void
1318ChatDialog::quit()
1319{
Yingdi Yu46948282013-11-06 18:43:31 -08001320 hide();
Yingdi Yu46948282013-11-06 18:43:31 -08001321 emit closeChatDialog(m_chatroomPrefix);
1322}
1323
1324
1325
Yingdi Yu7989eb22013-10-31 17:38:22 -07001326
Alexander Afanasyevb4b92292013-07-09 13:54:59 -07001327#if WAF
1328#include "chatdialog.moc"
1329#include "chatdialog.cpp.moc"
1330#endif