blob: 407349a0201481b7e654a4c83e7f3887f030f3ba [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
Yingdi Yu0b0a7362014-08-05 16:31:30 -070013#include "chat-dialog.hpp"
Yingdi Yu348f5ea2014-03-01 14:47:25 -080014#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>
Yingdi Yufa0b6a02014-04-30 14:26:42 -070024#include <ndn-cxx/util/random.hpp>
Yingdi Yu0b0a7362014-08-05 16:31:30 -070025#include <ndn-cxx/encoding/buffer-stream.hpp>
26#include "cryptopp.hpp"
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 -080031
Yingdi Yu0b0a7362014-08-05 16:31:30 -070032// INIT_LOGGER("ChatDialog");
Yingdi Yu348f5ea2014-03-01 14:47:25 -080033
34Q_DECLARE_METATYPE(std::vector<Sync::MissingDataInfo> )
Yingdi Yu233a9722014-03-07 15:47:09 -080035Q_DECLARE_METATYPE(ndn::shared_ptr<const ndn::Data>)
Yingdi Yu348f5ea2014-03-01 14:47:25 -080036Q_DECLARE_METATYPE(ndn::Interest)
37Q_DECLARE_METATYPE(size_t)
38
Yingdi Yu0b0a7362014-08-05 16:31:30 -070039
40namespace chronos {
41
42using std::vector;
43using std::string;
44using std::map;
45using std::queue;
46
47using ndn::IdentityCertificate;
48using ndn::SecRuleRelative;
49using ndn::Face;
50using ndn::OBufferStream;
51using ndn::OnDataValidated;
52using ndn::OnDataValidationFailed;
53
54
55static const int HELLO_INTERVAL = FRESHNESS * 3 / 4;
56static const uint8_t CHRONOS_RP_SEPARATOR[2] = {0xF0, 0x2E}; // %F0.
57
Yingdi Yu348f5ea2014-03-01 14:47:25 -080058ChatDialog::ChatDialog(ContactManager* contactManager,
59 shared_ptr<Face> face,
60 const IdentityCertificate& myCertificate,
61 const Name& chatroomPrefix,
Yingdi Yufa0b6a02014-04-30 14:26:42 -070062 const Name& localPrefix,
Yingdi Yu17032f82014-03-25 15:48:23 -070063 const std::string& nick,
Yingdi Yu348f5ea2014-03-01 14:47:25 -080064 bool withSecurity,
Yingdi Yufa0b6a02014-04-30 14:26:42 -070065 QWidget* parent)
Yingdi Yu348f5ea2014-03-01 14:47:25 -080066 : QDialog(parent)
67 , ui(new Ui::ChatDialog)
68 , m_contactManager(contactManager)
69 , m_face(face)
70 , m_myCertificate(myCertificate)
Yingdi Yu0b0a7362014-08-05 16:31:30 -070071 , m_chatroomName(chatroomPrefix.get(-1).toUri())
Yingdi Yu348f5ea2014-03-01 14:47:25 -080072 , m_chatroomPrefix(chatroomPrefix)
73 , m_localPrefix(localPrefix)
74 , m_useRoutablePrefix(false)
75 , m_nick(nick)
Yingdi Yua7876722014-03-25 14:46:55 -070076 , m_lastMsgTime(time::toUnixTimestamp(time::system_clock::now()).count())
Yingdi Yu348f5ea2014-03-01 14:47:25 -080077 , m_joined(false)
78 , m_sock(NULL)
Yingdi Yua7876722014-03-25 14:46:55 -070079 , m_session(static_cast<uint64_t>(time::toUnixTimestamp(time::system_clock::now()).count()))
Yingdi Yu348f5ea2014-03-01 14:47:25 -080080 , m_inviteListDialog(new InviteListDialog)
81{
82 qRegisterMetaType<std::vector<Sync::MissingDataInfo> >("std::vector<Sync::MissingDataInfo>");
Yingdi Yu233a9722014-03-07 15:47:09 -080083 qRegisterMetaType<ndn::shared_ptr<const ndn::Data> >("ndn.DataPtr");
Yingdi Yu348f5ea2014-03-01 14:47:25 -080084 qRegisterMetaType<ndn::Interest>("ndn.Interest");
85 qRegisterMetaType<size_t>("size_t");
86
87 m_scene = new DigestTreeScene(this);
Yingdi Yuf4aaa8b2014-03-10 11:24:31 -070088 m_trustScene = new TrustTreeScene(this);
Yingdi Yu348f5ea2014-03-01 14:47:25 -080089 m_rosterModel = new QStringListModel(this);
90 m_timer = new QTimer(this);
91
92 ui->setupUi(this);
Yingdi Yuf4aaa8b2014-03-10 11:24:31 -070093 ui->syncTreeViewer->setScene(m_scene);
Yingdi Yu348f5ea2014-03-01 14:47:25 -080094 m_scene->setSceneRect(m_scene->itemsBoundingRect());
Yingdi Yuf4aaa8b2014-03-10 11:24:31 -070095 ui->syncTreeViewer->hide();
96 ui->trustTreeViewer->setScene(m_trustScene);
97 m_trustScene->setSceneRect(m_trustScene->itemsBoundingRect());
98 ui->trustTreeViewer->hide();
Yingdi Yu348f5ea2014-03-01 14:47:25 -080099 ui->listView->setModel(m_rosterModel);
100
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700101 m_identity =
102 IdentityCertificate::certificateNameToPublicKeyName(m_myCertificate.getName()).getPrefix(-1);
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800103 updatePrefix();
104 updateLabels();
105
106 m_scene->setCurrentPrefix(QString(m_localChatPrefix.toUri().c_str()));
107 m_scene->plot("Empty");
108
Yingdi Yufa0b6a02014-04-30 14:26:42 -0700109 connect(ui->lineEdit, SIGNAL(returnPressed()),
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800110 this, SLOT(onReturnPressed()));
Yingdi Yufa0b6a02014-04-30 14:26:42 -0700111 connect(ui->syncTreeButton, SIGNAL(pressed()),
Yingdi Yuf4aaa8b2014-03-10 11:24:31 -0700112 this, SLOT(onSyncTreeButtonPressed()));
Yingdi Yufa0b6a02014-04-30 14:26:42 -0700113 connect(ui->trustTreeButton, SIGNAL(pressed()),
Yingdi Yuf4aaa8b2014-03-10 11:24:31 -0700114 this, SLOT(onTrustTreeButtonPressed()));
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800115 connect(m_scene, SIGNAL(replot()),
116 this, SLOT(onReplot()));
Yingdi Yufa0b6a02014-04-30 14:26:42 -0700117 connect(m_scene, SIGNAL(rosterChanged(QStringList)),
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800118 this, SLOT(onRosterChanged(QStringList)));
Yingdi Yufa0b6a02014-04-30 14:26:42 -0700119 connect(m_timer, SIGNAL(timeout()),
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800120 this, SLOT(onReplot()));
121
Yingdi Yufa0b6a02014-04-30 14:26:42 -0700122 connect(this, SIGNAL(processData(const ndn::shared_ptr<const ndn::Data>&, bool, bool)),
Yingdi Yu233a9722014-03-07 15:47:09 -0800123 this, SLOT(onProcessData(const ndn::shared_ptr<const ndn::Data>&, bool, bool)));
Yingdi Yufa0b6a02014-04-30 14:26:42 -0700124 connect(this, SIGNAL(processTreeUpdate(const std::vector<Sync::MissingDataInfo>)),
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800125 this, SLOT(onProcessTreeUpdate(const std::vector<Sync::MissingDataInfo>)));
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700126 connect(this, SIGNAL(reply(const ndn::Interest&,
127 const ndn::shared_ptr<const ndn::Data>&,
128 size_t, bool)),
129 this, SLOT(onReply(const ndn::Interest&,
130 const ndn::shared_ptr<const ndn::Data>&,
131 size_t, bool)));
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800132 connect(this, SIGNAL(replyTimeout(const ndn::Interest&, size_t)),
133 this, SLOT(onReplyTimeout(const ndn::Interest&, size_t)));
Yingdi Yu233a9722014-03-07 15:47:09 -0800134 connect(this, SIGNAL(introCert(const ndn::Interest&, const ndn::shared_ptr<const ndn::Data>&)),
135 this, SLOT(onIntroCert(const ndn::Interest&, const ndn::shared_ptr<const ndn::Data>&)));
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800136 connect(this, SIGNAL(introCertTimeout(const ndn::Interest&, int, const QString&)),
137 this, SLOT(onIntroCertTimeout(const ndn::Interest&, int, const QString&)));
138
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700139 if (withSecurity) {
140 m_invitationValidator = make_shared<chronos::ValidatorInvitation>();
141 m_dataRule = make_shared<SecRuleRelative>("([^<CHRONOCHAT-DATA>]*)<CHRONOCHAT-DATA><>",
142 "^([^<KEY>]*)<KEY>(<>*)<><ID-CERT>$",
143 "==", "\\1", "\\1", true);
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800144
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700145 ui->inviteButton->setEnabled(true);
146 ui->trustTreeButton->setEnabled(true);
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800147
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700148 connect(ui->inviteButton, SIGNAL(clicked()),
149 this, SLOT(onInviteListDialogRequested()));
150 connect(m_inviteListDialog, SIGNAL(sendInvitation(const QString&)),
151 this, SLOT(onSendInvitation(const QString&)));
152 connect(this, SIGNAL(waitForContactList()),
153 m_contactManager, SLOT(onWaitForContactList()));
154 connect(m_contactManager, SIGNAL(contactAliasListReady(const QStringList&)),
155 m_inviteListDialog, SLOT(onContactAliasListReady(const QStringList&)));
156 connect(m_contactManager, SIGNAL(contactIdListReady(const QStringList&)),
157 m_inviteListDialog, SLOT(onContactIdListReady(const QStringList&)));
158 }
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800159
160 initializeSync();
161}
162
163
164ChatDialog::~ChatDialog()
165{
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700166 if (m_certListPrefixId)
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800167 m_face->unsetInterestFilter(m_certListPrefixId);
168
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700169 if (m_certSinglePrefixId)
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800170 m_face->unsetInterestFilter(m_certSinglePrefixId);
171
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700172 if (m_sock != NULL) {
173 sendLeave();
174 delete m_sock;
175 m_sock = NULL;
176 }
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800177}
178
179// public methods:
180void
181ChatDialog::addSyncAnchor(const Invitation& invitation)
182{
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700183 // _LOG_DEBUG("Add sync anchor from invation");
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800184 // Add inviter certificate as trust anchor.
185 m_sock->addParticipant(invitation.getInviterCertificate());
Yingdi Yuf4aaa8b2014-03-10 11:24:31 -0700186 plotTrustTree();
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800187
188 // Ask inviter for IntroCertificate
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700189 Name inviterNameSpace =
190 IdentityCertificate::certificateNameToPublicKeyName(
191 invitation.getInviterCertificate().getName()).getPrefix(-1);
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800192 fetchIntroCert(inviterNameSpace, invitation.getInviterRoutingPrefix());
193}
194
195void
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700196ChatDialog::processTreeUpdateWrapper(const vector<Sync::MissingDataInfo>& v,
197 Sync::SyncSocket *sock)
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800198{
199 emit processTreeUpdate(v);
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700200 // _LOG_DEBUG("<<< Tree update signal emitted");
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800201}
202
203void
204ChatDialog::processDataWrapper(const shared_ptr<const Data>& data)
205{
Yingdi Yu233a9722014-03-07 15:47:09 -0800206 emit processData(data, true, false);
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700207 // _LOG_DEBUG("<<< " << data->getName() << " fetched");
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800208}
209
210void
211ChatDialog::processDataNoShowWrapper(const shared_ptr<const Data>& data)
212{
Yingdi Yu233a9722014-03-07 15:47:09 -0800213 emit processData(data, false, false);
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800214}
215
216void
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700217ChatDialog::processRemoveWrapper(const string& prefix)
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800218{
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700219 // _LOG_DEBUG("Sync REMOVE signal received for prefix: " << prefix);
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800220}
221
222// protected methods:
223void
224ChatDialog::closeEvent(QCloseEvent *e)
225{
226 QMessageBox::information(this, tr("ChronoChat"),
227 tr("The chatroom will keep running in the "
228 "system tray. To close the chatroom, "
229 "choose <b>Close chatroom</b> in the "
230 "context memu of the system tray entry."));
231 hide();
232 e->ignore();
233}
234
235void
Yingdi Yu233a9722014-03-07 15:47:09 -0800236ChatDialog::changeEvent(QEvent *e)
237{
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700238 switch(e->type()) {
Yingdi Yu233a9722014-03-07 15:47:09 -0800239 case QEvent::ActivationChange:
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700240 if (isActiveWindow()) {
Yingdi Yu233a9722014-03-07 15:47:09 -0800241 emit resetIcon();
242 }
243 break;
244 default:
245 break;
246 }
247}
248
249void
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800250ChatDialog::resizeEvent(QResizeEvent *e)
251{
252 fitView();
253}
254
255void
256ChatDialog::showEvent(QShowEvent *e)
257{
258 fitView();
259}
260
261// private methods:
262void
263ChatDialog::updatePrefix()
264{
265 m_certListPrefix.clear();
266 m_certSinglePrefix.clear();
267 m_localChatPrefix.clear();
268 m_chatPrefix.clear();
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700269 m_chatPrefix.append(m_identity)
270 .append("CHRONOCHAT-DATA")
271 .append(m_chatroomName)
272 .append(getRandomString());
273 if (!m_localPrefix.isPrefixOf(m_identity)) {
274 m_useRoutablePrefix = true;
275 m_certListPrefix.append(m_localPrefix).append(CHRONOS_RP_SEPARATOR, 2);
276 m_certSinglePrefix.append(m_localPrefix).append(CHRONOS_RP_SEPARATOR, 2);
277 m_localChatPrefix.append(m_localPrefix).append(CHRONOS_RP_SEPARATOR, 2);
278 }
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800279 m_certListPrefix.append(m_identity).append("CHRONOCHAT-CERT-LIST").append(m_chatroomName);
280 m_certSinglePrefix.append(m_identity).append("CHRONOCHAT-CERT-SINGLE").append(m_chatroomName);
281 m_localChatPrefix.append(m_chatPrefix);
282
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700283 if (m_certListPrefixId)
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800284 m_face->unsetInterestFilter(m_certListPrefixId);
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700285 m_certListPrefixId = m_face->setInterestFilter(m_certListPrefix,
286 bind(&ChatDialog::onCertListInterest,
287 this, _1, _2),
288 bind(&ChatDialog::onCertListRegisterFailed,
289 this, _1, _2));
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800290
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700291 if (m_certSinglePrefixId)
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800292 m_face->unsetInterestFilter(m_certSinglePrefixId);
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700293 m_certSinglePrefixId = m_face->setInterestFilter(m_certSinglePrefix,
294 bind(&ChatDialog::onCertSingleInterest,
295 this, _1, _2),
296 bind(&ChatDialog::onCertSingleRegisterFailed,
297 this, _1, _2));
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800298}
299
300void
301ChatDialog::updateLabels()
302{
303 QString settingDisp = QString("Chatroom: %1").arg(QString::fromStdString(m_chatroomName));
304 ui->infoLabel->setStyleSheet("QLabel {color: #630; font-size: 16px; font: bold \"Verdana\";}");
305 ui->infoLabel->setText(settingDisp);
306 QString prefixDisp;
307 Name privatePrefix("/private/local");
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700308 if (privatePrefix.isPrefixOf(m_localChatPrefix)) {
309 prefixDisp =
310 QString("<Warning: no connection to hub or hub does not support prefix autoconfig.>\n"
311 "<Prefix = %1>")
312 .arg(QString::fromStdString(m_localChatPrefix.toUri()));
313 ui->prefixLabel->setStyleSheet(
314 "QLabel {color: red; font-size: 12px; font: bold \"Verdana\";}");
315 }
316 else {
317 prefixDisp = QString("<Prefix = %1>")
318 .arg(QString::fromStdString(m_localChatPrefix.toUri()));
319 ui->prefixLabel->setStyleSheet(
320 "QLabel {color: Green; font-size: 12px; font: bold \"Verdana\";}");
321 }
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800322 ui->prefixLabel->setText(prefixDisp);
323}
324
325void
326ChatDialog::initializeSync()
327{
Yingdi Yufa0b6a02014-04-30 14:26:42 -0700328
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800329 m_sock = new Sync::SyncSocket(m_chatroomPrefix,
330 m_chatPrefix,
331 m_session,
332 m_useRoutablePrefix,
333 m_localPrefix,
334 m_face,
335 m_myCertificate,
336 m_dataRule,
337 bind(&ChatDialog::processTreeUpdateWrapper, this, _1, _2),
338 bind(&ChatDialog::processRemoveWrapper, this, _1));
Yingdi Yufa0b6a02014-04-30 14:26:42 -0700339
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800340 usleep(100000);
341
342 QTimer::singleShot(600, this, SLOT(sendJoin()));
343 m_timer->start(FRESHNESS * 1000);
Yingdi Yuf4aaa8b2014-03-10 11:24:31 -0700344 disableSyncTreeDisplay();
345 QTimer::singleShot(2200, this, SLOT(enableSyncTreeDisplay()));
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800346}
347
348void
349ChatDialog::sendInvitation(shared_ptr<Contact> contact, bool isIntroducer)
350{
351 // Add invitee as a trust anchor.
352 m_invitationValidator->addTrustAnchor(contact->getPublicKeyName(),
353 contact->getPublicKey());
354
355 // Prepared an invitation interest without routable prefix.
356 Invitation invitation(contact->getNameSpace(),
357 m_chatroomName,
358 m_localPrefix,
359 m_myCertificate);
360 Interest tmpInterest(invitation.getUnsignedInterestName());
361 m_keyChain.sign(tmpInterest, m_myCertificate.getName());
362
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700363 // Get invitee's routable prefix
364 // (ideally it will do some DNS lookup, but we assume everyone use /ndn/broadcast
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800365 Name routablePrefix = getInviteeRoutablePrefix(contact->getNameSpace());
366
367 // Check if we need to prepend the routable prefix to the interest name.
368 bool requireRoutablePrefix = false;
369 Name interestName;
370 size_t routablePrefixOffset = 0;
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700371 if (!routablePrefix.isPrefixOf(tmpInterest.getName())) {
372 interestName.append(routablePrefix).append(CHRONOS_RP_SEPARATOR, 2);
373 requireRoutablePrefix = true;
374 routablePrefixOffset = routablePrefix.size() + 1;
375 }
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800376 interestName.append(tmpInterest.getName());
377
378 // Send the invitation out
379 Interest interest(interestName);
380 interest.setMustBeFresh(true);
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700381 // _LOG_DEBUG("sendInvitation: " << interest.getName());
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800382 m_face->expressInterest(interest,
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700383 bind(&ChatDialog::replyWrapper,
384 this, _1, _2, routablePrefixOffset, isIntroducer),
385 bind(&ChatDialog::replyTimeoutWrapper,
386 this, _1, routablePrefixOffset));
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800387}
388
389void
Yingdi Yufa0b6a02014-04-30 14:26:42 -0700390ChatDialog::replyWrapper(const Interest& interest,
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800391 Data& data,
392 size_t routablePrefixOffset,
393 bool isIntroducer)
394{
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700395 // _LOG_DEBUG("ChatDialog::replyWrapper");
Yingdi Yu233a9722014-03-07 15:47:09 -0800396 emit reply(interest, data.shared_from_this(), routablePrefixOffset, isIntroducer);
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700397 // _LOG_DEBUG("OK?");
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800398}
399
400void
Yingdi Yufa0b6a02014-04-30 14:26:42 -0700401ChatDialog::replyTimeoutWrapper(const Interest& interest,
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800402 size_t routablePrefixOffset)
403{
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700404 // _LOG_DEBUG("ChatDialog::replyTimeoutWrapper");
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800405 emit replyTimeout(interest, routablePrefixOffset);
406}
407
Yingdi Yufa0b6a02014-04-30 14:26:42 -0700408void
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800409ChatDialog::onReplyValidated(const shared_ptr<const Data>& data,
410 size_t inviteeRoutablePrefixOffset,
411 bool isIntroducer)
412{
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700413 if (data->getName().size() <= inviteeRoutablePrefixOffset) {
414 Invitation invitation(data->getName());
415 invitationRejected(invitation.getInviteeNameSpace());
416 }
417 else {
418 Name inviteePrefix;
419 inviteePrefix.wireDecode(data->getName().get(inviteeRoutablePrefixOffset).blockFromValue());
420 IdentityCertificate inviteeCert;
421 inviteeCert.wireDecode(data->getContent().blockFromValue());
422 invitationAccepted(inviteeCert, inviteePrefix, isIntroducer);
423 }
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800424}
425
426void
427ChatDialog::onReplyValidationFailed(const shared_ptr<const Data>& data,
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700428 const string& failureInfo)
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800429{
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700430 // _LOG_DEBUG("Invitation reply cannot be validated: " + failureInfo + " ==> " +
431 // data->getName().toUri());
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800432}
433
434void
435ChatDialog::invitationRejected(const Name& identity)
436{
437 QString msg = QString::fromStdString(identity.toUri()) + " rejected your invitation!";
438 emit inivationRejection(msg);
439}
440
441void
Yingdi Yufa0b6a02014-04-30 14:26:42 -0700442ChatDialog::invitationAccepted(const IdentityCertificate& inviteeCert,
443 const Name& inviteePrefix,
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800444 bool isIntroducer)
445{
446 // Add invitee certificate as trust anchor.
447 m_sock->addParticipant(inviteeCert);
Yingdi Yuf4aaa8b2014-03-10 11:24:31 -0700448 plotTrustTree();
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800449
450 // Ask invitee for IntroCertificate.
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700451 Name inviteeNameSpace =
452 IdentityCertificate::certificateNameToPublicKeyName(inviteeCert.getName()).getPrefix(-1);
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800453 fetchIntroCert(inviteeNameSpace, inviteePrefix);
454}
455
456void
457ChatDialog::fetchIntroCert(const Name& identity, const Name& prefix)
458{
459 Name interestName;
460
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700461 if (!prefix.isPrefixOf(identity))
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800462 interestName.append(prefix).append(CHRONOS_RP_SEPARATOR, 2);
Yingdi Yufa0b6a02014-04-30 14:26:42 -0700463
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800464 interestName.append(identity)
465 .append("CHRONOCHAT-CERT-LIST")
466 .append(m_chatroomName)
467 .appendVersion();
468
469 Interest interest(interestName);
470 interest.setMustBeFresh(true);
471
472 m_face->expressInterest(interest,
473 bind(&ChatDialog::onIntroCertList, this, _1, _2),
Yingdi Yufa0b6a02014-04-30 14:26:42 -0700474 bind(&ChatDialog::onIntroCertListTimeout, this, _1, 1,
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800475 "IntroCertList: " + interestName.toUri()));
476}
477
478void
479ChatDialog::onIntroCertList(const Interest& interest, const Data& data)
480{
481 Chronos::IntroCertListMsg introCertList;
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700482 if (!introCertList.ParseFromArray(data.getContent().value(), data.getContent().value_size()))
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800483 return;
484
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700485 for (int i = 0; i < introCertList.certname_size(); i++) {
486 Name certName(introCertList.certname(i));
487 Interest interest(certName);
488 interest.setMustBeFresh(true);
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800489
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700490 // _LOG_DEBUG("onIntroCertList: to fetch " << certName);
Yingdi Yu233a9722014-03-07 15:47:09 -0800491
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700492 m_face->expressInterest(interest,
493 bind(&ChatDialog::introCertWrapper, this, _1, _2),
494 bind(&ChatDialog::introCertTimeoutWrapper, this, _1, 0,
495 QString("IntroCert: %1").arg(introCertList.certname(i).c_str())));
496 }
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800497}
498
499void
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700500ChatDialog::onIntroCertListTimeout(const Interest& interest, int retry, const string& msg)
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800501{
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700502 if (retry > 0) {
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800503 m_face->expressInterest(interest,
504 bind(&ChatDialog::onIntroCertList, this, _1, _2),
505 bind(&ChatDialog::onIntroCertListTimeout, this, _1, retry - 1, msg));
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700506 }
507 else {
508 // _LOG_DEBUG(msg << " TIMEOUT!");
509 }
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800510}
511
512void
513ChatDialog::introCertWrapper(const Interest& interest, Data& data)
514{
Yingdi Yu233a9722014-03-07 15:47:09 -0800515 emit introCert(interest, data.shared_from_this());
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800516}
517
518void
519ChatDialog::introCertTimeoutWrapper(const Interest& interest, int retry, const QString& msg)
520{
521 emit introCertTimeout(interest, retry, msg);
522}
523
524void
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700525ChatDialog::onCertListInterest(const Name& prefix, const Interest& interest)
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800526{
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700527 vector<Name> certNameList;
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800528 m_sock->getIntroCertNames(certNameList);
529
530 Chronos::IntroCertListMsg msg;
531
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700532 for (vector<Name>::const_iterator it = certNameList.begin(); it != certNameList.end(); it++) {
533 Name certName;
534 certName.append(m_certSinglePrefix).append(*it);
535 msg.add_certname(certName.toUri());
536 }
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800537 OBufferStream os;
538 msg.SerializeToOstream(&os);
539
540 Data data(interest.getName());
541 data.setContent(os.buf());
542 m_keyChain.sign(data, m_myCertificate.getName());
543
544 m_face->put(data);
545}
546
547void
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700548ChatDialog::onCertListRegisterFailed(const Name& prefix, const string& msg)
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800549{
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700550 // _LOG_DEBUG("ChatDialog::onCertListRegisterFailed failed: " + msg);
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800551}
552
553void
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700554ChatDialog::onCertSingleInterest(const Name& prefix, const Interest& interest)
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800555{
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700556 try {
557 Name certName = interest.getName().getSubName(prefix.size());
558 const Sync::IntroCertificate& introCert = m_sock->getIntroCertificate(certName);
559 Data data(interest.getName());
560 data.setContent(introCert.wireEncode());
561 m_keyChain.sign(data, m_myCertificate.getName());
562 m_face->put(data);
563 }
564 catch(Sync::SyncSocket::Error& e) {
565 return;
566 }
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800567}
568
569void
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700570ChatDialog::onCertSingleRegisterFailed(const Name& prefix, const string& msg)
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800571{
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700572 // _LOG_DEBUG("ChatDialog::onCertListRegisterFailed failed: " + msg);
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800573}
574
575void
576ChatDialog::sendMsg(SyncDemo::ChatMessage &msg)
577{
578 // send msg
579 OBufferStream os;
580 msg.SerializeToOstream(&os);
Yingdi Yufa0b6a02014-04-30 14:26:42 -0700581
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700582 if (!msg.IsInitialized()) {
583 // _LOG_DEBUG("Errrrr.. msg was not probally initialized " << __FILE__ <<
584 // ":" << __LINE__ << ". what is happening?");
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800585 abort();
586 }
Yingdi Yu233a9722014-03-07 15:47:09 -0800587 uint64_t nextSequence = m_sock->getNextSeq();
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800588 m_sock->publishData(os.buf()->buf(), os.buf()->size(), FRESHNESS);
589
Yingdi Yua7876722014-03-25 14:46:55 -0700590 m_lastMsgTime = time::toUnixTimestamp(time::system_clock::now()).count();
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800591
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700592 Sync::MissingDataInfo mdi = {m_localChatPrefix.toUri(),
593 Sync::SeqNo(0),
594 Sync::SeqNo(nextSequence)};
595 vector<Sync::MissingDataInfo> v;
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800596 v.push_back(mdi);
597 {
598 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
599 m_scene->processUpdate(v, m_sock->getRootDigest().c_str());
600 m_scene->msgReceived(QString::fromStdString(m_localChatPrefix.toUri()),
601 QString::fromStdString(m_nick));
602 }
603}
604
Yingdi Yuf4aaa8b2014-03-10 11:24:31 -0700605void ChatDialog::disableSyncTreeDisplay()
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800606{
Yingdi Yuf4aaa8b2014-03-10 11:24:31 -0700607 ui->syncTreeButton->setEnabled(false);
608 ui->syncTreeViewer->hide();
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800609 fitView();
610}
611
612void
613ChatDialog::appendMessage(const SyncDemo::ChatMessage msg, bool isHistory)
614{
615 boost::recursive_mutex::scoped_lock lock(m_msgMutex);
616
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700617 if (msg.type() == SyncDemo::ChatMessage::CHAT) {
618 if (!msg.has_data()) {
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800619 return;
620 }
621
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700622 if (msg.from().empty() || msg.data().empty()) {
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800623 return;
624 }
625
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700626 if (!msg.has_timestamp()) {
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800627 return;
628 }
629
630 // if (m_history.size() == MAX_HISTORY_ENTRY)
631 // {
632 // m_history.dequeue();
633 // }
634
635 // m_history.enqueue(msg);
636
637 QTextCharFormat nickFormat;
638 nickFormat.setForeground(Qt::darkGreen);
639 nickFormat.setFontWeight(QFont::Bold);
640 nickFormat.setFontUnderline(true);
641 nickFormat.setUnderlineColor(Qt::gray);
642
643 QTextCursor cursor(ui->textEdit->textCursor());
644 cursor.movePosition(QTextCursor::End);
645 QTextTableFormat tableFormat;
646 tableFormat.setBorder(0);
647 QTextTable *table = cursor.insertTable(1, 2, tableFormat);
648 QString from = QString("%1 ").arg(msg.from().c_str());
649 QTextTableCell fromCell = table->cellAt(0, 0);
650 fromCell.setFormat(nickFormat);
651 fromCell.firstCursorPosition().insertText(from);
652
653 time_t timestamp = msg.timestamp();
654 printTimeInCell(table, timestamp);
655
656 QTextCursor nextCursor(ui->textEdit->textCursor());
657 nextCursor.movePosition(QTextCursor::End);
658 table = nextCursor.insertTable(1, 1, tableFormat);
659 table->cellAt(0, 0).firstCursorPosition().insertText(QString::fromUtf8(msg.data().c_str()));
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700660 if (!isHistory) {
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800661 showMessage(from, QString::fromUtf8(msg.data().c_str()));
662 }
663 }
664
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700665 if (msg.type() == SyncDemo::ChatMessage::JOIN || msg.type() == SyncDemo::ChatMessage::LEAVE) {
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800666 QTextCharFormat nickFormat;
667 nickFormat.setForeground(Qt::gray);
668 nickFormat.setFontWeight(QFont::Bold);
669 nickFormat.setFontUnderline(true);
670 nickFormat.setUnderlineColor(Qt::gray);
671
672 QTextCursor cursor(ui->textEdit->textCursor());
673 cursor.movePosition(QTextCursor::End);
674 QTextTableFormat tableFormat;
675 tableFormat.setBorder(0);
676 QTextTable *table = cursor.insertTable(1, 2, tableFormat);
677 QString action;
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700678 if (msg.type() == SyncDemo::ChatMessage::JOIN) {
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800679 action = "enters room";
680 }
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700681 else {
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800682 action = "leaves room";
683 }
684
685 QString from = QString("%1 %2 ").arg(msg.from().c_str()).arg(action);
686 QTextTableCell fromCell = table->cellAt(0, 0);
687 fromCell.setFormat(nickFormat);
688 fromCell.firstCursorPosition().insertText(from);
689
690 time_t timestamp = msg.timestamp();
691 printTimeInCell(table, timestamp);
692 }
693
694 QScrollBar *bar = ui->textEdit->verticalScrollBar();
695 bar->setValue(bar->maximum());
696}
697
698void
699ChatDialog::processRemove(QString prefix)
700{
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700701 // _LOG_DEBUG("<<< remove node for prefix" << prefix.toStdString());
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800702
703 bool removed = m_scene->removeNode(prefix);
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700704 if (removed) {
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800705 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
706 m_scene->plot(m_sock->getRootDigest().c_str());
707 }
708}
709
710Name
711ChatDialog::getInviteeRoutablePrefix(const Name& invitee)
712{
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700713 return Name("/ndn/broadcast");
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800714}
715
716void
717ChatDialog::formChatMessage(const QString &text, SyncDemo::ChatMessage &msg) {
718 msg.set_from(m_nick);
719 msg.set_to(m_chatroomName);
720 msg.set_data(text.toStdString());
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700721 int32_t seconds =
722 static_cast<int32_t>(time::toUnixTimestamp(time::system_clock::now()).count()/1000000000);
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800723 msg.set_timestamp(seconds);
724 msg.set_type(SyncDemo::ChatMessage::CHAT);
725}
726
727void
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700728ChatDialog::formControlMessage(SyncDemo::ChatMessage &msg,
729 SyncDemo::ChatMessage::ChatMessageType type)
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800730{
731 msg.set_from(m_nick);
732 msg.set_to(m_chatroomName);
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700733 int32_t seconds =
734 static_cast<int32_t>(time::toUnixTimestamp(time::system_clock::now()).count()/1000000000);
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800735 msg.set_timestamp(seconds);
736 msg.set_type(type);
737}
738
739QString
740ChatDialog::formatTime(time_t timestamp)
741{
742 struct tm *tm_time = localtime(&timestamp);
743 int hour = tm_time->tm_hour;
744 QString amOrPM;
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700745 if (hour > 12) {
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800746 hour -= 12;
747 amOrPM = "PM";
748 }
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700749 else {
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800750 amOrPM = "AM";
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700751 if (hour == 0) {
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800752 hour = 12;
753 }
754 }
755
756 char textTime[12];
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700757 sprintf(textTime, "%d:%02d:%02d %s",
758 hour, tm_time->tm_min, tm_time->tm_sec, amOrPM.toStdString().c_str());
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800759 return QString(textTime);
760}
761
762void
763ChatDialog::printTimeInCell(QTextTable *table, time_t timestamp)
764{
765 QTextCharFormat timeFormat;
766 timeFormat.setForeground(Qt::gray);
767 timeFormat.setFontUnderline(true);
768 timeFormat.setUnderlineColor(Qt::gray);
769 QTextTableCell timeCell = table->cellAt(0, 1);
770 timeCell.setFormat(timeFormat);
771 timeCell.firstCursorPosition().insertText(formatTime(timestamp));
772}
773
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700774string
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800775ChatDialog::getRandomString()
776{
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700777 uint32_t r = ndn::random::generateWord32();
Yingdi Yu17032f82014-03-25 15:48:23 -0700778 std::stringstream ss;
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800779 {
780 using namespace CryptoPP;
781 StringSource(reinterpret_cast<uint8_t*>(&r), 4, true,
782 new HexEncoder(new FileSink(ss), false));
Yingdi Yufa0b6a02014-04-30 14:26:42 -0700783
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800784 }
785
786 return ss.str();
787}
788
789void
790ChatDialog::showMessage(const QString& from, const QString& data)
791{
792 if (!isActiveWindow())
793 emit showChatMessage(QString::fromStdString(m_chatroomName),
794 from, data);
795}
796
797void
798ChatDialog::fitView()
799{
800 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
801 QRectF rect = m_scene->itemsBoundingRect();
802 m_scene->setSceneRect(rect);
Yingdi Yuf4aaa8b2014-03-10 11:24:31 -0700803 ui->syncTreeViewer->fitInView(m_scene->itemsBoundingRect(), Qt::KeepAspectRatio);
804
805 QRectF trustRect = m_trustScene->itemsBoundingRect();
806 m_trustScene->setSceneRect(trustRect);
807 ui->trustTreeViewer->fitInView(m_trustScene->itemsBoundingRect(), Qt::KeepAspectRatio);
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800808}
809
810void
811ChatDialog::summonReaper()
812{
813 Sync::SyncLogic &logic = m_sock->getLogic ();
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700814 map<string, bool> branches = logic.getBranchPrefixes();
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800815 QMap<QString, DisplayUserPtr> roster = m_scene->getRosterFull();
816
817 m_zombieList.clear();
818
819 QMapIterator<QString, DisplayUserPtr> it(roster);
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700820 map<string, bool>::iterator mapIt;
821 while (it.hasNext()) {
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800822 it.next();
823 DisplayUserPtr p = it.value();
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700824 if (p != DisplayUserNullPtr) {
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800825 mapIt = branches.find(p->getPrefix().toStdString());
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700826 if (mapIt != branches.end()) {
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800827 mapIt->second = true;
828 }
829 }
830 }
831
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700832 for (mapIt = branches.begin(); mapIt != branches.end(); ++mapIt) {
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800833 // this is zombie. all active users should have been marked true
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700834 if (! mapIt->second) {
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800835 m_zombieList.append(mapIt->first.c_str());
836 }
837 }
838
839 m_zombieIndex = 0;
840
841 // start reaping
842 reap();
843}
844
Yingdi Yuf4aaa8b2014-03-10 11:24:31 -0700845void
846ChatDialog::getTree(TrustTreeNodeList& nodeList)
847{
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700848 typedef map<Name, shared_ptr<TrustTreeNode> > NodeMap;
Yingdi Yuf4aaa8b2014-03-10 11:24:31 -0700849
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700850 vector<Name> certNameList;
Yingdi Yuf4aaa8b2014-03-10 11:24:31 -0700851 NodeMap nodeMap;
852
853 m_sock->getIntroCertNames(certNameList);
854
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700855 for (vector<Name>::const_iterator it = certNameList.begin(); it != certNameList.end(); it++) {
856 Name introducerCertName;
857 Name introduceeCertName;
Yingdi Yuf4aaa8b2014-03-10 11:24:31 -0700858
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700859 introducerCertName.wireDecode(it->get(-2).blockFromValue());
860 introduceeCertName.wireDecode(it->get(-3).blockFromValue());
Yingdi Yuf4aaa8b2014-03-10 11:24:31 -0700861
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700862 Name introducerName =
863 IdentityCertificate::certificateNameToPublicKeyName(introducerCertName).getPrefix(-1);
864 Name introduceeName =
865 IdentityCertificate::certificateNameToPublicKeyName(introduceeCertName).getPrefix(-1);
Yingdi Yuf4aaa8b2014-03-10 11:24:31 -0700866
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700867 NodeMap::iterator introducerIt = nodeMap.find(introducerName);
868 if (introducerIt == nodeMap.end()) {
869 shared_ptr<TrustTreeNode> introducerNode(new TrustTreeNode(introducerName));
870 nodeMap[introducerName] = introducerNode;
Yingdi Yuf4aaa8b2014-03-10 11:24:31 -0700871 }
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700872 shared_ptr<TrustTreeNode> erNode = nodeMap[introducerName];
873
874 NodeMap::iterator introduceeIt = nodeMap.find(introduceeName);
875 if (introduceeIt == nodeMap.end()) {
876 shared_ptr<TrustTreeNode> introduceeNode(new TrustTreeNode(introduceeName));
877 nodeMap[introduceeName] = introduceeNode;
878 }
879 shared_ptr<TrustTreeNode> eeNode = nodeMap[introduceeName];
880
881 erNode->addIntroducee(eeNode);
882 eeNode->addIntroducer(erNode);
883 }
Yingdi Yufa0b6a02014-04-30 14:26:42 -0700884
Yingdi Yuf4aaa8b2014-03-10 11:24:31 -0700885 nodeList.clear();
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700886 queue<shared_ptr<TrustTreeNode> > nodeQueue;
Yingdi Yuf4aaa8b2014-03-10 11:24:31 -0700887
888 NodeMap::iterator nodeIt = nodeMap.find(m_identity);
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700889 if (nodeIt == nodeMap.end())
Yingdi Yuf4aaa8b2014-03-10 11:24:31 -0700890 return;
891
892 nodeQueue.push(nodeIt->second);
893 nodeIt->second->setLevel(0);
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700894 while (!nodeQueue.empty()) {
895 shared_ptr<TrustTreeNode>& node = nodeQueue.front();
896 node->setVisited();
Yingdi Yuf4aaa8b2014-03-10 11:24:31 -0700897
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700898 TrustTreeNodeList& introducees = node->getIntroducees();
899 for (TrustTreeNodeList::iterator eeIt = introducees.begin();
900 eeIt != introducees.end(); eeIt++) {
901 // _LOG_DEBUG("introducee: " << (*eeIt)->name() <<
902 // " visited: " << std::boolalpha << (*eeIt)->visited());
903 if (!(*eeIt)->visited()) {
904 nodeQueue.push(*eeIt);
905 (*eeIt)->setLevel(node->level()+1);
906 }
Yingdi Yuf4aaa8b2014-03-10 11:24:31 -0700907 }
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700908
909 nodeList.push_back(node);
910 nodeQueue.pop();
911 }
Yingdi Yuf4aaa8b2014-03-10 11:24:31 -0700912}
913
914void
915ChatDialog::plotTrustTree()
916{
917 TrustTreeNodeList nodeList;
918
919 getTree(nodeList);
920 {
921 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
922 m_trustScene->plotTrustTree(nodeList);
923 fitView();
924 }
925}
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800926
927// public slots:
928void
929ChatDialog::onLocalPrefixUpdated(const QString& localPrefix)
930{
931 Name newLocalPrefix(localPrefix.toStdString());
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700932 if (!newLocalPrefix.empty() && newLocalPrefix != m_localPrefix) {
933 // Update localPrefix
934 m_localPrefix = newLocalPrefix;
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800935
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700936 updatePrefix();
937 updateLabels();
938 m_scene->setCurrentPrefix(QString(m_localChatPrefix.toUri().c_str()));
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800939
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700940 if (m_sock != NULL) {
941 {
942 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
943 m_scene->clearAll();
944 m_scene->plot("Empty");
945 }
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800946
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700947 ui->textEdit->clear();
Yingdi Yufa0b6a02014-04-30 14:26:42 -0700948
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700949 if (m_joined) {
950 sendLeave();
951 }
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800952
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700953 delete m_sock;
954 m_sock = NULL;
Yingdi Yufa0b6a02014-04-30 14:26:42 -0700955
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700956 usleep(100000);
957 m_sock = new Sync::SyncSocket(m_chatroomPrefix,
958 m_chatPrefix,
959 m_session,
960 m_useRoutablePrefix,
961 m_localPrefix,
962 m_face,
963 m_myCertificate,
964 m_dataRule,
965 bind(&ChatDialog::processTreeUpdateWrapper, this, _1, _2),
966 bind(&ChatDialog::processRemoveWrapper, this, _1));
967 usleep(100000);
968 QTimer::singleShot(600, this, SLOT(sendJoin()));
969 m_timer->start(FRESHNESS * 1000);
970 disableSyncTreeDisplay();
971 QTimer::singleShot(2200, this, SLOT(enableSyncTreeDisplay()));
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800972 }
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700973 else
974 initializeSync();
975 }
Yingdi Yufa0b6a02014-04-30 14:26:42 -0700976 else
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800977 if (m_sock == NULL)
978 initializeSync();
979
980 fitView();
981}
982
983void
984ChatDialog::onClose()
985{
986 hide();
987 emit closeChatDialog(QString::fromStdString(m_chatroomName));
988}
989
990
991// private slots:
992void
993ChatDialog::onReturnPressed()
994{
995 QString text = ui->lineEdit->text();
996 if (text.isEmpty())
997 return;
998
999 ui->lineEdit->clear();
1000
Yingdi Yu0b0a7362014-08-05 16:31:30 -07001001 if (text.startsWith("boruoboluomi")) {
Yingdi Yu348f5ea2014-03-01 14:47:25 -08001002 summonReaper ();
1003 // reapButton->show();
1004 fitView();
1005 return;
1006 }
1007
Yingdi Yu0b0a7362014-08-05 16:31:30 -07001008 if (text.startsWith("minimanihong")) {
Yingdi Yu348f5ea2014-03-01 14:47:25 -08001009 // reapButton->hide();
1010 fitView();
1011 return;
1012 }
1013
1014 SyncDemo::ChatMessage msg;
1015 formChatMessage(text, msg);
1016
1017 appendMessage(msg);
1018
1019 sendMsg(msg);
1020
1021 fitView();
1022}
1023
Yingdi Yufa0b6a02014-04-30 14:26:42 -07001024void
Yingdi Yuf4aaa8b2014-03-10 11:24:31 -07001025ChatDialog::onSyncTreeButtonPressed()
Yingdi Yu348f5ea2014-03-01 14:47:25 -08001026{
Yingdi Yu0b0a7362014-08-05 16:31:30 -07001027 if (ui->syncTreeViewer->isVisible()) {
Yingdi Yuf4aaa8b2014-03-10 11:24:31 -07001028 ui->syncTreeViewer->hide();
1029 ui->syncTreeButton->setText("Show ChronoSync Tree");
Yingdi Yu348f5ea2014-03-01 14:47:25 -08001030 }
Yingdi Yu0b0a7362014-08-05 16:31:30 -07001031 else {
Yingdi Yuf4aaa8b2014-03-10 11:24:31 -07001032 ui->syncTreeViewer->show();
1033 ui->syncTreeButton->setText("Hide ChronoSync Tree");
1034 }
1035
1036 fitView();
1037}
1038
1039void
1040ChatDialog::onTrustTreeButtonPressed()
1041{
Yingdi Yu0b0a7362014-08-05 16:31:30 -07001042 if (ui->trustTreeViewer->isVisible()) {
Yingdi Yuf4aaa8b2014-03-10 11:24:31 -07001043 ui->trustTreeViewer->hide();
1044 ui->trustTreeButton->setText("Show Trust Tree");
1045 }
Yingdi Yu0b0a7362014-08-05 16:31:30 -07001046 else {
Yingdi Yuf4aaa8b2014-03-10 11:24:31 -07001047 ui->trustTreeViewer->show();
1048 ui->trustTreeButton->setText("Hide Trust Tree");
Yingdi Yu348f5ea2014-03-01 14:47:25 -08001049 }
1050
1051 fitView();
1052}
1053
1054void
Yingdi Yu233a9722014-03-07 15:47:09 -08001055ChatDialog::onProcessData(const shared_ptr<const Data>& data, bool show, bool isHistory)
Yingdi Yu348f5ea2014-03-01 14:47:25 -08001056{
1057 SyncDemo::ChatMessage msg;
1058 bool corrupted = false;
Yingdi Yu0b0a7362014-08-05 16:31:30 -07001059 if (!msg.ParseFromArray(data->getContent().value(), data->getContent().value_size())) {
1060 // _LOG_DEBUG("Errrrr.. Can not parse msg with name: " <<
1061 // data->getName() << ". what is happening?");
Yingdi Yu348f5ea2014-03-01 14:47:25 -08001062 // nasty stuff: as a remedy, we'll form some standard msg for inparsable msgs
1063 msg.set_from("inconnu");
1064 msg.set_type(SyncDemo::ChatMessage::OTHER);
1065 corrupted = true;
1066 }
1067
1068 // display msg received from network
1069 // we have to do so; this function is called by ccnd thread
1070 // so if we call appendMsg directly
1071 // Qt crash as "QObject: Cannot create children for a parent that is in a different thread"
1072 // the "cannonical" way to is use signal-slot
Yingdi Yu0b0a7362014-08-05 16:31:30 -07001073 if (show && !corrupted) {
Yingdi Yu348f5ea2014-03-01 14:47:25 -08001074 appendMessage(msg, isHistory);
1075 }
1076
Yingdi Yu0b0a7362014-08-05 16:31:30 -07001077 if (!isHistory) {
Yingdi Yu348f5ea2014-03-01 14:47:25 -08001078 // update the tree view
Yingdi Yu0b0a7362014-08-05 16:31:30 -07001079 string prefix = data->getName().getPrefix(-2).toUri();
1080 // _LOG_DEBUG("<<< updating scene for" << prefix << ": " << msg.from());
1081 if (msg.type() == SyncDemo::ChatMessage::LEAVE) {
Yingdi Yu348f5ea2014-03-01 14:47:25 -08001082 processRemove(prefix.c_str());
1083 }
Yingdi Yu0b0a7362014-08-05 16:31:30 -07001084 else {
Yingdi Yu348f5ea2014-03-01 14:47:25 -08001085 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
1086 m_scene->msgReceived(prefix.c_str(), msg.from().c_str());
1087 }
1088 }
1089 fitView();
1090}
1091
1092void
Yingdi Yu0b0a7362014-08-05 16:31:30 -07001093ChatDialog::onProcessTreeUpdate(const vector<Sync::MissingDataInfo>& v)
Yingdi Yu348f5ea2014-03-01 14:47:25 -08001094{
Yingdi Yu0b0a7362014-08-05 16:31:30 -07001095 // _LOG_DEBUG("<<< processing Tree Update");
Yingdi Yu348f5ea2014-03-01 14:47:25 -08001096
Yingdi Yu0b0a7362014-08-05 16:31:30 -07001097 if (v.empty()) {
Yingdi Yu348f5ea2014-03-01 14:47:25 -08001098 return;
1099 }
1100
1101 // reflect the changes on digest tree
1102 {
1103 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
1104 m_scene->processUpdate(v, m_sock->getRootDigest().c_str());
1105 }
1106
1107 int n = v.size();
1108 int totalMissingPackets = 0;
Yingdi Yu0b0a7362014-08-05 16:31:30 -07001109 for (int i = 0; i < n; i++) {
Yingdi Yu348f5ea2014-03-01 14:47:25 -08001110 totalMissingPackets += v[i].high.getSeq() - v[i].low.getSeq() + 1;
1111 }
1112
Yingdi Yu0b0a7362014-08-05 16:31:30 -07001113 for (int i = 0; i < n; i++) {
1114 if (totalMissingPackets < 4) {
1115 for (Sync::SeqNo seq = v[i].low; seq <= v[i].high; ++seq) {
Yingdi Yu348f5ea2014-03-01 14:47:25 -08001116 m_sock->fetchData(v[i].prefix, seq, bind(&ChatDialog::processDataWrapper, this, _1), 2);
Yingdi Yu0b0a7362014-08-05 16:31:30 -07001117 // _LOG_DEBUG("<<< Fetching " << v[i].prefix << "/" <<seq.getSession() <<"/" << seq.getSeq());
Yingdi Yu348f5ea2014-03-01 14:47:25 -08001118 }
1119 }
Yingdi Yu0b0a7362014-08-05 16:31:30 -07001120 else {
1121 m_sock->fetchData(v[i].prefix, v[i].high,
1122 bind(&ChatDialog::processDataNoShowWrapper, this, _1), 2);
Yingdi Yu348f5ea2014-03-01 14:47:25 -08001123 }
1124 }
1125 // adjust the view
1126 fitView();
1127}
1128
1129void
1130ChatDialog::onReplot()
1131{
1132 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
1133 m_scene->plot(m_sock->getRootDigest().c_str());
1134 fitView();
1135}
1136
1137void
1138ChatDialog::onRosterChanged(QStringList staleUserList)
1139{
1140 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
1141 QStringList rosterList = m_scene->getRosterList();
1142 m_rosterModel->setStringList(rosterList);
1143 QString user;
1144 QStringListIterator it(staleUserList);
Yingdi Yu0b0a7362014-08-05 16:31:30 -07001145 while (it.hasNext()) {
1146 string nick = it.next().toStdString();
Yingdi Yu348f5ea2014-03-01 14:47:25 -08001147 if (nick.empty())
1148 continue;
1149
1150 SyncDemo::ChatMessage msg;
1151 formControlMessage(msg, SyncDemo::ChatMessage::LEAVE);
1152 msg.set_from(nick);
1153 appendMessage(msg);
1154 }
Yingdi Yuf4aaa8b2014-03-10 11:24:31 -07001155 plotTrustTree();
Yingdi Yu348f5ea2014-03-01 14:47:25 -08001156}
1157
1158void
1159ChatDialog::onInviteListDialogRequested()
1160{
Yingdi Yu233a9722014-03-07 15:47:09 -08001161 emit waitForContactList();
Yingdi Yu348f5ea2014-03-01 14:47:25 -08001162 m_inviteListDialog->setInviteLabel(m_chatroomPrefix.toUri());
1163 m_inviteListDialog->show();
1164}
1165
1166void
1167ChatDialog::sendJoin()
1168{
1169 m_joined = true;
1170 SyncDemo::ChatMessage msg;
1171 formControlMessage(msg, SyncDemo::ChatMessage::JOIN);
1172 sendMsg(msg);
1173 boost::random::random_device rng;
1174 boost::random::uniform_int_distribution<> uniform(1, FRESHNESS / 5 * 1000);
1175 m_randomizedInterval = HELLO_INTERVAL * 1000 + uniform(rng);
1176 QTimer::singleShot(m_randomizedInterval, this, SLOT(sendHello()));
1177}
1178
1179void
1180ChatDialog::sendHello()
1181{
Yingdi Yua7876722014-03-25 14:46:55 -07001182 int64_t now = time::toUnixTimestamp(time::system_clock::now()).count();
Yingdi Yu348f5ea2014-03-01 14:47:25 -08001183 int elapsed = (now - m_lastMsgTime) / 1000000000;
Yingdi Yu0b0a7362014-08-05 16:31:30 -07001184 if (elapsed >= m_randomizedInterval / 1000) {
Yingdi Yu348f5ea2014-03-01 14:47:25 -08001185 SyncDemo::ChatMessage msg;
1186 formControlMessage(msg, SyncDemo::ChatMessage::HELLO);
1187 sendMsg(msg);
1188 boost::random::random_device rng;
1189 boost::random::uniform_int_distribution<> uniform(1, FRESHNESS / 5 * 1000);
1190 m_randomizedInterval = HELLO_INTERVAL * 1000 + uniform(rng);
1191 QTimer::singleShot(m_randomizedInterval, this, SLOT(sendHello()));
1192 }
Yingdi Yu0b0a7362014-08-05 16:31:30 -07001193 else {
Yingdi Yu348f5ea2014-03-01 14:47:25 -08001194 QTimer::singleShot((m_randomizedInterval - elapsed * 1000), this, SLOT(sendHello()));
1195 }
1196}
1197
1198void
1199ChatDialog::sendLeave()
1200{
1201 SyncDemo::ChatMessage msg;
1202 formControlMessage(msg, SyncDemo::ChatMessage::LEAVE);
1203 sendMsg(msg);
1204 usleep(500000);
1205 m_sock->leave();
1206 usleep(5000);
1207 m_joined = false;
Yingdi Yu0b0a7362014-08-05 16:31:30 -07001208 // _LOG_DEBUG("Sync REMOVE signal sent");
Yingdi Yu348f5ea2014-03-01 14:47:25 -08001209}
1210
Yingdi Yuf4aaa8b2014-03-10 11:24:31 -07001211void ChatDialog::enableSyncTreeDisplay()
Yingdi Yu348f5ea2014-03-01 14:47:25 -08001212{
Yingdi Yuf4aaa8b2014-03-10 11:24:31 -07001213 ui->syncTreeButton->setEnabled(true);
Yingdi Yu348f5ea2014-03-01 14:47:25 -08001214 // treeViewer->show();
1215 // fitView();
1216}
1217
1218void
1219ChatDialog::reap()
1220{
Yingdi Yu0b0a7362014-08-05 16:31:30 -07001221 if (m_zombieIndex < m_zombieList.size()) {
1222 string prefix = m_zombieList.at(m_zombieIndex).toStdString();
Yingdi Yu348f5ea2014-03-01 14:47:25 -08001223 m_sock->remove(prefix);
Yingdi Yu0b0a7362014-08-05 16:31:30 -07001224 // _LOG_DEBUG("Reaped: prefix = " << prefix);
Yingdi Yu348f5ea2014-03-01 14:47:25 -08001225 m_zombieIndex++;
1226 // reap again in 10 seconds
1227 QTimer::singleShot(10000, this, SLOT(reap()));
1228 }
1229}
1230
1231void
1232ChatDialog::onSendInvitation(QString invitee)
1233{
1234 Name inviteeNamespace(invitee.toStdString());
1235 shared_ptr<Contact> inviteeItem = m_contactManager->getContact(inviteeNamespace);
1236 sendInvitation(inviteeItem, true);
1237}
1238
Yingdi Yufa0b6a02014-04-30 14:26:42 -07001239void
1240ChatDialog::onReply(const Interest& interest,
Yingdi Yu233a9722014-03-07 15:47:09 -08001241 const shared_ptr<const Data>& data,
Yingdi Yu348f5ea2014-03-01 14:47:25 -08001242 size_t routablePrefixOffset,
1243 bool isIntroducer)
1244{
1245 OnDataValidated onValidated = bind(&ChatDialog::onReplyValidated,
Yingdi Yufa0b6a02014-04-30 14:26:42 -07001246 this, _1,
Yingdi Yu0b0a7362014-08-05 16:31:30 -07001247 //RoutablePrefix will be removed before passing to validator
1248 interest.getName().size()-routablePrefixOffset,
Yingdi Yu348f5ea2014-03-01 14:47:25 -08001249 isIntroducer);
1250
1251 OnDataValidationFailed onFailed = bind(&ChatDialog::onReplyValidationFailed,
1252 this, _1, _2);
1253
Yingdi Yu0b0a7362014-08-05 16:31:30 -07001254 if (routablePrefixOffset > 0) {
1255 // It is an encapsulated packet, we only validate the inner packet.
1256 shared_ptr<Data> innerData = make_shared<Data>();
1257 innerData->wireDecode(data->getContent().blockFromValue());
1258 m_invitationValidator->validate(*innerData, onValidated, onFailed);
1259 }
Yingdi Yu348f5ea2014-03-01 14:47:25 -08001260 else
Yingdi Yu233a9722014-03-07 15:47:09 -08001261 m_invitationValidator->validate(*data, onValidated, onFailed);
Yingdi Yu348f5ea2014-03-01 14:47:25 -08001262}
1263
1264void
Yingdi Yufa0b6a02014-04-30 14:26:42 -07001265ChatDialog::onReplyTimeout(const Interest& interest,
Yingdi Yu348f5ea2014-03-01 14:47:25 -08001266 size_t routablePrefixOffset)
1267{
1268 Name interestName;
Yingdi Yu0b0a7362014-08-05 16:31:30 -07001269 if (routablePrefixOffset > 0)
Yingdi Yu348f5ea2014-03-01 14:47:25 -08001270 interestName = interest.getName().getSubName(routablePrefixOffset);
1271 else
1272 interestName = interest.getName();
1273
1274 Invitation invitation(interestName);
1275
Yingdi Yu0b0a7362014-08-05 16:31:30 -07001276 QString msg = QString::fromUtf8("Your invitation to ") +
1277 QString::fromStdString(invitation.getInviteeNameSpace().toUri()) + " times out!";
Yingdi Yu348f5ea2014-03-01 14:47:25 -08001278 emit inivationRejection(msg);
1279}
1280
1281void
Yingdi Yu233a9722014-03-07 15:47:09 -08001282ChatDialog::onIntroCert(const Interest& interest, const shared_ptr<const Data>& data)
Yingdi Yu348f5ea2014-03-01 14:47:25 -08001283{
1284 Data innerData;
Yingdi Yu233a9722014-03-07 15:47:09 -08001285 innerData.wireDecode(data->getContent().blockFromValue());
Yingdi Yu348f5ea2014-03-01 14:47:25 -08001286 Sync::IntroCertificate introCert(innerData);
1287 m_sock->addParticipant(introCert);
Yingdi Yuf4aaa8b2014-03-10 11:24:31 -07001288 plotTrustTree();
Yingdi Yu348f5ea2014-03-01 14:47:25 -08001289}
1290
1291void
Yingdi Yu233a9722014-03-07 15:47:09 -08001292ChatDialog::onIntroCertTimeout(const Interest& interest, int retry, const QString& msg)
Yingdi Yu348f5ea2014-03-01 14:47:25 -08001293{
Yingdi Yu0b0a7362014-08-05 16:31:30 -07001294 // _LOG_DEBUG("onIntroCertTimeout: " << msg.toStdString());
Yingdi Yu348f5ea2014-03-01 14:47:25 -08001295}
1296
Yingdi Yu0b0a7362014-08-05 16:31:30 -07001297} // namespace chronos
Yingdi Yu348f5ea2014-03-01 14:47:25 -08001298
Yingdi Yu348f5ea2014-03-01 14:47:25 -08001299#if WAF
1300#include "chat-dialog.moc"
1301#include "chat-dialog.cpp.moc"
1302#endif