blob: c2d498d913094592b92b1566d9e1c857f64e5955 [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 Yu76dd8002013-12-24 11:16:32 +080024#include <ndn-cpp/sha256-with-rsa-signature.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 Yu6eabbd72013-12-27 08:44:12 +080038 ndn::ptr_lib::shared_ptr<ndn::IdentityManager> identityManager,
Yingdi Yu7989eb22013-10-31 17:38:22 -070039 const ndn::Name& chatroomPrefix,
40 const ndn::Name& localPrefix,
41 const ndn::Name& defaultIdentity,
Yingdi Yu46948282013-11-06 18:43:31 -080042 const std::string& nick,
43 bool trial,
Yingdi Yu5b989132013-10-23 14:03:09 -070044 QWidget *parent)
Yingdi Yu7989eb22013-10-31 17:38:22 -070045: QDialog(parent)
46 , ui(new Ui::ChatDialog)
47 , m_contactManager(contactManager)
48 , m_chatroomPrefix(chatroomPrefix)
49 , m_localPrefix(localPrefix)
50 , m_defaultIdentity(defaultIdentity)
Yingdi Yu76dd8002013-12-24 11:16:32 +080051 , m_invitationPolicyManager(new InvitationPolicyManager(m_chatroomPrefix.get(-1).toEscapedString(), m_defaultIdentity))
Yingdi Yu6eabbd72013-12-27 08:44:12 +080052 , m_identityManager(identityManager)
Yingdi Yu46948282013-11-06 18:43:31 -080053 , m_nick(nick)
Yingdi Yu7989eb22013-10-31 17:38:22 -070054 , m_sock(NULL)
55 , m_lastMsgTime(0)
56 // , m_historyInitialized(false)
57 , m_joined(false)
58 , m_inviteListDialog(new InviteListDialog(m_contactManager))
Zhenkai Zhu6d589aa2012-05-29 17:34:35 -070059{
Yingdi Yu7989eb22013-10-31 17:38:22 -070060 qRegisterMetaType<std::vector<Sync::MissingDataInfo> >("std::vector<Sync::MissingDataInfo>");
61 qRegisterMetaType<size_t>("size_t");
62
Yingdi Yueda39aa2013-10-23 23:07:29 -070063 ui->setupUi(this);
64
Yingdi Yufdb8ab82013-11-10 01:38:21 -080065 QString randString = getRandomString();
Yingdi Yu7989eb22013-10-31 17:38:22 -070066 m_localChatPrefix = m_localPrefix;
Yingdi Yu46948282013-11-06 18:43:31 -080067 m_localChatPrefix.append("%F0.").append(m_defaultIdentity);
Yingdi Yufdb8ab82013-11-10 01:38:21 -080068 m_localChatPrefix.append("chronos").append(m_chatroomPrefix.get(-1)).append(randString.toStdString());
Yingdi Yu7989eb22013-10-31 17:38:22 -070069
70 m_session = time(NULL);
71 m_scene = new DigestTreeScene(this);
72
73 initializeSetting();
74 updateLabels();
75
76 ui->treeViewer->setScene(m_scene);
77 ui->treeViewer->hide();
78 m_scene->plot("Empty");
79 QRectF rect = m_scene->itemsBoundingRect();
80 m_scene->setSceneRect(rect);
81
82 m_rosterModel = new QStringListModel(this);
83 ui->listView->setModel(m_rosterModel);
84
Yingdi Yu83eae842013-11-06 22:07:38 -080085 createActions();
86 createTrayIcon();
87
Yingdi Yu7989eb22013-10-31 17:38:22 -070088 m_timer = new QTimer(this);
89
Yingdi Yu6eabbd72013-12-27 08:44:12 +080090 startFace();
91
Yingdi Yu76dd8002013-12-24 11:16:32 +080092 ndn::Name certificateName = m_identityManager->getDefaultCertificateNameForIdentity(m_defaultIdentity);
Yingdi Yu6eabbd72013-12-27 08:44:12 +080093 m_syncPolicyManager = ndn::ptr_lib::make_shared<SyncPolicyManager>(m_defaultIdentity, certificateName, m_chatroomPrefix, m_face, m_transport);
Yingdi Yu7989eb22013-10-31 17:38:22 -070094
95 connect(ui->inviteButton, SIGNAL(clicked()),
96 this, SLOT(openInviteListDialog()));
97 connect(m_inviteListDialog, SIGNAL(invitionDetermined(QString, bool)),
98 this, SLOT(sendInvitationWrapper(QString, bool)));
99 connect(ui->lineEdit, SIGNAL(returnPressed()),
100 this, SLOT(returnPressed()));
101 connect(ui->treeButton, SIGNAL(pressed()),
102 this, SLOT(treeButtonPressed()));
103 connect(this, SIGNAL(dataReceived(QString, const char *, size_t, bool, bool)),
104 this, SLOT(processData(QString, const char *, size_t, bool, bool)));
105 connect(this, SIGNAL(treeUpdated(const std::vector<Sync::MissingDataInfo>)),
106 this, SLOT(processTreeUpdate(const std::vector<Sync::MissingDataInfo>)));
107 connect(m_timer, SIGNAL(timeout()),
108 this, SLOT(replot()));
109 connect(m_scene, SIGNAL(replot()),
110 this, SLOT(replot()));
Yingdi Yu83eae842013-11-06 22:07:38 -0800111 connect(trayIcon, SIGNAL(messageClicked()),
112 this, SLOT(showNormal()));
113 connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
114 this, SLOT(iconActivated(QSystemTrayIcon::ActivationReason)));
Yingdi Yu7989eb22013-10-31 17:38:22 -0700115 connect(m_scene, SIGNAL(rosterChanged(QStringList)),
116 this, SLOT(updateRosterList(QStringList)));
117
Yingdi Yu7989eb22013-10-31 17:38:22 -0700118
119 initializeSync();
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700120}
121
Yingdi Yu7989eb22013-10-31 17:38:22 -0700122
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700123ChatDialog::~ChatDialog()
124{
Yingdi Yu46948282013-11-06 18:43:31 -0800125 if(m_sock != NULL)
126 {
127 sendLeave();
128 delete m_sock;
129 m_sock = NULL;
130 }
Yingdi Yu6eabbd72013-12-27 08:44:12 +0800131 shutdownFace();
132}
133
134void
135ChatDialog::startFace()
136{
137 m_transport = ndn::ptr_lib::make_shared<ndn::TcpTransport>();
138 m_face = ndn::ptr_lib::make_shared<ndn::Face>(m_transport, ndn::ptr_lib::make_shared<ndn::TcpTransport::ConnectionInfo>("localhost"));
139
140 connectToDaemon();
141
142 m_running = true;
143 m_thread = boost::thread (&ChatDialog::eventLoop, this);
144}
145
146void
147ChatDialog::shutdownFace()
148{
149 {
150 boost::unique_lock<boost::recursive_mutex> lock(m_mutex);
151 m_running = false;
152 }
153
154 m_thread.join();
Yingdi Yu76dd8002013-12-24 11:16:32 +0800155 m_face->shutdown();
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700156}
157
Zhenkai Zhu86df7412012-09-27 16:30:20 -0700158void
Yingdi Yu6eabbd72013-12-27 08:44:12 +0800159ChatDialog::eventLoop()
160{
161 while (m_running)
162 {
163 try{
164 m_face->processEvents();
165 usleep(1000);
166 }catch(std::exception& e){
167 _LOG_DEBUG(" " << e.what() );
168 }
169 }
170}
171
172void
Yingdi Yu76dd8002013-12-24 11:16:32 +0800173ChatDialog::connectToDaemon()
Zhenkai Zhucf024442012-10-05 10:33:08 -0700174{
Yingdi Yu76dd8002013-12-24 11:16:32 +0800175 //Hack! transport does not connect to daemon unless an interest is expressed.
176 ndn::Name name("/ndn");
177 ndn::ptr_lib::shared_ptr<ndn::Interest> interest = ndn::ptr_lib::make_shared<ndn::Interest>(name);
178 m_face->expressInterest(*interest,
179 boost::bind(&ChatDialog::onConnectionData, this, _1, _2),
180 boost::bind(&ChatDialog::onConnectionDataTimeout, this, _1));
Zhenkai Zhud13acd02012-06-04 15:25:20 -0700181}
Alexander Afanasyevb4b92292013-07-09 13:54:59 -0700182
Yingdi Yueda39aa2013-10-23 23:07:29 -0700183void
Yingdi Yu76dd8002013-12-24 11:16:32 +0800184ChatDialog::onConnectionData(const ndn::ptr_lib::shared_ptr<const ndn::Interest>& interest,
185 const ndn::ptr_lib::shared_ptr<ndn::Data>& data)
186{ _LOG_DEBUG("onConnectionData"); }
187
188void
189ChatDialog::onConnectionDataTimeout(const ndn::ptr_lib::shared_ptr<const ndn::Interest>& interest)
190{ _LOG_DEBUG("onConnectionDataTimeout"); }
191
192void
Yingdi Yu7989eb22013-10-31 17:38:22 -0700193ChatDialog::initializeSetting()
Yingdi Yueda39aa2013-10-23 23:07:29 -0700194{
Yingdi Yu46948282013-11-06 18:43:31 -0800195 m_user.setNick(QString::fromStdString(m_nick));
Yingdi Yu76dd8002013-12-24 11:16:32 +0800196 m_user.setChatroom(QString::fromStdString(m_chatroomPrefix.get(-1).toEscapedString()));
Yingdi Yu7989eb22013-10-31 17:38:22 -0700197 m_user.setOriginPrefix(QString::fromStdString(m_localPrefix.toUri()));
198 m_user.setPrefix(QString::fromStdString(m_localChatPrefix.toUri()));
199 m_scene->setCurrentPrefix(QString::fromStdString(m_localChatPrefix.toUri()));
200}
Yingdi Yueda39aa2013-10-23 23:07:29 -0700201
Yingdi Yu7989eb22013-10-31 17:38:22 -0700202void
203ChatDialog::updateLabels()
204{
205 QString settingDisp = QString("Chatroom: %1").arg(m_user.getChatroom());
206 ui->infoLabel->setStyleSheet("QLabel {color: #630; font-size: 16px; font: bold \"Verdana\";}");
207 ui->infoLabel->setText(settingDisp);
208 QString prefixDisp;
209 if (m_user.getPrefix().startsWith("/private/local"))
210 {
211 prefixDisp = QString("<Warning: no connection to hub or hub does not support prefix autoconfig.>\n <Prefix = %1>").arg(m_user.getPrefix());
212 ui->prefixLabel->setStyleSheet("QLabel {color: red; font-size: 12px; font: bold \"Verdana\";}");
213 }
214 else
215 {
216 prefixDisp = QString("<Prefix = %1>").arg(m_user.getPrefix());
217 ui->prefixLabel->setStyleSheet("QLabel {color: Green; font-size: 12px; font: bold \"Verdana\";}");
218 }
219 ui->prefixLabel->setText(prefixDisp);
220}
Yingdi Yueda39aa2013-10-23 23:07:29 -0700221
Yingdi Yu7989eb22013-10-31 17:38:22 -0700222void
Yingdi Yu76dd8002013-12-24 11:16:32 +0800223ChatDialog::sendInterest(const ndn::Interest& interest,
224 const ndn::OnVerified& onVerified,
225 const ndn::OnVerifyFailed& onVerifyFailed,
226 const OnEventualTimeout& timeoutNotify,
227 const ndn::ptr_lib::shared_ptr<ndn::PolicyManager>& policyManager,
228 int retry /* = 1 */,
229 int stepCount /* = 0 */)
230{
231 m_face->expressInterest(interest,
232 boost::bind(&ChatDialog::onTargetData,
233 this,
234 _1,
235 _2,
236 stepCount,
237 onVerified,
238 onVerifyFailed,
239 timeoutNotify,
240 policyManager),
241 boost::bind(&ChatDialog::onTargetTimeout,
242 this,
243 _1,
244 retry,
245 stepCount,
246 onVerified,
247 onVerifyFailed,
248 timeoutNotify,
249 policyManager));
250}
251
252void
253ChatDialog::onTargetData(const ndn::ptr_lib::shared_ptr<const ndn::Interest>& interest,
254 const ndn::ptr_lib::shared_ptr<ndn::Data>& data,
255 int stepCount,
256 const ndn::OnVerified& onVerified,
257 const ndn::OnVerifyFailed& onVerifyFailed,
258 const OnEventualTimeout& timeoutNotify,
259 const ndn::ptr_lib::shared_ptr<ndn::PolicyManager>& policyManager)
260{
261 ndn::ptr_lib::shared_ptr<ndn::ValidationRequest> nextStep = policyManager->checkVerificationPolicy(data, stepCount, onVerified, onVerifyFailed);
262
263 if (nextStep)
264 m_face->expressInterest
265 (*nextStep->interest_,
266 boost::bind(&ChatDialog::onCertData, this, _1, _2, nextStep, policyManager),
267 boost::bind(&ChatDialog::onCertTimeout, this, _1, onVerifyFailed, data, nextStep, policyManager));
268}
269
270void
271ChatDialog::onTargetTimeout(const ndn::ptr_lib::shared_ptr<const ndn::Interest>& interest,
272 int retry,
273 int stepCount,
274 const ndn::OnVerified& onVerified,
275 const ndn::OnVerifyFailed& onVerifyFailed,
276 const OnEventualTimeout& timeoutNotify,
277 const ndn::ptr_lib::shared_ptr<ndn::PolicyManager>& policyManager)
278{
279 if(retry > 0)
280 sendInterest(*interest, onVerified, onVerifyFailed, timeoutNotify, policyManager, retry-1, stepCount);
281 else
282 {
283 _LOG_DEBUG("Interest: " << interest->getName().toUri() << " eventually times out!");
284 timeoutNotify();
285 }
286}
287
288void
289ChatDialog::onCertData(const ndn::ptr_lib::shared_ptr<const ndn::Interest>& interest,
290 const ndn::ptr_lib::shared_ptr<ndn::Data>& cert,
291 ndn::ptr_lib::shared_ptr<ndn::ValidationRequest> previousStep,
292 const ndn::ptr_lib::shared_ptr<ndn::PolicyManager>& policyManager)
293{
294 ndn::ptr_lib::shared_ptr<ndn::ValidationRequest> nextStep = policyManager->checkVerificationPolicy(cert,
295 previousStep->stepCount_,
296 previousStep->onVerified_,
297 previousStep->onVerifyFailed_);
298
299 if (nextStep)
300 m_face->expressInterest
301 (*nextStep->interest_,
302 boost::bind(&ChatDialog::onCertData, this, _1, _2, nextStep, policyManager),
303 boost::bind(&ChatDialog::onCertTimeout, this, _1, previousStep->onVerifyFailed_, cert, nextStep, policyManager));
304}
305
306void
307ChatDialog::onCertTimeout(const ndn::ptr_lib::shared_ptr<const ndn::Interest>& interest,
308 const ndn::OnVerifyFailed& onVerifyFailed,
309 const ndn::ptr_lib::shared_ptr<ndn::Data>& data,
310 ndn::ptr_lib::shared_ptr<ndn::ValidationRequest> nextStep,
311 const ndn::ptr_lib::shared_ptr<ndn::PolicyManager>& policyManager)
312{
313 if(nextStep->retry_ > 0)
314 m_face->expressInterest(*interest,
315 boost::bind(&ChatDialog::onCertData,
316 this,
317 _1,
318 _2,
319 nextStep,
320 policyManager),
321 boost::bind(&ChatDialog::onCertTimeout,
322 this,
323 _1,
324 onVerifyFailed,
325 data,
326 nextStep,
327 policyManager));
328 else
329 onVerifyFailed(data);
330}
331
332void
333ChatDialog::sendInvitation(ndn::ptr_lib::shared_ptr<ContactItem> contact, bool isIntroducer)
Yingdi Yu7989eb22013-10-31 17:38:22 -0700334{
335 m_invitationPolicyManager->addTrustAnchor(contact->getSelfEndorseCertificate());
336
Yingdi Yu76dd8002013-12-24 11:16:32 +0800337 ndn::Name certificateName = m_identityManager->getDefaultCertificateNameForIdentity(m_defaultIdentity);
Yingdi Yu7989eb22013-10-31 17:38:22 -0700338
339 ndn::Name interestName("/ndn/broadcast/chronos/invitation");
Yingdi Yueda39aa2013-10-23 23:07:29 -0700340 interestName.append(contact->getNameSpace());
341 interestName.append("chatroom");
342 interestName.append(m_chatroomPrefix.get(-1));
343 interestName.append("inviter-prefix");
344 interestName.append(m_localPrefix);
345 interestName.append("inviter");
346 interestName.append(certificateName);
347
348 string signedUri = interestName.toUri();
Yingdi Yu76dd8002013-12-24 11:16:32 +0800349 ndn::Blob signedBlob((const uint8_t*)signedUri.c_str(), signedUri.size());
Yingdi Yueda39aa2013-10-23 23:07:29 -0700350
Yingdi Yu76dd8002013-12-24 11:16:32 +0800351 ndn::ptr_lib::shared_ptr<const ndn::Sha256WithRsaSignature> sha256sig = ndn::ptr_lib::dynamic_pointer_cast<const ndn::Sha256WithRsaSignature>(m_identityManager->signByCertificate(signedBlob.buf(), signedBlob.size(), certificateName));
352 const ndn::Blob& sigBits = sha256sig->getSignature();
Yingdi Yueda39aa2013-10-23 23:07:29 -0700353
Yingdi Yu6eabbd72013-12-27 08:44:12 +0800354 _LOG_DEBUG("size A: " << interestName.size());
355
Yingdi Yu76dd8002013-12-24 11:16:32 +0800356 interestName.append(sigBits);
Yingdi Yu6eabbd72013-12-27 08:44:12 +0800357
358 _LOG_DEBUG("size B: " << interestName.size());
359
Yingdi Yu76dd8002013-12-24 11:16:32 +0800360 //TODO... remove version from invitation interest
361 // interestName.appendVersion();
Yingdi Yu46948282013-11-06 18:43:31 -0800362
Yingdi Yu76dd8002013-12-24 11:16:32 +0800363 ndn::Interest interest(interestName);
364 ndn::OnVerified onVerified = boost::bind(&ChatDialog::onInviteReplyVerified,
365 this,
366 _1,
367 contact->getNameSpace(),
368 isIntroducer);
Yingdi Yueda39aa2013-10-23 23:07:29 -0700369
Yingdi Yu76dd8002013-12-24 11:16:32 +0800370 ndn::OnVerifyFailed onVerifyFailed = boost::bind(&ChatDialog::onInviteReplyVerifyFailed,
371 this,
372 _1,
373 contact->getNameSpace());
374
375 OnEventualTimeout timeoutNotify = boost::bind(&ChatDialog::onInviteReplyTimeout,
376 this,
377 contact->getNameSpace());
378
379
380 sendInterest(interest, onVerified, onVerifyFailed, timeoutNotify, m_invitationPolicyManager);
381}
382
383void
384ChatDialog::onInviteReplyVerified(const ndn::ptr_lib::shared_ptr<ndn::Data>& data,
385 const ndn::Name& identity,
386 bool isIntroducer)
387{
388 string content((const char*)data->getContent().buf(), data->getContent().size());
389 if(content == string("nack"))
390 invitationRejected(identity);
391 else
392 invitationAccepted(identity, data, content, isIntroducer);
Yingdi Yueda39aa2013-10-23 23:07:29 -0700393}
394
395void
Yingdi Yu76dd8002013-12-24 11:16:32 +0800396ChatDialog::onInviteReplyVerifyFailed(const ndn::ptr_lib::shared_ptr<ndn::Data>& data,
397 const ndn::Name& identity)
Yingdi Yueda39aa2013-10-23 23:07:29 -0700398{
Yingdi Yu76dd8002013-12-24 11:16:32 +0800399 _LOG_DEBUG("Reply from " << identity.toUri() << " cannot be verified!");
400 QString msg = QString::fromUtf8("Reply from ") + QString::fromStdString(identity.toUri()) + " cannot be verified!";
401 emit inivationRejection(msg);
402}
403
404
405void
406ChatDialog::onInviteReplyTimeout(const ndn::Name& identity)
407{
408 _LOG_DEBUG("Your invitation to " << identity.toUri() << " times out!");
409 QString msg = QString::fromUtf8("Your invitation to ") + QString::fromStdString(identity.toUri()) + " times out!";
410 emit inivationRejection(msg);
Yingdi Yueda39aa2013-10-23 23:07:29 -0700411}
412
413void
Yingdi Yu7989eb22013-10-31 17:38:22 -0700414ChatDialog::invitationRejected(const ndn::Name& identity)
415{
Yingdi Yu72781e52013-11-06 23:00:21 -0800416 _LOG_DEBUG(" " << identity.toUri() << " Rejected your invitation!");
Yingdi Yu0aca2652013-11-10 10:47:44 -0800417 QString msg = QString::fromStdString(identity.toUri()) + " Rejected your invitation!";
418 emit inivationRejection(msg);
Yingdi Yu7989eb22013-10-31 17:38:22 -0700419}
420
421void
Yingdi Yu76dd8002013-12-24 11:16:32 +0800422ChatDialog::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 -0700423{
Yingdi Yu72781e52013-11-06 23:00:21 -0800424 _LOG_DEBUG(" " << identity.toUri() << " Accepted your invitation!");
Yingdi Yu76dd8002013-12-24 11:16:32 +0800425 const ndn::Sha256WithRsaSignature* sha256sig = dynamic_cast<const ndn::Sha256WithRsaSignature*>(data->getSignature());
Yingdi Yu7989eb22013-10-31 17:38:22 -0700426 const ndn::Name & keyLocatorName = sha256sig->getKeyLocator().getKeyName();
Yingdi Yu76dd8002013-12-24 11:16:32 +0800427 ndn::ptr_lib::shared_ptr<ndn::IdentityCertificate> dskCertificate = m_invitationPolicyManager->getValidatedDskCertificate(keyLocatorName);
Yingdi Yue6476cd2013-11-06 18:51:19 -0800428 m_syncPolicyManager->addChatDataRule(inviteePrefix, *dskCertificate, isIntroducer);
Yingdi Yu83eae842013-11-06 22:07:38 -0800429 publishIntroCert(*dskCertificate, isIntroducer);
Yingdi Yueda39aa2013-10-23 23:07:29 -0700430}
431
Yingdi Yu76dd8002013-12-24 11:16:32 +0800432void
433ChatDialog::publishIntroCert(const ndn::IdentityCertificate& dskCertificate, bool isIntroducer)
Yingdi Yueda39aa2013-10-23 23:07:29 -0700434{
Yingdi Yu76dd8002013-12-24 11:16:32 +0800435 SyncIntroCertificate syncIntroCertificate(m_chatroomPrefix,
436 dskCertificate.getPublicKeyName(),
437 m_identityManager->getDefaultKeyNameForIdentity(m_defaultIdentity),
438 dskCertificate.getNotBefore(),
439 dskCertificate.getNotAfter(),
440 dskCertificate.getPublicKeyInfo(),
441 (isIntroducer ? SyncIntroCertificate::INTRODUCER : SyncIntroCertificate::PRODUCER));
442 ndn::Name certName = m_identityManager->getDefaultCertificateNameForIdentity(m_defaultIdentity);
443 _LOG_DEBUG("Publish Intro Certificate: " << syncIntroCertificate.getName());
444 m_identityManager->signByCertificate(syncIntroCertificate, certName);
445 m_transport->send(*syncIntroCertificate.wireEncode());
Yingdi Yueda39aa2013-10-23 23:07:29 -0700446}
447
Yingdi Yu76dd8002013-12-24 11:16:32 +0800448void
449ChatDialog::addTrustAnchor(const EndorseCertificate& selfEndorseCertificate)
450{ m_invitationPolicyManager->addTrustAnchor(selfEndorseCertificate); }
451
452void
453ChatDialog::addChatDataRule(const ndn::Name& prefix,
454 const ndn::IdentityCertificate& identityCertificate,
455 bool isIntroducer)
456{ m_syncPolicyManager->addChatDataRule(prefix, identityCertificate, isIntroducer); }
457
Yingdi Yueda39aa2013-10-23 23:07:29 -0700458
Yingdi Yu46948282013-11-06 18:43:31 -0800459
460void
Yingdi Yu7989eb22013-10-31 17:38:22 -0700461ChatDialog::initializeSync()
462{
463
464 m_sock = new Sync::SyncSocket(m_chatroomPrefix.toUri(),
465 m_syncPolicyManager,
Yingdi Yu6eabbd72013-12-27 08:44:12 +0800466 m_face,
467 m_transport,
Yingdi Yu76dd8002013-12-24 11:16:32 +0800468 boost::bind(&ChatDialog::processTreeUpdateWrapper, this, _1, _2),
469 boost::bind(&ChatDialog::processRemoveWrapper, this, _1));
Yingdi Yu7989eb22013-10-31 17:38:22 -0700470
471 usleep(100000);
472
473 QTimer::singleShot(600, this, SLOT(sendJoin()));
474 m_timer->start(FRESHNESS * 1000);
475 disableTreeDisplay();
476 QTimer::singleShot(2200, this, SLOT(enableTreeDisplay()));
477 // Sync::CcnxWrapperPtr handle = boost::make_shared<Sync::CcnxWrapper> ();
478 // handle->setInterestFilter(m_user.getPrefix().toStdString(), bind(&ChatDialog::respondHistoryRequest, this, _1));
Yingdi Yu7989eb22013-10-31 17:38:22 -0700479}
480
481void
482ChatDialog::returnPressed()
483{
484 QString text = ui->lineEdit->text();
485 if (text.isEmpty())
486 return;
487
488 ui->lineEdit->clear();
489
490 if (text.startsWith("boruoboluomi"))
491 {
492 summonReaper ();
493 // reapButton->show();
494 fitView();
495 return;
496 }
497
498 if (text.startsWith("minimanihong"))
499 {
500 // reapButton->hide();
501 fitView();
502 return;
503 }
504
505 SyncDemo::ChatMessage msg;
506 formChatMessage(text, msg);
507
508 appendMessage(msg);
509
510 sendMsg(msg);
511
512 fitView();
513}
514
515void
516ChatDialog::treeButtonPressed()
517{
518 if (ui->treeViewer->isVisible())
519 {
520 ui->treeViewer->hide();
521 ui->treeButton->setText("Show ChronoSync Tree");
522 }
523 else
524 {
525 ui->treeViewer->show();
526 ui->treeButton->setText("Hide ChronoSync Tree");
527 }
528
529 fitView();
530}
531
532void ChatDialog::disableTreeDisplay()
533{
534 ui->treeButton->setEnabled(false);
535 ui->treeViewer->hide();
536 fitView();
537}
538
539void ChatDialog::enableTreeDisplay()
540{
541 ui->treeButton->setEnabled(true);
542 // treeViewer->show();
543 // fitView();
544}
545
546void
547ChatDialog::processTreeUpdateWrapper(const std::vector<Sync::MissingDataInfo> v, Sync::SyncSocket *sock)
548{
549 emit treeUpdated(v);
550 _LOG_DEBUG("<<< Tree update signal emitted");
551}
552
553void
554ChatDialog::processRemoveWrapper(std::string prefix)
555{
556 _LOG_DEBUG("Sync REMOVE signal received for prefix: " << prefix);
557}
558
559void
560ChatDialog::processTreeUpdate(const std::vector<Sync::MissingDataInfo> v)
561{
562 _LOG_DEBUG("<<< processing Tree Update");
563
564 if (v.empty())
565 {
566 return;
567 }
568
569 // reflect the changes on digest tree
570 {
571 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
572 m_scene->processUpdate(v, m_sock->getRootDigest().c_str());
573 }
574
575 int n = v.size();
576 int totalMissingPackets = 0;
577 for (int i = 0; i < n; i++)
578 {
579 totalMissingPackets += v[i].high.getSeq() - v[i].low.getSeq() + 1;
580 }
581
582 for (int i = 0; i < n; i++)
583 {
584 if (totalMissingPackets < 4)
585 {
586 for (Sync::SeqNo seq = v[i].low; seq <= v[i].high; ++seq)
587 {
588 m_sock->fetchData(v[i].prefix, seq, bind(&ChatDialog::processDataWrapper, this, _1), 2);
589 _LOG_DEBUG("<<< Fetching " << v[i].prefix << "/" <<seq.getSession() <<"/" << seq.getSeq());
590 }
591 }
592 else
593 {
594 m_sock->fetchData(v[i].prefix, v[i].high, bind(&ChatDialog::processDataNoShowWrapper, this, _1), 2);
595 }
596 }
597
598 // adjust the view
599 fitView();
600
601}
602
603void
Yingdi Yu76dd8002013-12-24 11:16:32 +0800604ChatDialog::processDataWrapper(const ndn::ptr_lib::shared_ptr<ndn::Data>& data)
Yingdi Yu7989eb22013-10-31 17:38:22 -0700605{
606 string name = data->getName().toUri();
Yingdi Yu76dd8002013-12-24 11:16:32 +0800607 const char* buf = (const char*)data->getContent().buf();
608 size_t len = data->getContent().size();
Yingdi Yu7989eb22013-10-31 17:38:22 -0700609
610 char *tempBuf = new char[len];
611 memcpy(tempBuf, buf, len);
612 emit dataReceived(name.c_str(), tempBuf, len, true, false);
613 _LOG_DEBUG("<<< " << name << " fetched");
614}
615
616void
Yingdi Yu76dd8002013-12-24 11:16:32 +0800617ChatDialog::processDataNoShowWrapper(const ndn::ptr_lib::shared_ptr<ndn::Data>& data)
Yingdi Yu7989eb22013-10-31 17:38:22 -0700618{
619 string name = data->getName().toUri();
Yingdi Yu76dd8002013-12-24 11:16:32 +0800620 const char* buf = (const char*)data->getContent().buf();
621 size_t len = data->getContent().size();
Yingdi Yu7989eb22013-10-31 17:38:22 -0700622
623 char *tempBuf = new char[len];
624 memcpy(tempBuf, buf, len);
625 emit dataReceived(name.c_str(), tempBuf, len, false, false);
626
627 // if (!m_historyInitialized)
628 // {
629 // fetchHistory(name);
630 // m_historyInitialized = true;
631 // }
632}
633
634// void
635// ChatDialog::fetchHistory(std::string name)
636// {
637
638// /****************************/
639// /* TODO: fix following part */
640// /****************************/
641// string nameWithoutSeq = name.substr(0, name.find_last_of('/'));
642// string prefix = nameWithoutSeq.substr(0, nameWithoutSeq.find_last_of('/'));
643// prefix += "/history";
644// // Ptr<Wrapper>CcnxWrapperPtr handle = boost::make_shared<Sync::CcnxWrapper> ();
645// // QString randomString = getRandomString();
646// // for (int i = 0; i < MAX_HISTORY_ENTRY; i++)
647// // {
648// // QString interest = QString("%1/%2/%3").arg(prefix.c_str()).arg(randomString).arg(i);
649// // handle->sendInterest(interest.toStdString(), bind(&ChatDialog::processDataHistoryWrapper, this, _1, _2, _3));
650// // }
651// }
652
653void
654ChatDialog::processData(QString name, const char *buf, size_t len, bool show, bool isHistory)
655{
656 SyncDemo::ChatMessage msg;
657 bool corrupted = false;
658 if (!msg.ParseFromArray(buf, len))
659 {
660 _LOG_DEBUG("Errrrr.. Can not parse msg with name: " << name.toStdString() << ". what is happening?");
661 // nasty stuff: as a remedy, we'll form some standard msg for inparsable msgs
662 msg.set_from("inconnu");
663 msg.set_type(SyncDemo::ChatMessage::OTHER);
664 corrupted = true;
665 }
666
667 delete [] buf;
668 buf = NULL;
669
670 // display msg received from network
671 // we have to do so; this function is called by ccnd thread
672 // so if we call appendMsg directly
673 // Qt crash as "QObject: Cannot create children for a parent that is in a different thread"
674 // the "cannonical" way to is use signal-slot
675 if (show && !corrupted)
676 {
677 appendMessage(msg, isHistory);
678 }
679
680 if (!isHistory)
681 {
682 // update the tree view
683 std::string stdStrName = name.toStdString();
684 std::string stdStrNameWithoutSeq = stdStrName.substr(0, stdStrName.find_last_of('/'));
685 std::string prefix = stdStrNameWithoutSeq.substr(0, stdStrNameWithoutSeq.find_last_of('/'));
686 _LOG_DEBUG("<<< updating scene for" << prefix << ": " << msg.from());
687 if (msg.type() == SyncDemo::ChatMessage::LEAVE)
688 {
689 processRemove(prefix.c_str());
690 }
691 else
692 {
693 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
694 m_scene->msgReceived(prefix.c_str(), msg.from().c_str());
695 }
696 }
697 fitView();
698}
699
700void
701ChatDialog::processRemove(QString prefix)
702{
703 _LOG_DEBUG("<<< remove node for prefix" << prefix.toStdString());
704
705 bool removed = m_scene->removeNode(prefix);
706 if (removed)
707 {
708 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
709 m_scene->plot(m_sock->getRootDigest().c_str());
710 }
711}
712
713void
714ChatDialog::sendJoin()
715{
716 m_joined = true;
717 SyncDemo::ChatMessage msg;
718 formControlMessage(msg, SyncDemo::ChatMessage::JOIN);
719 sendMsg(msg);
720 boost::random::random_device rng;
721 boost::random::uniform_int_distribution<> uniform(1, FRESHNESS / 5 * 1000);
722 m_randomizedInterval = HELLO_INTERVAL * 1000 + uniform(rng);
723 QTimer::singleShot(m_randomizedInterval, this, SLOT(sendHello()));
724}
725
726void
727ChatDialog::sendHello()
728{
729 time_t now = time(NULL);
730 int elapsed = now - m_lastMsgTime;
731 if (elapsed >= m_randomizedInterval / 1000)
732 {
733 SyncDemo::ChatMessage msg;
734 formControlMessage(msg, SyncDemo::ChatMessage::HELLO);
735 sendMsg(msg);
736 boost::random::random_device rng;
737 boost::random::uniform_int_distribution<> uniform(1, FRESHNESS / 5 * 1000);
738 m_randomizedInterval = HELLO_INTERVAL * 1000 + uniform(rng);
739 QTimer::singleShot(m_randomizedInterval, this, SLOT(sendHello()));
740 }
741 else
742 {
743 QTimer::singleShot((m_randomizedInterval - elapsed * 1000), this, SLOT(sendHello()));
744 }
745}
746
747void
748ChatDialog::sendLeave()
749{
750 SyncDemo::ChatMessage msg;
751 formControlMessage(msg, SyncDemo::ChatMessage::LEAVE);
752 sendMsg(msg);
753 usleep(500000);
754 m_sock->remove(m_user.getPrefix().toStdString());
755 usleep(5000);
756 m_joined = false;
757 _LOG_DEBUG("Sync REMOVE signal sent");
758}
759
760void
761ChatDialog::replot()
762{
763 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
764 m_scene->plot(m_sock->getRootDigest().c_str());
765 fitView();
766}
767
768void
769ChatDialog::summonReaper()
770{
771 Sync::SyncLogic &logic = m_sock->getLogic ();
772 map<string, bool> branches = logic.getBranchPrefixes();
773 QMap<QString, DisplayUserPtr> roster = m_scene->getRosterFull();
774
775 m_zombieList.clear();
776
777 QMapIterator<QString, DisplayUserPtr> it(roster);
778 map<string, bool>::iterator mapIt;
779 while(it.hasNext())
780 {
781 it.next();
782 DisplayUserPtr p = it.value();
783 if (p != DisplayUserNullPtr)
784 {
785 mapIt = branches.find(p->getPrefix().toStdString());
786 if (mapIt != branches.end())
787 {
788 mapIt->second = true;
789 }
790 }
791 }
792
793 for (mapIt = branches.begin(); mapIt != branches.end(); ++mapIt)
794 {
795 // this is zombie. all active users should have been marked true
796 if (! mapIt->second)
797 {
798 m_zombieList.append(mapIt->first.c_str());
799 }
800 }
801
802 m_zombieIndex = 0;
803
804 // start reaping
805 reap();
806}
807
808void
809ChatDialog::reap()
810{
811 if (m_zombieIndex < m_zombieList.size())
812 {
813 string prefix = m_zombieList.at(m_zombieIndex).toStdString();
814 m_sock->remove(prefix);
815 _LOG_DEBUG("Reaped: prefix = " << prefix);
816 m_zombieIndex++;
817 // reap again in 10 seconds
818 QTimer::singleShot(10000, this, SLOT(reap()));
819 }
820}
821
822void
823ChatDialog::updateRosterList(QStringList staleUserList)
824{
825 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
826 QStringList rosterList = m_scene->getRosterList();
827 m_rosterModel->setStringList(rosterList);
828 QString user;
829 QStringListIterator it(staleUserList);
830 while(it.hasNext())
831 {
832 std::string nick = it.next().toStdString();
833 if (nick.empty())
834 continue;
835
836 SyncDemo::ChatMessage msg;
837 formControlMessage(msg, SyncDemo::ChatMessage::LEAVE);
838 msg.set_from(nick);
839 appendMessage(msg);
840 }
841}
842
843void
Yingdi Yufdb8ab82013-11-10 01:38:21 -0800844ChatDialog::settingUpdated(QString nick, QString chatroom, QString originPrefix)
845{
Yingdi Yu1ecf81f2013-11-10 12:25:43 -0800846 _LOG_DEBUG("called");
Yingdi Yufdb8ab82013-11-10 01:38:21 -0800847 QString randString = getRandomString();
848 bool needWrite = false;
849 bool needFresh = false;
850
851 QString oldPrefix = m_user.getPrefix();
852 if (!originPrefix.isEmpty() && originPrefix != m_user.getOriginPrefix()) {
853 m_user.setOriginPrefix(originPrefix);
854
855 m_localPrefix = ndn::Name(originPrefix.toStdString());
856 m_localChatPrefix = m_localPrefix;
857 m_localChatPrefix.append("%F0.").append(m_defaultIdentity);
858 m_localChatPrefix.append("chronos").append(m_chatroomPrefix.get(-1)).append(randString.toStdString());
859 m_user.setPrefix(QString::fromStdString(m_localChatPrefix.toUri()));
860 m_scene->setCurrentPrefix(QString::fromStdString(m_localChatPrefix.toUri()));
861 needWrite = true;
862 needFresh = true;
863 }
864
865 if (needWrite) {
866 updateLabels();
867 }
868
869 if (needFresh && m_sock != NULL)
870 {
871
872 {
873 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
874 m_scene->clearAll();
875 m_scene->plot("Empty");
876 }
877
Yingdi Yua66183f2013-11-10 10:32:18 -0800878 ui->textEdit->clear();
Yingdi Yufdb8ab82013-11-10 01:38:21 -0800879
880 // keep the new prefix
881 QString newPrefix = m_user.getPrefix();
882 // send leave for the old
883 m_user.setPrefix(oldPrefix);
884 // there is no point to send leave if we haven't joined yet
885 if (m_joined)
886 {
887 sendLeave();
888 }
889 // resume new prefix
890 m_user.setPrefix(newPrefix);
891 // Sync::CcnxWrapperPtr handle = Sync::CcnxWrapper::Create();
892 // handle->clearInterestFilter(oldPrefix.toStdString());
893 delete m_sock;
894 m_sock = NULL;
895
896 try
897 {
898 usleep(100000);
899 m_sock = new Sync::SyncSocket(m_chatroomPrefix.toUri(),
900 m_syncPolicyManager,
Yingdi Yu6eabbd72013-12-27 08:44:12 +0800901 m_face,
902 m_transport,
Yingdi Yufdb8ab82013-11-10 01:38:21 -0800903 bind(&ChatDialog::processTreeUpdateWrapper, this, _1, _2),
904 bind(&ChatDialog::processRemoveWrapper, this, _1));
905 usleep(100000);
906 // Sync::CcnxWrapperPtr handle = boost::make_shared<Sync::CcnxWrapper> ();
907 // handle->setInterestFilter(m_user.getPrefix().toStdString(), bind(&ChatDialog::respondHistoryRequest, this, _1));
Yingdi Yua66183f2013-11-10 10:32:18 -0800908 QTimer::singleShot(600, this, SLOT(sendJoin()));
Yingdi Yufdb8ab82013-11-10 01:38:21 -0800909 m_timer->start(FRESHNESS * 1000);
910 disableTreeDisplay();
Yingdi Yua66183f2013-11-10 10:32:18 -0800911 QTimer::singleShot(2200, this, SLOT(enableTreeDisplay()));
Yingdi Yu76dd8002013-12-24 11:16:32 +0800912 }catch(std::exception& e){
Yingdi Yufdb8ab82013-11-10 01:38:21 -0800913 emit noNdnConnection(QString::fromStdString("Cannot conect to ndnd!\n Have you started your ndnd?"));
914 }
915 }
916 else if (needFresh && m_sock == NULL)
917 {
918 initializeSync();
919 }
920 else if (m_sock == NULL)
921 {
922 initializeSync();
923 }
924 else
925 {
926// #ifdef __DEBUG
927// std::cout << "Just changing nicks, we're good. " << std::endl;
928// #endif
929 }
930
931 fitView();
932}
933
934void
Yingdi Yu83eae842013-11-06 22:07:38 -0800935ChatDialog::iconActivated(QSystemTrayIcon::ActivationReason reason)
936{
937 switch (reason)
938 {
939 case QSystemTrayIcon::Trigger:
940 case QSystemTrayIcon::DoubleClick:
941 break;
942 case QSystemTrayIcon::MiddleClick:
943 // showMessage();
944 break;
945 default:;
946 }
947}
948
949
950void
951ChatDialog::messageClicked()
952{
953 this->showMaximized();
954}
955
956
957void
958ChatDialog::createActions()
959{
Yingdi Yu702d6f12013-11-07 17:00:54 -0800960 minimizeAction = new QAction(tr("Mi&nimize"), this);
961 connect(minimizeAction, SIGNAL(triggered()), this, SLOT(hide()));
Yingdi Yu83eae842013-11-06 22:07:38 -0800962
Yingdi Yu702d6f12013-11-07 17:00:54 -0800963 maximizeAction = new QAction(tr("Ma&ximize"), this);
964 connect(maximizeAction, SIGNAL(triggered()), this, SLOT(showMaximized()));
Yingdi Yu83eae842013-11-06 22:07:38 -0800965
Yingdi Yu702d6f12013-11-07 17:00:54 -0800966 restoreAction = new QAction(tr("&Restore"), this);
967 connect(restoreAction, SIGNAL(triggered()), this, SLOT(showNormal()));
Yingdi Yu83eae842013-11-06 22:07:38 -0800968
969 // settingsAction = new QAction(tr("Settings"), this);
970 // connect (settingsAction, SIGNAL(triggered()), this, SLOT(buttonPressed()));
971
972 // settingsAction->setMenuRole (QAction::PreferencesRole);
973
Yingdi Yufdb8ab82013-11-10 01:38:21 -0800974 updateLocalPrefixAction = new QAction(tr("Update local prefix"), this);
975 connect (updateLocalPrefixAction, SIGNAL(triggered()), this, SLOT(updateLocalPrefix()));
Yingdi Yu83eae842013-11-06 22:07:38 -0800976
Yingdi Yu702d6f12013-11-07 17:00:54 -0800977 quitAction = new QAction(tr("Quit"), this);
978 connect(quitAction, SIGNAL(triggered()), this, SLOT(quit()));
Yingdi Yu83eae842013-11-06 22:07:38 -0800979}
980
981void
982ChatDialog::createTrayIcon()
983{
Yingdi Yu702d6f12013-11-07 17:00:54 -0800984 trayIconMenu = new QMenu(this);
985 trayIconMenu->addAction(minimizeAction);
986 trayIconMenu->addAction(maximizeAction);
987 trayIconMenu->addAction(restoreAction);
Yingdi Yu83eae842013-11-06 22:07:38 -0800988 // trayIconMenu->addSeparator();
989 // trayIconMenu->addAction(settingsAction);
Yingdi Yufdb8ab82013-11-10 01:38:21 -0800990 trayIconMenu->addSeparator();
991 trayIconMenu->addAction(updateLocalPrefixAction);
Yingdi Yu702d6f12013-11-07 17:00:54 -0800992 trayIconMenu->addSeparator();
993 trayIconMenu->addAction(quitAction);
Yingdi Yu83eae842013-11-06 22:07:38 -0800994
995 trayIcon = new QSystemTrayIcon(this);
Yingdi Yu702d6f12013-11-07 17:00:54 -0800996 trayIcon->setContextMenu(trayIconMenu);
Yingdi Yu83eae842013-11-06 22:07:38 -0800997
998 QIcon icon(":/images/icon_small.png");
999 trayIcon->setIcon(icon);
1000 setWindowIcon(icon);
1001 trayIcon->setToolTip("ChronoChat System Tray Icon");
1002 trayIcon->setVisible(true);
Yingdi Yu83eae842013-11-06 22:07:38 -08001003}
1004
1005
1006void
Yingdi Yu7989eb22013-10-31 17:38:22 -07001007ChatDialog::resizeEvent(QResizeEvent *e)
1008{
1009 fitView();
1010}
1011
1012void
1013ChatDialog::showEvent(QShowEvent *e)
1014{
1015 fitView();
1016}
1017
1018void
1019ChatDialog::fitView()
1020{
1021 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
1022 QRectF rect = m_scene->itemsBoundingRect();
1023 m_scene->setSceneRect(rect);
1024 ui->treeViewer->fitInView(m_scene->itemsBoundingRect(), Qt::KeepAspectRatio);
1025}
1026
1027void
1028ChatDialog::formChatMessage(const QString &text, SyncDemo::ChatMessage &msg) {
1029 msg.set_from(m_user.getNick().toStdString());
1030 msg.set_to(m_user.getChatroom().toStdString());
1031 msg.set_data(text.toUtf8().constData());
1032 time_t seconds = time(NULL);
1033 msg.set_timestamp(seconds);
1034 msg.set_type(SyncDemo::ChatMessage::CHAT);
1035}
1036
1037void
1038ChatDialog::formControlMessage(SyncDemo::ChatMessage &msg, SyncDemo::ChatMessage::ChatMessageType type)
1039{
1040 msg.set_from(m_user.getNick().toStdString());
1041 msg.set_to(m_user.getChatroom().toStdString());
1042 time_t seconds = time(NULL);
1043 msg.set_timestamp(seconds);
1044 msg.set_type(type);
1045}
1046
1047void
Yingdi Yufdb8ab82013-11-10 01:38:21 -08001048ChatDialog::updateLocalPrefix()
1049{
Yingdi Yua66183f2013-11-10 10:32:18 -08001050 m_newLocalPrefixReady = false;
Yingdi Yu76dd8002013-12-24 11:16:32 +08001051 ndn::Name interestName("/local/ndn/prefix");
1052 ndn::Interest interest(interestName);
1053 interest.setChildSelector(ndn_Interest_CHILD_SELECTOR_RIGHT);
1054 interest.setInterestLifetimeMilliseconds(1000);
Yingdi Yufdb8ab82013-11-10 01:38:21 -08001055
Yingdi Yu76dd8002013-12-24 11:16:32 +08001056 m_face->expressInterest(interest,
1057 bind(&ChatDialog::onLocalPrefix, this, _1, _2),
1058 bind(&ChatDialog::onLocalPrefixTimeout, this, _1));
Yingdi Yufdb8ab82013-11-10 01:38:21 -08001059
Yingdi Yua66183f2013-11-10 10:32:18 -08001060 while(m_newLocalPrefixReady == false)
1061 {
1062#if BOOST_VERSION >= 1050000
1063 boost::this_thread::sleep_for(boost::chrono::milliseconds(100));
1064#else
1065 boost::this_thread::sleep(boost::posix_time::milliseconds(100));
1066#endif
1067 }
Yingdi Yu1ecf81f2013-11-10 12:25:43 -08001068 _LOG_DEBUG("now the prefix is " << m_newLocalPrefix.toUri());
Yingdi Yuaf305d72013-11-10 11:54:02 -08001069 _LOG_DEBUG("in use prefix is " << m_user.getOriginPrefix().toStdString());
Yingdi Yua66183f2013-11-10 10:32:18 -08001070 QString originPrefix = QString::fromStdString(m_newLocalPrefix.toUri());
1071
1072 if (originPrefix != "" && m_user.getOriginPrefix () != originPrefix)
1073 emit settingUpdated(m_user.getNick (), m_user.getChatroom (), originPrefix);
Yingdi Yufdb8ab82013-11-10 01:38:21 -08001074}
1075
Yingdi Yu76dd8002013-12-24 11:16:32 +08001076
1077void
1078ChatDialog::onLocalPrefix(const ndn::ptr_lib::shared_ptr<const ndn::Interest>& interest,
1079 const ndn::ptr_lib::shared_ptr<ndn::Data>& data)
1080{
1081 string dataString((const char*)data->getContent().buf(), data->getContent().size());
1082 QString originPrefix = QString::fromStdString (dataString).trimmed ();
1083 string trimmedString = originPrefix.toStdString();
1084 m_newLocalPrefix = ndn::Name(trimmedString);
1085 m_newLocalPrefixReady = true;
1086}
1087
1088void
1089ChatDialog::onLocalPrefixTimeout(const ndn::ptr_lib::shared_ptr<const ndn::Interest>& interest)
1090{
1091 m_newLocalPrefix = m_localPrefix;
1092 m_newLocalPrefixReady = true;
1093}
1094
Yingdi Yufdb8ab82013-11-10 01:38:21 -08001095static std::string chars2("qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM0123456789");
1096
1097QString
1098ChatDialog::getRandomString()
1099{
1100 std::string randStr;
1101 boost::random::random_device rng;
1102 boost::random::uniform_int_distribution<> index_dist(0, chars2.size() - 1);
1103 for (int i = 0; i < 10; i ++)
1104 {
1105 randStr += chars2[index_dist(rng)];
1106 }
1107 return randStr.c_str();
1108}
1109
1110void
Yingdi Yu83eae842013-11-06 22:07:38 -08001111ChatDialog::changeEvent(QEvent *e)
1112{
1113 switch(e->type())
1114 {
1115 case QEvent::ActivationChange:
1116 if (isActiveWindow())
1117 {
1118 trayIcon->setIcon(QIcon(":/images/icon_small.png"));
1119 }
1120 break;
1121 default:
1122 break;
1123 }
1124}
1125
1126void
Yingdi Yu7989eb22013-10-31 17:38:22 -07001127ChatDialog::appendMessage(const SyncDemo::ChatMessage msg, bool isHistory)
1128{
1129 boost::recursive_mutex::scoped_lock lock(m_msgMutex);
1130
1131 if (msg.type() == SyncDemo::ChatMessage::CHAT)
1132 {
1133
1134 if (!msg.has_data())
1135 {
1136 return;
1137 }
1138
1139 if (msg.from().empty() || msg.data().empty())
1140 {
1141 return;
1142 }
1143
1144 if (!msg.has_timestamp())
1145 {
1146 return;
1147 }
1148
1149 // if (m_history.size() == MAX_HISTORY_ENTRY)
1150 // {
1151 // m_history.dequeue();
1152 // }
1153
1154 // m_history.enqueue(msg);
1155
1156 QTextCharFormat nickFormat;
1157 nickFormat.setForeground(Qt::darkGreen);
1158 nickFormat.setFontWeight(QFont::Bold);
1159 nickFormat.setFontUnderline(true);
1160 nickFormat.setUnderlineColor(Qt::gray);
1161
1162 QTextCursor cursor(ui->textEdit->textCursor());
1163 cursor.movePosition(QTextCursor::End);
1164 QTextTableFormat tableFormat;
1165 tableFormat.setBorder(0);
1166 QTextTable *table = cursor.insertTable(1, 2, tableFormat);
1167 QString from = QString("%1 ").arg(msg.from().c_str());
1168 QTextTableCell fromCell = table->cellAt(0, 0);
1169 fromCell.setFormat(nickFormat);
1170 fromCell.firstCursorPosition().insertText(from);
1171
1172 time_t timestamp = msg.timestamp();
1173 printTimeInCell(table, timestamp);
1174
1175 QTextCursor nextCursor(ui->textEdit->textCursor());
1176 nextCursor.movePosition(QTextCursor::End);
1177 table = nextCursor.insertTable(1, 1, tableFormat);
1178 table->cellAt(0, 0).firstCursorPosition().insertText(QString::fromUtf8(msg.data().c_str()));
1179 if (!isHistory)
1180 {
1181 showMessage(from, QString::fromUtf8(msg.data().c_str()));
1182 }
1183 }
1184
1185 if (msg.type() == SyncDemo::ChatMessage::JOIN || msg.type() == SyncDemo::ChatMessage::LEAVE)
1186 {
1187 QTextCharFormat nickFormat;
1188 nickFormat.setForeground(Qt::gray);
1189 nickFormat.setFontWeight(QFont::Bold);
1190 nickFormat.setFontUnderline(true);
1191 nickFormat.setUnderlineColor(Qt::gray);
1192
1193 QTextCursor cursor(ui->textEdit->textCursor());
1194 cursor.movePosition(QTextCursor::End);
1195 QTextTableFormat tableFormat;
1196 tableFormat.setBorder(0);
1197 QTextTable *table = cursor.insertTable(1, 2, tableFormat);
1198 QString action;
1199 if (msg.type() == SyncDemo::ChatMessage::JOIN)
1200 {
1201 action = "enters room";
1202 }
1203 else
1204 {
1205 action = "leaves room";
1206 }
1207
1208 QString from = QString("%1 %2 ").arg(msg.from().c_str()).arg(action);
1209 QTextTableCell fromCell = table->cellAt(0, 0);
1210 fromCell.setFormat(nickFormat);
1211 fromCell.firstCursorPosition().insertText(from);
1212
1213 time_t timestamp = msg.timestamp();
1214 printTimeInCell(table, timestamp);
1215 }
1216
1217 QScrollBar *bar = ui->textEdit->verticalScrollBar();
1218 bar->setValue(bar->maximum());
1219}
1220
1221QString
1222ChatDialog::formatTime(time_t timestamp)
1223{
1224 struct tm *tm_time = localtime(&timestamp);
1225 int hour = tm_time->tm_hour;
1226 QString amOrPM;
1227 if (hour > 12)
1228 {
1229 hour -= 12;
1230 amOrPM = "PM";
1231 }
1232 else
1233 {
1234 amOrPM = "AM";
1235 if (hour == 0)
1236 {
1237 hour = 12;
1238 }
1239 }
1240
1241 char textTime[12];
1242 sprintf(textTime, "%d:%02d:%02d %s", hour, tm_time->tm_min, tm_time->tm_sec, amOrPM.toStdString().c_str());
1243 return QString(textTime);
1244}
1245
1246void
1247ChatDialog::printTimeInCell(QTextTable *table, time_t timestamp)
1248{
1249 QTextCharFormat timeFormat;
1250 timeFormat.setForeground(Qt::gray);
1251 timeFormat.setFontUnderline(true);
1252 timeFormat.setUnderlineColor(Qt::gray);
1253 QTextTableCell timeCell = table->cellAt(0, 1);
1254 timeCell.setFormat(timeFormat);
1255 timeCell.firstCursorPosition().insertText(formatTime(timestamp));
1256}
1257
1258void
1259ChatDialog::showMessage(QString from, QString data)
1260{
1261 if (!isActiveWindow())
1262 {
Yingdi Yu83eae842013-11-06 22:07:38 -08001263 trayIcon->showMessage(QString("Chatroom %1 has a new message").arg(m_user.getChatroom()), QString("<%1>: %2").arg(from).arg(data), QSystemTrayIcon::Information, 20000);
1264 trayIcon->setIcon(QIcon(":/images/note.png"));
Yingdi Yu7989eb22013-10-31 17:38:22 -07001265 }
1266}
1267
1268void
1269ChatDialog::sendMsg(SyncDemo::ChatMessage &msg)
1270{
1271 // send msg
1272 size_t size = msg.ByteSize();
1273 char *buf = new char[size];
1274 msg.SerializeToArray(buf, size);
1275 if (!msg.IsInitialized())
1276 {
1277 _LOG_DEBUG("Errrrr.. msg was not probally initialized "<<__FILE__ <<":"<<__LINE__<<". what is happening?");
1278 abort();
1279 }
1280 m_sock->publishData(m_user.getPrefix().toStdString(), m_session, buf, size, FRESHNESS);
1281
1282 delete buf;
1283
1284 m_lastMsgTime = time(NULL);
1285
1286 int nextSequence = m_sock->getNextSeq(m_user.getPrefix().toStdString(), m_session);
1287 Sync::MissingDataInfo mdi = {m_user.getPrefix().toStdString(), Sync::SeqNo(0), Sync::SeqNo(nextSequence - 1)};
1288 std::vector<Sync::MissingDataInfo> v;
1289 v.push_back(mdi);
1290 {
1291 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
1292 m_scene->processUpdate(v, m_sock->getRootDigest().c_str());
1293 m_scene->msgReceived(m_user.getPrefix(), m_user.getNick());
1294 }
1295}
1296
1297void
1298ChatDialog::openInviteListDialog()
1299{
1300 m_inviteListDialog->setInviteLabel(m_chatroomPrefix.toUri());
1301 m_inviteListDialog->show();
1302}
1303
1304void
1305ChatDialog::sendInvitationWrapper(QString invitee, bool isIntroducer)
1306{
Yingdi Yu76dd8002013-12-24 11:16:32 +08001307 ndn::Name inviteeNamespace(invitee.toStdString());
1308 ndn::ptr_lib::shared_ptr<ContactItem> inviteeItem = m_contactManager->getContact(inviteeNamespace);
Yingdi Yu7989eb22013-10-31 17:38:22 -07001309 sendInvitation(inviteeItem, isIntroducer);
1310}
1311
Yingdi Yu46948282013-11-06 18:43:31 -08001312void
1313ChatDialog::closeEvent(QCloseEvent *e)
1314{
Yingdi Yu702d6f12013-11-07 17:00:54 -08001315 if (trayIcon->isVisible())
1316 {
1317 QMessageBox::information(this, tr("Chronos"),
1318 tr("The program will keep running in the "
1319 "system tray. To terminate the program"
1320 "choose <b>Quit</b> in the context memu"
1321 "of the system tray entry."));
1322 hide();
1323 e->ignore();
1324 }
1325}
1326
1327void
1328ChatDialog::quit()
1329{
Yingdi Yu46948282013-11-06 18:43:31 -08001330 hide();
Yingdi Yu46948282013-11-06 18:43:31 -08001331 emit closeChatDialog(m_chatroomPrefix);
1332}
1333
1334
1335
Yingdi Yu7989eb22013-10-31 17:38:22 -07001336
Alexander Afanasyevb4b92292013-07-09 13:54:59 -07001337#if WAF
1338#include "chatdialog.moc"
1339#include "chatdialog.cpp.moc"
1340#endif