blob: 74b75c367540a815ac03fc1a13d316cfe9d09979 [file] [log] [blame]
Yingdi Yu348f5ea2014-03-01 14:47:25 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
2/*
3 * Copyright (c) 2013, Regents of the University of California
4 * Yingdi Yu
5 *
6 * BSD license, See the LICENSE file for more information
7 *
8 * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
9 * Alexander Afanasyev <alexander.afanasyev@ucla.edu>
10 * Yingdi Yu <yingdi@cs.ucla.edu>
11 */
12
13#include "chat-dialog.h"
14#include "ui_chat-dialog.h"
15
16#include <QScrollBar>
17#include <QMessageBox>
18#include <QCloseEvent>
19
20#ifndef Q_MOC_RUN
21#include <sync-intro-certificate.h>
22#include <boost/random/random_device.hpp>
23#include <boost/random/uniform_int_distribution.hpp>
24#include <ndn-cpp-dev/util/random.hpp>
25#include <cryptopp/hex.h>
26#include <cryptopp/files.h>
Yingdi Yuf4aaa8b2014-03-10 11:24:31 -070027#include <queue>
Yingdi Yu348f5ea2014-03-01 14:47:25 -080028#include "logging.h"
29#endif
30
Yingdi Yu348f5ea2014-03-01 14:47:25 -080031using namespace ndn;
Yingdi Yu17032f82014-03-25 15:48:23 -070032using ndn::shared_ptr;
Yingdi Yu348f5ea2014-03-01 14:47:25 -080033using namespace chronos;
34
35INIT_LOGGER("ChatDialog");
36
37static const int HELLO_INTERVAL = FRESHNESS * 3 / 4;
38static const uint8_t CHRONOS_RP_SEPARATOR[2] = {0xF0, 0x2E}; // %F0.
39
40Q_DECLARE_METATYPE(std::vector<Sync::MissingDataInfo> )
Yingdi Yu233a9722014-03-07 15:47:09 -080041Q_DECLARE_METATYPE(ndn::shared_ptr<const ndn::Data>)
Yingdi Yu348f5ea2014-03-01 14:47:25 -080042Q_DECLARE_METATYPE(ndn::Interest)
43Q_DECLARE_METATYPE(size_t)
44
45ChatDialog::ChatDialog(ContactManager* contactManager,
46 shared_ptr<Face> face,
47 const IdentityCertificate& myCertificate,
48 const Name& chatroomPrefix,
49 const Name& localPrefix,
Yingdi Yu17032f82014-03-25 15:48:23 -070050 const std::string& nick,
Yingdi Yu348f5ea2014-03-01 14:47:25 -080051 bool withSecurity,
52 QWidget* parent)
53 : QDialog(parent)
54 , ui(new Ui::ChatDialog)
55 , m_contactManager(contactManager)
56 , m_face(face)
57 , m_myCertificate(myCertificate)
58 , m_chatroomName(chatroomPrefix.get(-1).toEscapedString())
59 , m_chatroomPrefix(chatroomPrefix)
60 , m_localPrefix(localPrefix)
61 , m_useRoutablePrefix(false)
62 , m_nick(nick)
Yingdi Yua7876722014-03-25 14:46:55 -070063 , m_lastMsgTime(time::toUnixTimestamp(time::system_clock::now()).count())
Yingdi Yu348f5ea2014-03-01 14:47:25 -080064 , m_joined(false)
65 , m_sock(NULL)
Yingdi Yua7876722014-03-25 14:46:55 -070066 , m_session(static_cast<uint64_t>(time::toUnixTimestamp(time::system_clock::now()).count()))
Yingdi Yu348f5ea2014-03-01 14:47:25 -080067 , m_inviteListDialog(new InviteListDialog)
68{
69 qRegisterMetaType<std::vector<Sync::MissingDataInfo> >("std::vector<Sync::MissingDataInfo>");
Yingdi Yu233a9722014-03-07 15:47:09 -080070 qRegisterMetaType<ndn::shared_ptr<const ndn::Data> >("ndn.DataPtr");
Yingdi Yu348f5ea2014-03-01 14:47:25 -080071 qRegisterMetaType<ndn::Interest>("ndn.Interest");
72 qRegisterMetaType<size_t>("size_t");
73
74 m_scene = new DigestTreeScene(this);
Yingdi Yuf4aaa8b2014-03-10 11:24:31 -070075 m_trustScene = new TrustTreeScene(this);
Yingdi Yu348f5ea2014-03-01 14:47:25 -080076 m_rosterModel = new QStringListModel(this);
77 m_timer = new QTimer(this);
78
79 ui->setupUi(this);
Yingdi Yuf4aaa8b2014-03-10 11:24:31 -070080 ui->syncTreeViewer->setScene(m_scene);
Yingdi Yu348f5ea2014-03-01 14:47:25 -080081 m_scene->setSceneRect(m_scene->itemsBoundingRect());
Yingdi Yuf4aaa8b2014-03-10 11:24:31 -070082 ui->syncTreeViewer->hide();
83 ui->trustTreeViewer->setScene(m_trustScene);
84 m_trustScene->setSceneRect(m_trustScene->itemsBoundingRect());
85 ui->trustTreeViewer->hide();
Yingdi Yu348f5ea2014-03-01 14:47:25 -080086 ui->listView->setModel(m_rosterModel);
87
88 m_identity = IdentityCertificate::certificateNameToPublicKeyName(m_myCertificate.getName()).getPrefix(-1);
89 updatePrefix();
90 updateLabels();
91
92 m_scene->setCurrentPrefix(QString(m_localChatPrefix.toUri().c_str()));
93 m_scene->plot("Empty");
94
95 connect(ui->lineEdit, SIGNAL(returnPressed()),
96 this, SLOT(onReturnPressed()));
Yingdi Yuf4aaa8b2014-03-10 11:24:31 -070097 connect(ui->syncTreeButton, SIGNAL(pressed()),
98 this, SLOT(onSyncTreeButtonPressed()));
99 connect(ui->trustTreeButton, SIGNAL(pressed()),
100 this, SLOT(onTrustTreeButtonPressed()));
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800101 connect(m_scene, SIGNAL(replot()),
102 this, SLOT(onReplot()));
103 connect(m_scene, SIGNAL(rosterChanged(QStringList)),
104 this, SLOT(onRosterChanged(QStringList)));
105 connect(m_timer, SIGNAL(timeout()),
106 this, SLOT(onReplot()));
107
Yingdi Yu233a9722014-03-07 15:47:09 -0800108 connect(this, SIGNAL(processData(const ndn::shared_ptr<const ndn::Data>&, bool, bool)),
109 this, SLOT(onProcessData(const ndn::shared_ptr<const ndn::Data>&, bool, bool)));
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800110 connect(this, SIGNAL(processTreeUpdate(const std::vector<Sync::MissingDataInfo>)),
111 this, SLOT(onProcessTreeUpdate(const std::vector<Sync::MissingDataInfo>)));
Yingdi Yu233a9722014-03-07 15:47:09 -0800112 connect(this, SIGNAL(reply(const ndn::Interest&, const ndn::shared_ptr<const ndn::Data>&, size_t, bool)),
113 this, SLOT(onReply(const ndn::Interest&, const ndn::shared_ptr<const ndn::Data>&, size_t, bool)));
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800114 connect(this, SIGNAL(replyTimeout(const ndn::Interest&, size_t)),
115 this, SLOT(onReplyTimeout(const ndn::Interest&, size_t)));
Yingdi Yu233a9722014-03-07 15:47:09 -0800116 connect(this, SIGNAL(introCert(const ndn::Interest&, const ndn::shared_ptr<const ndn::Data>&)),
117 this, SLOT(onIntroCert(const ndn::Interest&, const ndn::shared_ptr<const ndn::Data>&)));
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800118 connect(this, SIGNAL(introCertTimeout(const ndn::Interest&, int, const QString&)),
119 this, SLOT(onIntroCertTimeout(const ndn::Interest&, int, const QString&)));
120
121 if(withSecurity)
122 {
123
124 m_invitationValidator = make_shared<chronos::ValidatorInvitation>();
125 m_dataRule = make_shared<SecRuleRelative>("([^<CHRONOCHAT-DATA>]*)<CHRONOCHAT-DATA><>",
126 "^([^<KEY>]*)<KEY>(<>*)<><ID-CERT>$",
127 "==", "\\1", "\\1", true);
128
129 ui->inviteButton->setEnabled(true);
Yingdi Yuf4aaa8b2014-03-10 11:24:31 -0700130 ui->trustTreeButton->setEnabled(true);
131
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800132 connect(ui->inviteButton, SIGNAL(clicked()),
133 this, SLOT(onInviteListDialogRequested()));
134 connect(m_inviteListDialog, SIGNAL(sendInvitation(const QString&)),
135 this, SLOT(onSendInvitation(const QString&)));
Yingdi Yu233a9722014-03-07 15:47:09 -0800136 connect(this, SIGNAL(waitForContactList()),
137 m_contactManager, SLOT(onWaitForContactList()));
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800138 connect(m_contactManager, SIGNAL(contactAliasListReady(const QStringList&)),
139 m_inviteListDialog, SLOT(onContactAliasListReady(const QStringList&)));
140 connect(m_contactManager, SIGNAL(contactIdListReady(const QStringList&)),
141 m_inviteListDialog, SLOT(onContactIdListReady(const QStringList&)));
142 }
143
144 initializeSync();
145}
146
147
148ChatDialog::~ChatDialog()
149{
150 if(m_certListPrefixId)
151 m_face->unsetInterestFilter(m_certListPrefixId);
152
153 if(m_certSinglePrefixId)
154 m_face->unsetInterestFilter(m_certSinglePrefixId);
155
156 if(m_sock != NULL)
157 {
158 sendLeave();
159 delete m_sock;
160 m_sock = NULL;
161 }
162}
163
164// public methods:
165void
166ChatDialog::addSyncAnchor(const Invitation& invitation)
167{
Yingdi Yu233a9722014-03-07 15:47:09 -0800168 _LOG_DEBUG("Add sync anchor from invation");
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800169 // Add inviter certificate as trust anchor.
170 m_sock->addParticipant(invitation.getInviterCertificate());
Yingdi Yuf4aaa8b2014-03-10 11:24:31 -0700171 plotTrustTree();
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800172
173 // Ask inviter for IntroCertificate
174 Name inviterNameSpace = IdentityCertificate::certificateNameToPublicKeyName(invitation.getInviterCertificate().getName()).getPrefix(-1);
175 fetchIntroCert(inviterNameSpace, invitation.getInviterRoutingPrefix());
176}
177
178void
Yingdi Yu17032f82014-03-25 15:48:23 -0700179ChatDialog::processTreeUpdateWrapper(const std::vector<Sync::MissingDataInfo>& v, Sync::SyncSocket *sock)
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800180{
181 emit processTreeUpdate(v);
182 _LOG_DEBUG("<<< Tree update signal emitted");
183}
184
185void
186ChatDialog::processDataWrapper(const shared_ptr<const Data>& data)
187{
Yingdi Yu233a9722014-03-07 15:47:09 -0800188 emit processData(data, true, false);
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800189 _LOG_DEBUG("<<< " << data->getName() << " fetched");
190}
191
192void
193ChatDialog::processDataNoShowWrapper(const shared_ptr<const Data>& data)
194{
Yingdi Yu233a9722014-03-07 15:47:09 -0800195 emit processData(data, false, false);
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800196}
197
198void
Yingdi Yu17032f82014-03-25 15:48:23 -0700199ChatDialog::processRemoveWrapper(std::string prefix)
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800200{
201 _LOG_DEBUG("Sync REMOVE signal received for prefix: " << prefix);
202}
203
204// protected methods:
205void
206ChatDialog::closeEvent(QCloseEvent *e)
207{
208 QMessageBox::information(this, tr("ChronoChat"),
209 tr("The chatroom will keep running in the "
210 "system tray. To close the chatroom, "
211 "choose <b>Close chatroom</b> in the "
212 "context memu of the system tray entry."));
213 hide();
214 e->ignore();
215}
216
217void
Yingdi Yu233a9722014-03-07 15:47:09 -0800218ChatDialog::changeEvent(QEvent *e)
219{
220 switch(e->type())
221 {
222 case QEvent::ActivationChange:
223 if (isActiveWindow())
224 {
225 emit resetIcon();
226 }
227 break;
228 default:
229 break;
230 }
231}
232
233void
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800234ChatDialog::resizeEvent(QResizeEvent *e)
235{
236 fitView();
237}
238
239void
240ChatDialog::showEvent(QShowEvent *e)
241{
242 fitView();
243}
244
245// private methods:
246void
247ChatDialog::updatePrefix()
248{
249 m_certListPrefix.clear();
250 m_certSinglePrefix.clear();
251 m_localChatPrefix.clear();
252 m_chatPrefix.clear();
253 m_chatPrefix.append(m_identity).append("CHRONOCHAT-DATA").append(m_chatroomName).append(getRandomString());
254 if(!m_localPrefix.isPrefixOf(m_identity))
255 {
256 m_useRoutablePrefix = true;
257 m_certListPrefix.append(m_localPrefix).append(CHRONOS_RP_SEPARATOR, 2);
258 m_certSinglePrefix.append(m_localPrefix).append(CHRONOS_RP_SEPARATOR, 2);
259 m_localChatPrefix.append(m_localPrefix).append(CHRONOS_RP_SEPARATOR, 2);
260 }
261 m_certListPrefix.append(m_identity).append("CHRONOCHAT-CERT-LIST").append(m_chatroomName);
262 m_certSinglePrefix.append(m_identity).append("CHRONOCHAT-CERT-SINGLE").append(m_chatroomName);
263 m_localChatPrefix.append(m_chatPrefix);
264
265 if(m_certListPrefixId)
266 m_face->unsetInterestFilter(m_certListPrefixId);
267 m_certListPrefixId = m_face->setInterestFilter (m_certListPrefix,
268 bind(&ChatDialog::onCertListInterest, this, _1, _2),
269 bind(&ChatDialog::onCertListRegisterFailed, this, _1, _2));
270
271 if(m_certSinglePrefixId)
272 m_face->unsetInterestFilter(m_certSinglePrefixId);
273 m_certSinglePrefixId = m_face->setInterestFilter (m_certSinglePrefix,
274 bind(&ChatDialog::onCertSingleInterest, this, _1, _2),
275 bind(&ChatDialog::onCertSingleRegisterFailed, this, _1, _2));
276}
277
278void
279ChatDialog::updateLabels()
280{
281 QString settingDisp = QString("Chatroom: %1").arg(QString::fromStdString(m_chatroomName));
282 ui->infoLabel->setStyleSheet("QLabel {color: #630; font-size: 16px; font: bold \"Verdana\";}");
283 ui->infoLabel->setText(settingDisp);
284 QString prefixDisp;
285 Name privatePrefix("/private/local");
286 if(privatePrefix.isPrefixOf(m_localChatPrefix))
287 {
288 prefixDisp =
289 QString("<Warning: no connection to hub or hub does not support prefix autoconfig.>\n <Prefix = %1>")
290 .arg(QString::fromStdString(m_localChatPrefix.toUri()));
291 ui->prefixLabel->setStyleSheet("QLabel {color: red; font-size: 12px; font: bold \"Verdana\";}");
292 }
293 else
294 {
295 prefixDisp = QString("<Prefix = %1>")
296 .arg(QString::fromStdString(m_localChatPrefix.toUri()));
297 ui->prefixLabel->setStyleSheet("QLabel {color: Green; font-size: 12px; font: bold \"Verdana\";}");
298 }
299 ui->prefixLabel->setText(prefixDisp);
300}
301
302void
303ChatDialog::initializeSync()
304{
305
306 m_sock = new Sync::SyncSocket(m_chatroomPrefix,
307 m_chatPrefix,
308 m_session,
309 m_useRoutablePrefix,
310 m_localPrefix,
311 m_face,
312 m_myCertificate,
313 m_dataRule,
314 bind(&ChatDialog::processTreeUpdateWrapper, this, _1, _2),
315 bind(&ChatDialog::processRemoveWrapper, this, _1));
316
317 usleep(100000);
318
319 QTimer::singleShot(600, this, SLOT(sendJoin()));
320 m_timer->start(FRESHNESS * 1000);
Yingdi Yuf4aaa8b2014-03-10 11:24:31 -0700321 disableSyncTreeDisplay();
322 QTimer::singleShot(2200, this, SLOT(enableSyncTreeDisplay()));
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800323}
324
325void
326ChatDialog::sendInvitation(shared_ptr<Contact> contact, bool isIntroducer)
327{
328 // Add invitee as a trust anchor.
329 m_invitationValidator->addTrustAnchor(contact->getPublicKeyName(),
330 contact->getPublicKey());
331
332 // Prepared an invitation interest without routable prefix.
333 Invitation invitation(contact->getNameSpace(),
334 m_chatroomName,
335 m_localPrefix,
336 m_myCertificate);
337 Interest tmpInterest(invitation.getUnsignedInterestName());
338 m_keyChain.sign(tmpInterest, m_myCertificate.getName());
339
340 // Get invitee's routable prefix (ideally it will do some DNS lookup, but we assume everyone use /ndn/broadcast
341 Name routablePrefix = getInviteeRoutablePrefix(contact->getNameSpace());
342
343 // Check if we need to prepend the routable prefix to the interest name.
344 bool requireRoutablePrefix = false;
345 Name interestName;
346 size_t routablePrefixOffset = 0;
347 if(!routablePrefix.isPrefixOf(tmpInterest.getName()))
348 {
349 interestName.append(routablePrefix).append(CHRONOS_RP_SEPARATOR, 2);
350 requireRoutablePrefix = true;
351 routablePrefixOffset = routablePrefix.size() + 1;
352 }
353 interestName.append(tmpInterest.getName());
354
355 // Send the invitation out
356 Interest interest(interestName);
357 interest.setMustBeFresh(true);
Yingdi Yu233a9722014-03-07 15:47:09 -0800358 _LOG_DEBUG("sendInvitation: " << interest.getName());
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800359 m_face->expressInterest(interest,
360 bind(&ChatDialog::replyWrapper, this, _1, _2, routablePrefixOffset, isIntroducer),
361 bind(&ChatDialog::replyTimeoutWrapper, this, _1, routablePrefixOffset));
362}
363
364void
365ChatDialog::replyWrapper(const Interest& interest,
366 Data& data,
367 size_t routablePrefixOffset,
368 bool isIntroducer)
369{
Yingdi Yu233a9722014-03-07 15:47:09 -0800370 _LOG_DEBUG("ChatDialog::replyWrapper");
371 emit reply(interest, data.shared_from_this(), routablePrefixOffset, isIntroducer);
372 _LOG_DEBUG("OK?");
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800373}
374
375void
376ChatDialog::replyTimeoutWrapper(const Interest& interest,
377 size_t routablePrefixOffset)
378{
Yingdi Yu233a9722014-03-07 15:47:09 -0800379 _LOG_DEBUG("ChatDialog::replyTimeoutWrapper");
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800380 emit replyTimeout(interest, routablePrefixOffset);
381}
382
383void
384ChatDialog::onReplyValidated(const shared_ptr<const Data>& data,
385 size_t inviteeRoutablePrefixOffset,
386 bool isIntroducer)
387{
388 if(data->getName().size() <= inviteeRoutablePrefixOffset)
389 {
390 Invitation invitation(data->getName());
391 invitationRejected(invitation.getInviteeNameSpace());
392 }
393 else
394 {
395 Name inviteePrefix;
396 inviteePrefix.wireDecode(data->getName().get(inviteeRoutablePrefixOffset).blockFromValue());
397 IdentityCertificate inviteeCert;
398 inviteeCert.wireDecode(data->getContent().blockFromValue());
399 invitationAccepted(inviteeCert, inviteePrefix, isIntroducer);
400 }
401}
402
403void
404ChatDialog::onReplyValidationFailed(const shared_ptr<const Data>& data,
Yingdi Yu17032f82014-03-25 15:48:23 -0700405 const std::string& failureInfo)
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800406{
407 _LOG_DEBUG("Invitation reply cannot be validated: " + failureInfo + " ==> " + data->getName().toUri());
408}
409
410void
411ChatDialog::invitationRejected(const Name& identity)
412{
413 QString msg = QString::fromStdString(identity.toUri()) + " rejected your invitation!";
414 emit inivationRejection(msg);
415}
416
417void
418ChatDialog::invitationAccepted(const IdentityCertificate& inviteeCert,
419 const Name& inviteePrefix,
420 bool isIntroducer)
421{
422 // Add invitee certificate as trust anchor.
423 m_sock->addParticipant(inviteeCert);
Yingdi Yuf4aaa8b2014-03-10 11:24:31 -0700424 plotTrustTree();
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800425
426 // Ask invitee for IntroCertificate.
427 Name inviteeNameSpace = IdentityCertificate::certificateNameToPublicKeyName(inviteeCert.getName()).getPrefix(-1);
428 fetchIntroCert(inviteeNameSpace, inviteePrefix);
429}
430
431void
432ChatDialog::fetchIntroCert(const Name& identity, const Name& prefix)
433{
434 Name interestName;
435
436 if(!prefix.isPrefixOf(identity))
437 interestName.append(prefix).append(CHRONOS_RP_SEPARATOR, 2);
438
439 interestName.append(identity)
440 .append("CHRONOCHAT-CERT-LIST")
441 .append(m_chatroomName)
442 .appendVersion();
443
444 Interest interest(interestName);
445 interest.setMustBeFresh(true);
446
447 m_face->expressInterest(interest,
448 bind(&ChatDialog::onIntroCertList, this, _1, _2),
449 bind(&ChatDialog::onIntroCertListTimeout, this, _1, 1,
450 "IntroCertList: " + interestName.toUri()));
451}
452
453void
454ChatDialog::onIntroCertList(const Interest& interest, const Data& data)
455{
456 Chronos::IntroCertListMsg introCertList;
457 if(!introCertList.ParseFromArray(data.getContent().value(), data.getContent().value_size()))
458 return;
459
460 for(int i = 0; i < introCertList.certname_size(); i++)
461 {
462 Name certName(introCertList.certname(i));
463 Interest interest(certName);
464 interest.setMustBeFresh(true);
465
Yingdi Yu233a9722014-03-07 15:47:09 -0800466 _LOG_DEBUG("onIntroCertList: to fetch " << certName);
467
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800468 m_face->expressInterest(interest,
469 bind(&ChatDialog::introCertWrapper, this, _1, _2),
470 bind(&ChatDialog::introCertTimeoutWrapper, this, _1, 0,
471 QString("IntroCert: %1").arg(introCertList.certname(i).c_str())));
472 }
473}
474
475void
Yingdi Yu17032f82014-03-25 15:48:23 -0700476ChatDialog::onIntroCertListTimeout(const Interest& interest, int retry, const std::string& msg)
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800477{
478 if(retry > 0)
479 m_face->expressInterest(interest,
480 bind(&ChatDialog::onIntroCertList, this, _1, _2),
481 bind(&ChatDialog::onIntroCertListTimeout, this, _1, retry - 1, msg));
482 else
483 _LOG_DEBUG(msg << " TIMEOUT!");
484}
485
486void
487ChatDialog::introCertWrapper(const Interest& interest, Data& data)
488{
Yingdi Yu233a9722014-03-07 15:47:09 -0800489 emit introCert(interest, data.shared_from_this());
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800490}
491
492void
493ChatDialog::introCertTimeoutWrapper(const Interest& interest, int retry, const QString& msg)
494{
495 emit introCertTimeout(interest, retry, msg);
496}
497
498void
499ChatDialog::onCertListInterest(const Name& prefix, const ndn::Interest& interest)
500{
Yingdi Yu17032f82014-03-25 15:48:23 -0700501 std::vector<Name> certNameList;
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800502 m_sock->getIntroCertNames(certNameList);
503
504 Chronos::IntroCertListMsg msg;
505
Yingdi Yu17032f82014-03-25 15:48:23 -0700506 std::vector<Name>::const_iterator it = certNameList.begin();
507 std::vector<Name>::const_iterator end = certNameList.end();
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800508 for(; it != end; it++)
509 {
510 Name certName;
511 certName.append(m_certSinglePrefix).append(*it);
512 msg.add_certname(certName.toUri());
513 }
514 OBufferStream os;
515 msg.SerializeToOstream(&os);
516
517 Data data(interest.getName());
518 data.setContent(os.buf());
519 m_keyChain.sign(data, m_myCertificate.getName());
520
521 m_face->put(data);
522}
523
524void
Yingdi Yu17032f82014-03-25 15:48:23 -0700525ChatDialog::onCertListRegisterFailed(const Name& prefix, const std::string& msg)
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800526{
527 _LOG_DEBUG("ChatDialog::onCertListRegisterFailed failed: " + msg);
528}
529
530void
531ChatDialog::onCertSingleInterest(const Name& prefix, const ndn::Interest& interest)
532{
533 try
534 {
535 Name certName = interest.getName().getSubName(prefix.size());
536 const Sync::IntroCertificate& introCert = m_sock->getIntroCertificate(certName);
537 Data data(interest.getName());
538 data.setContent(introCert.wireEncode());
Yingdi Yu233a9722014-03-07 15:47:09 -0800539 m_keyChain.sign(data, m_myCertificate.getName());
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800540 m_face->put(data);
541 }
542 catch(Sync::SyncSocket::Error& e)
543 {
544 return;
545 }
546}
547
548void
Yingdi Yu17032f82014-03-25 15:48:23 -0700549ChatDialog::onCertSingleRegisterFailed(const Name& prefix, const std::string& msg)
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800550{
551 _LOG_DEBUG("ChatDialog::onCertListRegisterFailed failed: " + msg);
552}
553
554void
555ChatDialog::sendMsg(SyncDemo::ChatMessage &msg)
556{
557 // send msg
558 OBufferStream os;
559 msg.SerializeToOstream(&os);
560
561 if (!msg.IsInitialized())
562 {
563 _LOG_DEBUG("Errrrr.. msg was not probally initialized "<<__FILE__ <<":"<<__LINE__<<". what is happening?");
564 abort();
565 }
Yingdi Yu233a9722014-03-07 15:47:09 -0800566 uint64_t nextSequence = m_sock->getNextSeq();
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800567 m_sock->publishData(os.buf()->buf(), os.buf()->size(), FRESHNESS);
568
Yingdi Yua7876722014-03-25 14:46:55 -0700569 m_lastMsgTime = time::toUnixTimestamp(time::system_clock::now()).count();
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800570
Yingdi Yu233a9722014-03-07 15:47:09 -0800571 Sync::MissingDataInfo mdi = {m_localChatPrefix.toUri(), Sync::SeqNo(0), Sync::SeqNo(nextSequence)};
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800572 std::vector<Sync::MissingDataInfo> v;
573 v.push_back(mdi);
574 {
575 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
576 m_scene->processUpdate(v, m_sock->getRootDigest().c_str());
577 m_scene->msgReceived(QString::fromStdString(m_localChatPrefix.toUri()),
578 QString::fromStdString(m_nick));
579 }
580}
581
Yingdi Yuf4aaa8b2014-03-10 11:24:31 -0700582void ChatDialog::disableSyncTreeDisplay()
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800583{
Yingdi Yuf4aaa8b2014-03-10 11:24:31 -0700584 ui->syncTreeButton->setEnabled(false);
585 ui->syncTreeViewer->hide();
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800586 fitView();
587}
588
589void
590ChatDialog::appendMessage(const SyncDemo::ChatMessage msg, bool isHistory)
591{
592 boost::recursive_mutex::scoped_lock lock(m_msgMutex);
593
594 if (msg.type() == SyncDemo::ChatMessage::CHAT)
595 {
596
597 if (!msg.has_data())
598 {
599 return;
600 }
601
602 if (msg.from().empty() || msg.data().empty())
603 {
604 return;
605 }
606
607 if (!msg.has_timestamp())
608 {
609 return;
610 }
611
612 // if (m_history.size() == MAX_HISTORY_ENTRY)
613 // {
614 // m_history.dequeue();
615 // }
616
617 // m_history.enqueue(msg);
618
619 QTextCharFormat nickFormat;
620 nickFormat.setForeground(Qt::darkGreen);
621 nickFormat.setFontWeight(QFont::Bold);
622 nickFormat.setFontUnderline(true);
623 nickFormat.setUnderlineColor(Qt::gray);
624
625 QTextCursor cursor(ui->textEdit->textCursor());
626 cursor.movePosition(QTextCursor::End);
627 QTextTableFormat tableFormat;
628 tableFormat.setBorder(0);
629 QTextTable *table = cursor.insertTable(1, 2, tableFormat);
630 QString from = QString("%1 ").arg(msg.from().c_str());
631 QTextTableCell fromCell = table->cellAt(0, 0);
632 fromCell.setFormat(nickFormat);
633 fromCell.firstCursorPosition().insertText(from);
634
635 time_t timestamp = msg.timestamp();
636 printTimeInCell(table, timestamp);
637
638 QTextCursor nextCursor(ui->textEdit->textCursor());
639 nextCursor.movePosition(QTextCursor::End);
640 table = nextCursor.insertTable(1, 1, tableFormat);
641 table->cellAt(0, 0).firstCursorPosition().insertText(QString::fromUtf8(msg.data().c_str()));
642 if (!isHistory)
643 {
644 showMessage(from, QString::fromUtf8(msg.data().c_str()));
645 }
646 }
647
648 if (msg.type() == SyncDemo::ChatMessage::JOIN || msg.type() == SyncDemo::ChatMessage::LEAVE)
649 {
650 QTextCharFormat nickFormat;
651 nickFormat.setForeground(Qt::gray);
652 nickFormat.setFontWeight(QFont::Bold);
653 nickFormat.setFontUnderline(true);
654 nickFormat.setUnderlineColor(Qt::gray);
655
656 QTextCursor cursor(ui->textEdit->textCursor());
657 cursor.movePosition(QTextCursor::End);
658 QTextTableFormat tableFormat;
659 tableFormat.setBorder(0);
660 QTextTable *table = cursor.insertTable(1, 2, tableFormat);
661 QString action;
662 if (msg.type() == SyncDemo::ChatMessage::JOIN)
663 {
664 action = "enters room";
665 }
666 else
667 {
668 action = "leaves room";
669 }
670
671 QString from = QString("%1 %2 ").arg(msg.from().c_str()).arg(action);
672 QTextTableCell fromCell = table->cellAt(0, 0);
673 fromCell.setFormat(nickFormat);
674 fromCell.firstCursorPosition().insertText(from);
675
676 time_t timestamp = msg.timestamp();
677 printTimeInCell(table, timestamp);
678 }
679
680 QScrollBar *bar = ui->textEdit->verticalScrollBar();
681 bar->setValue(bar->maximum());
682}
683
684void
685ChatDialog::processRemove(QString prefix)
686{
687 _LOG_DEBUG("<<< remove node for prefix" << prefix.toStdString());
688
689 bool removed = m_scene->removeNode(prefix);
690 if (removed)
691 {
692 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
693 m_scene->plot(m_sock->getRootDigest().c_str());
694 }
695}
696
697Name
698ChatDialog::getInviteeRoutablePrefix(const Name& invitee)
699{
700 return ndn::Name("/ndn/broadcast");
701}
702
703void
704ChatDialog::formChatMessage(const QString &text, SyncDemo::ChatMessage &msg) {
705 msg.set_from(m_nick);
706 msg.set_to(m_chatroomName);
707 msg.set_data(text.toStdString());
Yingdi Yua7876722014-03-25 14:46:55 -0700708 int32_t seconds = static_cast<int32_t>(time::toUnixTimestamp(time::system_clock::now()).count()/1000000000);
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800709 msg.set_timestamp(seconds);
710 msg.set_type(SyncDemo::ChatMessage::CHAT);
711}
712
713void
714ChatDialog::formControlMessage(SyncDemo::ChatMessage &msg, SyncDemo::ChatMessage::ChatMessageType type)
715{
716 msg.set_from(m_nick);
717 msg.set_to(m_chatroomName);
Yingdi Yua7876722014-03-25 14:46:55 -0700718 int32_t seconds = static_cast<int32_t>(time::toUnixTimestamp(time::system_clock::now()).count()/1000000000);
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800719 msg.set_timestamp(seconds);
720 msg.set_type(type);
721}
722
723QString
724ChatDialog::formatTime(time_t timestamp)
725{
726 struct tm *tm_time = localtime(&timestamp);
727 int hour = tm_time->tm_hour;
728 QString amOrPM;
729 if (hour > 12)
730 {
731 hour -= 12;
732 amOrPM = "PM";
733 }
734 else
735 {
736 amOrPM = "AM";
737 if (hour == 0)
738 {
739 hour = 12;
740 }
741 }
742
743 char textTime[12];
744 sprintf(textTime, "%d:%02d:%02d %s", hour, tm_time->tm_min, tm_time->tm_sec, amOrPM.toStdString().c_str());
745 return QString(textTime);
746}
747
748void
749ChatDialog::printTimeInCell(QTextTable *table, time_t timestamp)
750{
751 QTextCharFormat timeFormat;
752 timeFormat.setForeground(Qt::gray);
753 timeFormat.setFontUnderline(true);
754 timeFormat.setUnderlineColor(Qt::gray);
755 QTextTableCell timeCell = table->cellAt(0, 1);
756 timeCell.setFormat(timeFormat);
757 timeCell.firstCursorPosition().insertText(formatTime(timestamp));
758}
759
Yingdi Yu17032f82014-03-25 15:48:23 -0700760std::string
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800761ChatDialog::getRandomString()
762{
763 uint32_t r = random::generateWord32();
Yingdi Yu17032f82014-03-25 15:48:23 -0700764 std::stringstream ss;
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800765 {
766 using namespace CryptoPP;
767 StringSource(reinterpret_cast<uint8_t*>(&r), 4, true,
768 new HexEncoder(new FileSink(ss), false));
769
770 }
771
772 return ss.str();
773}
774
775void
776ChatDialog::showMessage(const QString& from, const QString& data)
777{
778 if (!isActiveWindow())
779 emit showChatMessage(QString::fromStdString(m_chatroomName),
780 from, data);
781}
782
783void
784ChatDialog::fitView()
785{
786 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
787 QRectF rect = m_scene->itemsBoundingRect();
788 m_scene->setSceneRect(rect);
Yingdi Yuf4aaa8b2014-03-10 11:24:31 -0700789 ui->syncTreeViewer->fitInView(m_scene->itemsBoundingRect(), Qt::KeepAspectRatio);
790
791 QRectF trustRect = m_trustScene->itemsBoundingRect();
792 m_trustScene->setSceneRect(trustRect);
793 ui->trustTreeViewer->fitInView(m_trustScene->itemsBoundingRect(), Qt::KeepAspectRatio);
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800794}
795
796void
797ChatDialog::summonReaper()
798{
799 Sync::SyncLogic &logic = m_sock->getLogic ();
Yingdi Yu17032f82014-03-25 15:48:23 -0700800 std::map<std::string, bool> branches = logic.getBranchPrefixes();
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800801 QMap<QString, DisplayUserPtr> roster = m_scene->getRosterFull();
802
803 m_zombieList.clear();
804
805 QMapIterator<QString, DisplayUserPtr> it(roster);
Yingdi Yu17032f82014-03-25 15:48:23 -0700806 std::map<std::string, bool>::iterator mapIt;
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800807 while(it.hasNext())
808 {
809 it.next();
810 DisplayUserPtr p = it.value();
811 if (p != DisplayUserNullPtr)
812 {
813 mapIt = branches.find(p->getPrefix().toStdString());
814 if (mapIt != branches.end())
815 {
816 mapIt->second = true;
817 }
818 }
819 }
820
821 for (mapIt = branches.begin(); mapIt != branches.end(); ++mapIt)
822 {
823 // this is zombie. all active users should have been marked true
824 if (! mapIt->second)
825 {
826 m_zombieList.append(mapIt->first.c_str());
827 }
828 }
829
830 m_zombieIndex = 0;
831
832 // start reaping
833 reap();
834}
835
Yingdi Yuf4aaa8b2014-03-10 11:24:31 -0700836void
837ChatDialog::getTree(TrustTreeNodeList& nodeList)
838{
Yingdi Yu17032f82014-03-25 15:48:23 -0700839 typedef std::map<Name, shared_ptr<TrustTreeNode> > NodeMap;
Yingdi Yuf4aaa8b2014-03-10 11:24:31 -0700840
Yingdi Yu17032f82014-03-25 15:48:23 -0700841 std::vector<Name> certNameList;
Yingdi Yuf4aaa8b2014-03-10 11:24:31 -0700842 NodeMap nodeMap;
843
844 m_sock->getIntroCertNames(certNameList);
845
Yingdi Yu17032f82014-03-25 15:48:23 -0700846 std::vector<Name>::const_iterator it = certNameList.begin();
847 std::vector<Name>::const_iterator end = certNameList.end();
Yingdi Yuf4aaa8b2014-03-10 11:24:31 -0700848 for(; it != end; it++)
849 {
850 Name introducerCertName;
851 Name introduceeCertName;
852
853 introducerCertName.wireDecode(it->get(-2).blockFromValue());
854 introduceeCertName.wireDecode(it->get(-3).blockFromValue());
855
856 Name introducerName = IdentityCertificate::certificateNameToPublicKeyName(introducerCertName).getPrefix(-1);
857 Name introduceeName = IdentityCertificate::certificateNameToPublicKeyName(introduceeCertName).getPrefix(-1);
858
859 NodeMap::iterator introducerIt = nodeMap.find(introducerName);
860 if(introducerIt == nodeMap.end())
861 {
862 shared_ptr<TrustTreeNode> introducerNode(new TrustTreeNode(introducerName));
863 nodeMap[introducerName] = introducerNode;
864 }
865 shared_ptr<TrustTreeNode> erNode = nodeMap[introducerName];
866
867 NodeMap::iterator introduceeIt = nodeMap.find(introduceeName);
868 if(introduceeIt == nodeMap.end())
869 {
870 shared_ptr<TrustTreeNode> introduceeNode(new TrustTreeNode(introduceeName));
871 nodeMap[introduceeName] = introduceeNode;
872 }
873 shared_ptr<TrustTreeNode> eeNode = nodeMap[introduceeName];
874
875 erNode->addIntroducee(eeNode);
876 eeNode->addIntroducer(erNode);
877 }
878
879 nodeList.clear();
Yingdi Yu17032f82014-03-25 15:48:23 -0700880 std::queue<shared_ptr<TrustTreeNode> > nodeQueue;
Yingdi Yuf4aaa8b2014-03-10 11:24:31 -0700881
882 NodeMap::iterator nodeIt = nodeMap.find(m_identity);
883 if(nodeIt == nodeMap.end())
884 return;
885
886 nodeQueue.push(nodeIt->second);
887 nodeIt->second->setLevel(0);
888 while(!nodeQueue.empty())
889 {
890 shared_ptr<TrustTreeNode>& node = nodeQueue.front();
891 node->setVisited();
892
893 TrustTreeNodeList& introducees = node->getIntroducees();
894 TrustTreeNodeList::iterator eeIt = introducees.begin();
895 TrustTreeNodeList::iterator eeEnd = introducees.end();
896
897 for(; eeIt != eeEnd; eeIt++)
898 {
899 _LOG_DEBUG("introducee: " << (*eeIt)->name() << " visited: " << boolalpha << (*eeIt)->visited());
900 if(!(*eeIt)->visited())
901 {
902 nodeQueue.push(*eeIt);
903 (*eeIt)->setLevel(node->level()+1);
904 }
905 }
906
907 nodeList.push_back(node);
908 nodeQueue.pop();
909 }
910}
911
912void
913ChatDialog::plotTrustTree()
914{
915 TrustTreeNodeList nodeList;
916
917 getTree(nodeList);
918 {
919 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
920 m_trustScene->plotTrustTree(nodeList);
921 fitView();
922 }
923}
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800924
925// public slots:
926void
927ChatDialog::onLocalPrefixUpdated(const QString& localPrefix)
928{
929 Name newLocalPrefix(localPrefix.toStdString());
930 if(!newLocalPrefix.empty() && newLocalPrefix != m_localPrefix)
931 {
932 // Update localPrefix
933 m_localPrefix = newLocalPrefix;
934
935 updatePrefix();
936 updateLabels();
937 m_scene->setCurrentPrefix(QString(m_localChatPrefix.toUri().c_str()));
938
939 if(m_sock != NULL)
940 {
941 {
942 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
943 m_scene->clearAll();
944 m_scene->plot("Empty");
945 }
946
947 ui->textEdit->clear();
948
949 if (m_joined)
950 {
951 sendLeave();
952 }
953
954 delete m_sock;
955 m_sock = NULL;
956
957 usleep(100000);
958 m_sock = new Sync::SyncSocket(m_chatroomPrefix,
959 m_chatPrefix,
960 m_session,
961 m_useRoutablePrefix,
962 m_localPrefix,
963 m_face,
964 m_myCertificate,
965 m_dataRule,
966 bind(&ChatDialog::processTreeUpdateWrapper, this, _1, _2),
967 bind(&ChatDialog::processRemoveWrapper, this, _1));
968 usleep(100000);
969 QTimer::singleShot(600, this, SLOT(sendJoin()));
970 m_timer->start(FRESHNESS * 1000);
Yingdi Yuf4aaa8b2014-03-10 11:24:31 -0700971 disableSyncTreeDisplay();
972 QTimer::singleShot(2200, this, SLOT(enableSyncTreeDisplay()));
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800973 }
974 else
975 initializeSync();
976 }
977 else
978 if (m_sock == NULL)
979 initializeSync();
980
981 fitView();
982}
983
984void
985ChatDialog::onClose()
986{
987 hide();
988 emit closeChatDialog(QString::fromStdString(m_chatroomName));
989}
990
991
992// private slots:
993void
994ChatDialog::onReturnPressed()
995{
996 QString text = ui->lineEdit->text();
997 if (text.isEmpty())
998 return;
999
1000 ui->lineEdit->clear();
1001
1002 if (text.startsWith("boruoboluomi"))
1003 {
1004 summonReaper ();
1005 // reapButton->show();
1006 fitView();
1007 return;
1008 }
1009
1010 if (text.startsWith("minimanihong"))
1011 {
1012 // reapButton->hide();
1013 fitView();
1014 return;
1015 }
1016
1017 SyncDemo::ChatMessage msg;
1018 formChatMessage(text, msg);
1019
1020 appendMessage(msg);
1021
1022 sendMsg(msg);
1023
1024 fitView();
1025}
1026
1027void
Yingdi Yuf4aaa8b2014-03-10 11:24:31 -07001028ChatDialog::onSyncTreeButtonPressed()
Yingdi Yu348f5ea2014-03-01 14:47:25 -08001029{
Yingdi Yuf4aaa8b2014-03-10 11:24:31 -07001030 if (ui->syncTreeViewer->isVisible())
Yingdi Yu348f5ea2014-03-01 14:47:25 -08001031 {
Yingdi Yuf4aaa8b2014-03-10 11:24:31 -07001032 ui->syncTreeViewer->hide();
1033 ui->syncTreeButton->setText("Show ChronoSync Tree");
Yingdi Yu348f5ea2014-03-01 14:47:25 -08001034 }
1035 else
1036 {
Yingdi Yuf4aaa8b2014-03-10 11:24:31 -07001037 ui->syncTreeViewer->show();
1038 ui->syncTreeButton->setText("Hide ChronoSync Tree");
1039 }
1040
1041 fitView();
1042}
1043
1044void
1045ChatDialog::onTrustTreeButtonPressed()
1046{
1047 if (ui->trustTreeViewer->isVisible())
1048 {
1049 ui->trustTreeViewer->hide();
1050 ui->trustTreeButton->setText("Show Trust Tree");
1051 }
1052 else
1053 {
1054 ui->trustTreeViewer->show();
1055 ui->trustTreeButton->setText("Hide Trust Tree");
Yingdi Yu348f5ea2014-03-01 14:47:25 -08001056 }
1057
1058 fitView();
1059}
1060
1061void
Yingdi Yu233a9722014-03-07 15:47:09 -08001062ChatDialog::onProcessData(const shared_ptr<const Data>& data, bool show, bool isHistory)
Yingdi Yu348f5ea2014-03-01 14:47:25 -08001063{
1064 SyncDemo::ChatMessage msg;
1065 bool corrupted = false;
Yingdi Yu233a9722014-03-07 15:47:09 -08001066 if (!msg.ParseFromArray(data->getContent().value(), data->getContent().value_size()))
Yingdi Yu348f5ea2014-03-01 14:47:25 -08001067 {
Yingdi Yu233a9722014-03-07 15:47:09 -08001068 _LOG_DEBUG("Errrrr.. Can not parse msg with name: " << data->getName() << ". what is happening?");
Yingdi Yu348f5ea2014-03-01 14:47:25 -08001069 // nasty stuff: as a remedy, we'll form some standard msg for inparsable msgs
1070 msg.set_from("inconnu");
1071 msg.set_type(SyncDemo::ChatMessage::OTHER);
1072 corrupted = true;
1073 }
1074
1075 // display msg received from network
1076 // we have to do so; this function is called by ccnd thread
1077 // so if we call appendMsg directly
1078 // Qt crash as "QObject: Cannot create children for a parent that is in a different thread"
1079 // the "cannonical" way to is use signal-slot
1080 if (show && !corrupted)
1081 {
1082 appendMessage(msg, isHistory);
1083 }
1084
1085 if (!isHistory)
1086 {
1087 // update the tree view
Yingdi Yuf4aaa8b2014-03-10 11:24:31 -07001088 std::string prefix = data->getName().getPrefix(-2).toUri();
Yingdi Yu348f5ea2014-03-01 14:47:25 -08001089 _LOG_DEBUG("<<< updating scene for" << prefix << ": " << msg.from());
1090 if (msg.type() == SyncDemo::ChatMessage::LEAVE)
1091 {
1092 processRemove(prefix.c_str());
1093 }
1094 else
1095 {
1096 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
1097 m_scene->msgReceived(prefix.c_str(), msg.from().c_str());
1098 }
1099 }
1100 fitView();
1101}
1102
1103void
Yingdi Yu17032f82014-03-25 15:48:23 -07001104ChatDialog::onProcessTreeUpdate(const std::vector<Sync::MissingDataInfo>& v)
Yingdi Yu348f5ea2014-03-01 14:47:25 -08001105{
1106 _LOG_DEBUG("<<< processing Tree Update");
1107
1108 if (v.empty())
1109 {
1110 return;
1111 }
1112
1113 // reflect the changes on digest tree
1114 {
1115 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
1116 m_scene->processUpdate(v, m_sock->getRootDigest().c_str());
1117 }
1118
1119 int n = v.size();
1120 int totalMissingPackets = 0;
1121 for (int i = 0; i < n; i++)
1122 {
1123 totalMissingPackets += v[i].high.getSeq() - v[i].low.getSeq() + 1;
1124 }
1125
1126 for (int i = 0; i < n; i++)
1127 {
1128 if (totalMissingPackets < 4)
1129 {
1130 for (Sync::SeqNo seq = v[i].low; seq <= v[i].high; ++seq)
1131 {
1132 m_sock->fetchData(v[i].prefix, seq, bind(&ChatDialog::processDataWrapper, this, _1), 2);
1133 _LOG_DEBUG("<<< Fetching " << v[i].prefix << "/" <<seq.getSession() <<"/" << seq.getSeq());
1134 }
1135 }
1136 else
1137 {
1138 m_sock->fetchData(v[i].prefix, v[i].high, bind(&ChatDialog::processDataNoShowWrapper, this, _1), 2);
1139 }
1140 }
1141 // adjust the view
1142 fitView();
1143}
1144
1145void
1146ChatDialog::onReplot()
1147{
1148 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
1149 m_scene->plot(m_sock->getRootDigest().c_str());
1150 fitView();
1151}
1152
1153void
1154ChatDialog::onRosterChanged(QStringList staleUserList)
1155{
1156 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
1157 QStringList rosterList = m_scene->getRosterList();
1158 m_rosterModel->setStringList(rosterList);
1159 QString user;
1160 QStringListIterator it(staleUserList);
1161 while(it.hasNext())
1162 {
1163 std::string nick = it.next().toStdString();
1164 if (nick.empty())
1165 continue;
1166
1167 SyncDemo::ChatMessage msg;
1168 formControlMessage(msg, SyncDemo::ChatMessage::LEAVE);
1169 msg.set_from(nick);
1170 appendMessage(msg);
1171 }
Yingdi Yuf4aaa8b2014-03-10 11:24:31 -07001172 plotTrustTree();
Yingdi Yu348f5ea2014-03-01 14:47:25 -08001173}
1174
1175void
1176ChatDialog::onInviteListDialogRequested()
1177{
Yingdi Yu233a9722014-03-07 15:47:09 -08001178 emit waitForContactList();
Yingdi Yu348f5ea2014-03-01 14:47:25 -08001179 m_inviteListDialog->setInviteLabel(m_chatroomPrefix.toUri());
1180 m_inviteListDialog->show();
1181}
1182
1183void
1184ChatDialog::sendJoin()
1185{
1186 m_joined = true;
1187 SyncDemo::ChatMessage msg;
1188 formControlMessage(msg, SyncDemo::ChatMessage::JOIN);
1189 sendMsg(msg);
1190 boost::random::random_device rng;
1191 boost::random::uniform_int_distribution<> uniform(1, FRESHNESS / 5 * 1000);
1192 m_randomizedInterval = HELLO_INTERVAL * 1000 + uniform(rng);
1193 QTimer::singleShot(m_randomizedInterval, this, SLOT(sendHello()));
1194}
1195
1196void
1197ChatDialog::sendHello()
1198{
Yingdi Yua7876722014-03-25 14:46:55 -07001199 int64_t now = time::toUnixTimestamp(time::system_clock::now()).count();
Yingdi Yu348f5ea2014-03-01 14:47:25 -08001200 int elapsed = (now - m_lastMsgTime) / 1000000000;
1201 if (elapsed >= m_randomizedInterval / 1000)
1202 {
1203 SyncDemo::ChatMessage msg;
1204 formControlMessage(msg, SyncDemo::ChatMessage::HELLO);
1205 sendMsg(msg);
1206 boost::random::random_device rng;
1207 boost::random::uniform_int_distribution<> uniform(1, FRESHNESS / 5 * 1000);
1208 m_randomizedInterval = HELLO_INTERVAL * 1000 + uniform(rng);
1209 QTimer::singleShot(m_randomizedInterval, this, SLOT(sendHello()));
1210 }
1211 else
1212 {
1213 QTimer::singleShot((m_randomizedInterval - elapsed * 1000), this, SLOT(sendHello()));
1214 }
1215}
1216
1217void
1218ChatDialog::sendLeave()
1219{
1220 SyncDemo::ChatMessage msg;
1221 formControlMessage(msg, SyncDemo::ChatMessage::LEAVE);
1222 sendMsg(msg);
1223 usleep(500000);
1224 m_sock->leave();
1225 usleep(5000);
1226 m_joined = false;
1227 _LOG_DEBUG("Sync REMOVE signal sent");
1228}
1229
Yingdi Yuf4aaa8b2014-03-10 11:24:31 -07001230void ChatDialog::enableSyncTreeDisplay()
Yingdi Yu348f5ea2014-03-01 14:47:25 -08001231{
Yingdi Yuf4aaa8b2014-03-10 11:24:31 -07001232 ui->syncTreeButton->setEnabled(true);
Yingdi Yu348f5ea2014-03-01 14:47:25 -08001233 // treeViewer->show();
1234 // fitView();
1235}
1236
1237void
1238ChatDialog::reap()
1239{
1240 if (m_zombieIndex < m_zombieList.size())
1241 {
Yingdi Yu17032f82014-03-25 15:48:23 -07001242 std::string prefix = m_zombieList.at(m_zombieIndex).toStdString();
Yingdi Yu348f5ea2014-03-01 14:47:25 -08001243 m_sock->remove(prefix);
1244 _LOG_DEBUG("Reaped: prefix = " << prefix);
1245 m_zombieIndex++;
1246 // reap again in 10 seconds
1247 QTimer::singleShot(10000, this, SLOT(reap()));
1248 }
1249}
1250
1251void
1252ChatDialog::onSendInvitation(QString invitee)
1253{
1254 Name inviteeNamespace(invitee.toStdString());
1255 shared_ptr<Contact> inviteeItem = m_contactManager->getContact(inviteeNamespace);
1256 sendInvitation(inviteeItem, true);
1257}
1258
1259void
1260ChatDialog::onReply(const Interest& interest,
Yingdi Yu233a9722014-03-07 15:47:09 -08001261 const shared_ptr<const Data>& data,
Yingdi Yu348f5ea2014-03-01 14:47:25 -08001262 size_t routablePrefixOffset,
1263 bool isIntroducer)
1264{
1265 OnDataValidated onValidated = bind(&ChatDialog::onReplyValidated,
1266 this, _1,
1267 interest.getName().size()-routablePrefixOffset, //RoutablePrefix will be removed before data is passed to the validator
1268 isIntroducer);
1269
1270 OnDataValidationFailed onFailed = bind(&ChatDialog::onReplyValidationFailed,
1271 this, _1, _2);
1272
1273 if(routablePrefixOffset > 0)
1274 {
1275 // It is an encapsulated packet, we only validate the inner packet.
Yingdi Yu233a9722014-03-07 15:47:09 -08001276 shared_ptr<Data> innerData = make_shared<Data>();
1277 innerData->wireDecode(data->getContent().blockFromValue());
1278 m_invitationValidator->validate(*innerData, onValidated, onFailed);
Yingdi Yu348f5ea2014-03-01 14:47:25 -08001279 }
1280 else
Yingdi Yu233a9722014-03-07 15:47:09 -08001281 m_invitationValidator->validate(*data, onValidated, onFailed);
Yingdi Yu348f5ea2014-03-01 14:47:25 -08001282}
1283
1284void
1285ChatDialog::onReplyTimeout(const Interest& interest,
1286 size_t routablePrefixOffset)
1287{
1288 Name interestName;
1289 if(routablePrefixOffset > 0)
1290 interestName = interest.getName().getSubName(routablePrefixOffset);
1291 else
1292 interestName = interest.getName();
1293
1294 Invitation invitation(interestName);
1295
1296 QString msg = QString::fromUtf8("Your invitation to ") + QString::fromStdString(invitation.getInviteeNameSpace().toUri()) + " times out!";
1297 emit inivationRejection(msg);
1298}
1299
1300void
Yingdi Yu233a9722014-03-07 15:47:09 -08001301ChatDialog::onIntroCert(const Interest& interest, const shared_ptr<const Data>& data)
Yingdi Yu348f5ea2014-03-01 14:47:25 -08001302{
1303 Data innerData;
Yingdi Yu233a9722014-03-07 15:47:09 -08001304 innerData.wireDecode(data->getContent().blockFromValue());
Yingdi Yu348f5ea2014-03-01 14:47:25 -08001305 Sync::IntroCertificate introCert(innerData);
1306 m_sock->addParticipant(introCert);
Yingdi Yuf4aaa8b2014-03-10 11:24:31 -07001307 plotTrustTree();
Yingdi Yu348f5ea2014-03-01 14:47:25 -08001308}
1309
1310void
Yingdi Yu233a9722014-03-07 15:47:09 -08001311ChatDialog::onIntroCertTimeout(const Interest& interest, int retry, const QString& msg)
Yingdi Yu348f5ea2014-03-01 14:47:25 -08001312{
1313 _LOG_DEBUG("onIntroCertTimeout: " << msg.toStdString());
1314}
1315
1316
Yingdi Yu348f5ea2014-03-01 14:47:25 -08001317#if WAF
1318#include "chat-dialog.moc"
1319#include "chat-dialog.cpp.moc"
1320#endif