blob: 4ecb7dbe79e6bae74c6a53c01ee991345145b04d [file] [log] [blame]
Yingdi Yu04842232013-10-23 14:03:09 -07001/* -*- 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 *
Yingdi Yu42f66462013-10-31 17:38:22 -07008 * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
9 * Alexander Afanasyev <alexander.afanasyev@ucla.edu>
10 * Yingdi Yu <yingdi@cs.ucla.edu>
Yingdi Yu04842232013-10-23 14:03:09 -070011 */
12
13#include "chatdialog.h"
14#include "ui_chatdialog.h"
15
Yingdi Yu42f66462013-10-31 17:38:22 -070016#include <QScrollBar>
17
Yingdi Yuc4d08d22013-10-23 23:07:29 -070018#ifndef Q_MOC_RUN
19#include <ndn.cxx/security/identity/identity-manager.h>
Yingdi Yuc4d08d22013-10-23 23:07:29 -070020#include <ndn.cxx/security/encryption/basic-encryption-manager.h>
Yingdi Yu42f66462013-10-31 17:38:22 -070021#include <sync-intro-certificate.h>
22#include <boost/random/random_device.hpp>
23#include <boost/random/uniform_int_distribution.hpp>
Yingdi Yuc4d08d22013-10-23 23:07:29 -070024#include "logging.h"
25#endif
26
Yingdi Yu04842232013-10-23 14:03:09 -070027using namespace std;
Yingdi Yu04842232013-10-23 14:03:09 -070028
Yingdi Yuc4d08d22013-10-23 23:07:29 -070029INIT_LOGGER("ChatDialog");
30
Yingdi Yu42f66462013-10-31 17:38:22 -070031static const int HELLO_INTERVAL = FRESHNESS * 3 / 4;
32
33Q_DECLARE_METATYPE(std::vector<Sync::MissingDataInfo> )
34Q_DECLARE_METATYPE(size_t)
35
36ChatDialog::ChatDialog(ndn::Ptr<ContactManager> contactManager,
37 const ndn::Name& chatroomPrefix,
38 const ndn::Name& localPrefix,
39 const ndn::Name& defaultIdentity,
Yingdi Yu04842232013-10-23 14:03:09 -070040 QWidget *parent)
Yingdi Yu42f66462013-10-31 17:38:22 -070041: QDialog(parent)
42 , ui(new Ui::ChatDialog)
43 , m_contactManager(contactManager)
44 , m_chatroomPrefix(chatroomPrefix)
45 , m_localPrefix(localPrefix)
46 , m_defaultIdentity(defaultIdentity)
47 , m_invitationPolicyManager(ndn::Ptr<InvitationPolicyManager>(new InvitationPolicyManager(m_chatroomPrefix.get(-1).toUri())))
48 , m_sock(NULL)
49 , m_lastMsgTime(0)
50 // , m_historyInitialized(false)
51 , m_joined(false)
52 , m_inviteListDialog(new InviteListDialog(m_contactManager))
Yingdi Yu04842232013-10-23 14:03:09 -070053{
Yingdi Yu42f66462013-10-31 17:38:22 -070054 qRegisterMetaType<std::vector<Sync::MissingDataInfo> >("std::vector<Sync::MissingDataInfo>");
55 qRegisterMetaType<size_t>("size_t");
56
Yingdi Yuc4d08d22013-10-23 23:07:29 -070057 ui->setupUi(this);
58
Yingdi Yu42f66462013-10-31 17:38:22 -070059 m_localChatPrefix = m_localPrefix;
60 m_localChatPrefix.append("FH").append(m_defaultIdentity);
61 m_localChatPrefix.append("chronos").append(m_chatroomPrefix.get(-1));
62
63 m_session = time(NULL);
64 m_scene = new DigestTreeScene(this);
65
66 initializeSetting();
67 updateLabels();
68
69 ui->treeViewer->setScene(m_scene);
70 ui->treeViewer->hide();
71 m_scene->plot("Empty");
72 QRectF rect = m_scene->itemsBoundingRect();
73 m_scene->setSceneRect(rect);
74
75 m_rosterModel = new QStringListModel(this);
76 ui->listView->setModel(m_rosterModel);
77
78 m_timer = new QTimer(this);
79
Yingdi Yuc4d08d22013-10-23 23:07:29 -070080 setWrapper();
Yingdi Yu42f66462013-10-31 17:38:22 -070081
82 connect(ui->inviteButton, SIGNAL(clicked()),
83 this, SLOT(openInviteListDialog()));
84 connect(m_inviteListDialog, SIGNAL(invitionDetermined(QString, bool)),
85 this, SLOT(sendInvitationWrapper(QString, bool)));
86 connect(ui->lineEdit, SIGNAL(returnPressed()),
87 this, SLOT(returnPressed()));
88 connect(ui->treeButton, SIGNAL(pressed()),
89 this, SLOT(treeButtonPressed()));
90 connect(this, SIGNAL(dataReceived(QString, const char *, size_t, bool, bool)),
91 this, SLOT(processData(QString, const char *, size_t, bool, bool)));
92 connect(this, SIGNAL(treeUpdated(const std::vector<Sync::MissingDataInfo>)),
93 this, SLOT(processTreeUpdate(const std::vector<Sync::MissingDataInfo>)));
94 connect(m_timer, SIGNAL(timeout()),
95 this, SLOT(replot()));
96 connect(m_scene, SIGNAL(replot()),
97 this, SLOT(replot()));
98 // TODO: TrayIcon
99 // connect(trayIcon, SIGNAL(messageClicked()),
100 // this, SLOT(showNormal()));
101 // connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
102 // this, SLOT(iconActivated(QSystemTrayIcon::ActivationReason)));
103 connect(m_scene, SIGNAL(rosterChanged(QStringList)),
104 this, SLOT(updateRosterList(QStringList)));
105
106 // m_identityManager = ndn::Ptr<ndn::security::IdentityManager>::Create();
107 // // ndn::Ptr<ndn::security::EncryptionManager> encryptionManager = ndn::Ptr<ndn::security::EncryptionManager>(new ndn::security::BasicEncryptionManager(privateStorage, "/tmp/encryption.db"));
108
109 // ndn::Name certificateName = m_identityManager->getDefaultCertificateNameByIdentity(m_defaultIdentity);
110 // m_syncPolicyManager = ndn::Ptr<SyncPolicyManager>(new SyncPolicyManager(m_defaultIdentity, certificateName, m_chatroomPrefix));
111
112 initializeSync();
Yingdi Yu04842232013-10-23 14:03:09 -0700113}
114
Yingdi Yu42f66462013-10-31 17:38:22 -0700115// ChatDialog::ChatDialog(const ndn::Name& chatroomPrefix,
116// const ndn::Name& localPrefix,
117// const ndn::Name& defaultIdentity,
118// const ndn::security::IdentityCertificate& identityCertificate,
119// QWidget *parent)
120// : QDialog(parent)
121// , ui(new Ui::ChatDialog)
122// , m_chatroomPrefix(chatroomPrefix)
123// , m_localPrefix(localPrefix)
124// , m_defaultIdentity(defaultIdentity)
125// , m_invitationPolicyManager(ndn::Ptr<InvitationPolicyManager>(new InvitationPolicyManager(m_chatroomPrefix.get(-1).toUri())))
126
127// , m_sock(NULL)
128// , m_lastMsgTime(0)
129// // , m_historyInitialized(false)
130// , m_joined(false)
131// {
132// qRegisterMetaType<std::vector<Sync::MissingDataInfo> >("std::vector<Sync::MissingDataInfo>");
133// qRegisterMetaType<size_t>("size_t");
134
135// ui->setupUi(this);
136
137// m_localChatPrefix = m_localPrefix;
138// m_localChatPrefix.append("FH").append(m_defaultIdentity);
139// m_localChatPrefix.append("chronos").append(m_chatroomPrefix.get(-1));
140
141// m_session = time(NULL);
142// m_scene = new DigestTreeScene(this);
143
144// initializeSetting();
145// updateLabels();
146
147// ui->treeViewer->setScene(m_scene);
148// ui->treeViewer->hide();
149// m_scene->plot("Empty");
150// QRectF rect = m_scene->itemsBoundingRect();
151// m_scene->setSceneRect(rect);
152
153// m_rosterModel = new QStringListModel(this);
154// ui->listView->setModel(m_rosterModel);
155
156// m_timer = new QTimer(this);
157
158// setWrapper();
159
160// connect(ui->lineEdit, SIGNAL(returnPressed()),
161// this, SLOT(returnPressed()));
162// connect(ui->treeButton, SIGNAL(pressed()),
163// this, SLOT(treeButtonPressed()));
164// connect(this, SIGNAL(dataReceived(QString, const char *, size_t, bool, bool)),
165// this, SLOT(processData(QString, const char *, size_t, bool, bool)));
166// connect(this, SIGNAL(treeUpdated(const std::vector<Sync::MissingDataInfo>)),
167// this, SLOT(processTreeUpdate(const std::vector<Sync::MissingDataInfo>)));
168// connect(m_timer, SIGNAL(timeout()),
169// this, SLOT(replot()));
170// connect(m_scene, SIGNAL(replot()),
171// this, SLOT(replot()));
172// // TODO: TrayIcon
173// // connect(trayIcon, SIGNAL(messageClicked()),
174// // this, SLOT(showNormal()));
175// // connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
176// // this, SLOT(iconActivated(QSystemTrayIcon::ActivationReason)));
177// connect(m_scene, SIGNAL(rosterChanged(QStringList)),
178// this, SLOT(updateRosterList(QStringList)));
179
180// // m_identityManager = ndn::Ptr<ndn::security::IdentityManager>::Create();
181// // // ndn::Ptr<ndn::security::EncryptionManager> encryptionManager = ndn::Ptr<ndn::security::EncryptionManager>(new ndn::security::BasicEncryptionManager(privateStorage, "/tmp/encryption.db"));
182
183// // ndn::Name certificateName = m_identityManager->getDefaultCertificateNameByIdentity(m_defaultIdentity);
184// // m_syncPolicyManager = ndn::Ptr<SyncPolicyManager>(new SyncPolicyManager(m_defaultIdentity, certificateName, m_chatroomPrefix));
185
186// initializeSync();
187// }
188
Yingdi Yu04842232013-10-23 14:03:09 -0700189ChatDialog::~ChatDialog()
190{
Yingdi Yuc4d08d22013-10-23 23:07:29 -0700191 delete ui;
Yingdi Yu42f66462013-10-31 17:38:22 -0700192 sendLeave();
Yingdi Yuc4d08d22013-10-23 23:07:29 -0700193 m_handler->shutdown();
Yingdi Yu04842232013-10-23 14:03:09 -0700194}
195
196void
Yingdi Yuc4d08d22013-10-23 23:07:29 -0700197ChatDialog::setWrapper()
Yingdi Yu04842232013-10-23 14:03:09 -0700198{
Yingdi Yu42f66462013-10-31 17:38:22 -0700199 m_identityManager = ndn::Ptr<ndn::security::IdentityManager>::Create();
200 // ndn::Ptr<ndn::security::EncryptionManager> encryptionManager = ndn::Ptr<ndn::security::EncryptionManager>(new ndn::security::BasicEncryptionManager(privateStorage, "/tmp/encryption.db"));
Yingdi Yuc4d08d22013-10-23 23:07:29 -0700201
Yingdi Yu42f66462013-10-31 17:38:22 -0700202 ndn::Name certificateName = m_identityManager->getDefaultCertificateNameByIdentity(m_defaultIdentity);
203 m_syncPolicyManager = ndn::Ptr<SyncPolicyManager>(new SyncPolicyManager(m_defaultIdentity, certificateName, m_chatroomPrefix));
Yingdi Yuc4d08d22013-10-23 23:07:29 -0700204
Yingdi Yu42f66462013-10-31 17:38:22 -0700205 m_keychain = ndn::Ptr<ndn::security::Keychain>(new ndn::security::Keychain(m_identityManager, m_invitationPolicyManager, NULL));
206
207 m_handler = ndn::Ptr<ndn::Wrapper>(new ndn::Wrapper(m_keychain));
Yingdi Yu04842232013-10-23 14:03:09 -0700208}
209
Yingdi Yuc4d08d22013-10-23 23:07:29 -0700210void
Yingdi Yu42f66462013-10-31 17:38:22 -0700211ChatDialog::initializeSetting()
Yingdi Yuc4d08d22013-10-23 23:07:29 -0700212{
Yingdi Yu42f66462013-10-31 17:38:22 -0700213 // TODO: nick name may be changed.
214 m_user.setNick(QString::fromStdString(m_defaultIdentity.get(-1).toUri()));
215 m_user.setChatroom(QString::fromStdString(m_chatroomPrefix.get(-1).toUri()));
216 m_user.setOriginPrefix(QString::fromStdString(m_localPrefix.toUri()));
217 m_user.setPrefix(QString::fromStdString(m_localChatPrefix.toUri()));
218 m_scene->setCurrentPrefix(QString::fromStdString(m_localChatPrefix.toUri()));
219}
Yingdi Yuc4d08d22013-10-23 23:07:29 -0700220
Yingdi Yu42f66462013-10-31 17:38:22 -0700221void
222ChatDialog::updateLabels()
223{
224 QString settingDisp = QString("Chatroom: %1").arg(m_user.getChatroom());
225 ui->infoLabel->setStyleSheet("QLabel {color: #630; font-size: 16px; font: bold \"Verdana\";}");
226 ui->infoLabel->setText(settingDisp);
227 QString prefixDisp;
228 if (m_user.getPrefix().startsWith("/private/local"))
229 {
230 prefixDisp = QString("<Warning: no connection to hub or hub does not support prefix autoconfig.>\n <Prefix = %1>").arg(m_user.getPrefix());
231 ui->prefixLabel->setStyleSheet("QLabel {color: red; font-size: 12px; font: bold \"Verdana\";}");
232 }
233 else
234 {
235 prefixDisp = QString("<Prefix = %1>").arg(m_user.getPrefix());
236 ui->prefixLabel->setStyleSheet("QLabel {color: Green; font-size: 12px; font: bold \"Verdana\";}");
237 }
238 ui->prefixLabel->setText(prefixDisp);
239}
Yingdi Yuc4d08d22013-10-23 23:07:29 -0700240
Yingdi Yu42f66462013-10-31 17:38:22 -0700241void
242ChatDialog::sendInvitation(ndn::Ptr<ContactItem> contact, bool isIntroducer)
243{
244 m_invitationPolicyManager->addTrustAnchor(contact->getSelfEndorseCertificate());
245
246 ndn::Name certificateName = m_identityManager->getDefaultCertificateNameByIdentity(m_defaultIdentity);
247
248 ndn::Name interestName("/ndn/broadcast/chronos/invitation");
Yingdi Yuc4d08d22013-10-23 23:07:29 -0700249 interestName.append(contact->getNameSpace());
250 interestName.append("chatroom");
251 interestName.append(m_chatroomPrefix.get(-1));
252 interestName.append("inviter-prefix");
253 interestName.append(m_localPrefix);
254 interestName.append("inviter");
255 interestName.append(certificateName);
256
257 string signedUri = interestName.toUri();
Yingdi Yu42f66462013-10-31 17:38:22 -0700258 ndn::Blob signedBlob(signedUri.c_str(), signedUri.size());
Yingdi Yuc4d08d22013-10-23 23:07:29 -0700259
Yingdi Yu42f66462013-10-31 17:38:22 -0700260 ndn::Ptr<const ndn::signature::Sha256WithRsa> sha256sig = ndn::DynamicCast<const ndn::signature::Sha256WithRsa>(m_identityManager->signByCertificate(signedBlob, certificateName));
261 const ndn::Blob& sigBits = sha256sig->getSignatureBits();
Yingdi Yuc4d08d22013-10-23 23:07:29 -0700262
263 interestName.append(sigBits.buf(), sigBits.size());
264
Yingdi Yu42f66462013-10-31 17:38:22 -0700265 ndn::Ptr<ndn::Interest> interest = ndn::Ptr<ndn::Interest>(new ndn::Interest(interestName));
266 ndn::Ptr<ndn::Closure> closure = ndn::Ptr<ndn::Closure>(new ndn::Closure(boost::bind(&ChatDialog::onInviteReplyVerified,
267 this,
268 _1,
269 contact->getNameSpace(),
270 isIntroducer),
271 boost::bind(&ChatDialog::onInviteTimeout,
272 this,
273 _1,
274 _2,
275 contact->getNameSpace(),
276 7),
277 boost::bind(&ChatDialog::onUnverified,
278 this,
279 _1)));
Yingdi Yuc4d08d22013-10-23 23:07:29 -0700280
281 m_handler->sendInterest(interest, closure);
282}
283
284void
Yingdi Yu42f66462013-10-31 17:38:22 -0700285ChatDialog::addTrustAnchor(const EndorseCertificate& selfEndorseCertificate)
286{ m_invitationPolicyManager->addTrustAnchor(selfEndorseCertificate); }
287
288void
289ChatDialog::addChatDataRule(const ndn::Name& prefix,
290 const ndn::security::IdentityCertificate& identityCertificate,
291 bool isIntroducer)
292{ m_syncPolicyManager->addChatDataRule(prefix, identityCertificate, isIntroducer); }
293
294void
295ChatDialog::publishIntroCert(ndn::Ptr<ndn::security::IdentityCertificate> dskCertificate, bool isIntroducer)
Yingdi Yuc4d08d22013-10-23 23:07:29 -0700296{
Yingdi Yu42f66462013-10-31 17:38:22 -0700297 SyncIntroCertificate syncIntroCertificate(m_chatroomPrefix,
298 dskCertificate->getPublicKeyName(),
299 m_identityManager->getDefaultKeyNameForIdentity(m_defaultIdentity),
300 dskCertificate->getNotBefore(),
301 dskCertificate->getNotAfter(),
302 dskCertificate->getPublicKeyInfo(),
303 (isIntroducer ? SyncIntroCertificate::INTRODUCER : SyncIntroCertificate::PRODUCER));
304 ndn::Name certName = m_identityManager->getDefaultCertificateNameByIdentity(m_defaultIdentity);
Yingdi Yued8cfc42013-11-01 17:37:51 -0700305 _LOG_DEBUG("publishIntroCert: " << syncIntroCertificate.getName());
Yingdi Yu42f66462013-10-31 17:38:22 -0700306 m_identityManager->signByCertificate(syncIntroCertificate, certName);
307 m_handler->putToNdnd(*syncIntroCertificate.encodeToWire());
Yingdi Yuc4d08d22013-10-23 23:07:29 -0700308}
309
310void
Yingdi Yu42f66462013-10-31 17:38:22 -0700311ChatDialog::invitationRejected(const ndn::Name& identity)
312{
313 _LOG_DEBUG(" " << identity.toUri() << " rejected your invitation!");
314 //TODO:
315}
316
317void
318ChatDialog::invitationAccepted(const ndn::Name& identity, ndn::Ptr<ndn::Data> data, const string& inviteePrefix, bool isIntroducer)
Yingdi Yuc4d08d22013-10-23 23:07:29 -0700319{
320 _LOG_DEBUG(" " << identity.toUri() << " accepted your invitation!");
Yingdi Yu42f66462013-10-31 17:38:22 -0700321 ndn::Ptr<const ndn::signature::Sha256WithRsa> sha256sig = boost::dynamic_pointer_cast<const ndn::signature::Sha256WithRsa> (data->getSignature());
322 const ndn::Name & keyLocatorName = sha256sig->getKeyLocator().getKeyName();
323 ndn::Ptr<ndn::security::IdentityCertificate> dskCertificate = m_invitationPolicyManager->getValidatedDskCertificate(keyLocatorName);
324 m_syncPolicyManager->addChatDataRule(inviteePrefix, *dskCertificate, isIntroducer);
325 publishIntroCert(dskCertificate, isIntroducer);
Yingdi Yuc4d08d22013-10-23 23:07:29 -0700326}
327
328void
Yingdi Yu42f66462013-10-31 17:38:22 -0700329ChatDialog::onInviteReplyVerified(ndn::Ptr<ndn::Data> data, const ndn::Name& identity, bool isIntroducer)
Yingdi Yuc4d08d22013-10-23 23:07:29 -0700330{
331 string content(data->content().buf(), data->content().size());
332 if(content.empty())
333 invitationRejected(identity);
334 else
Yingdi Yu42f66462013-10-31 17:38:22 -0700335 invitationAccepted(identity, data, content, isIntroducer);
Yingdi Yuc4d08d22013-10-23 23:07:29 -0700336}
337
338void
Yingdi Yu42f66462013-10-31 17:38:22 -0700339ChatDialog::onInviteTimeout(ndn::Ptr<ndn::Closure> closure, ndn::Ptr<ndn::Interest> interest, const ndn::Name& identity, int retry)
Yingdi Yuc4d08d22013-10-23 23:07:29 -0700340{
341 if(retry > 0)
342 {
Yingdi Yu42f66462013-10-31 17:38:22 -0700343 ndn::Ptr<ndn::Closure> newClosure = ndn::Ptr<ndn::Closure>(new ndn::Closure(closure->m_dataCallback,
344 boost::bind(&ChatDialog::onInviteTimeout,
345 this,
346 _1,
347 _2,
348 identity,
349 retry - 1),
350 closure->m_unverifiedCallback,
351 closure->m_stepCount)
352 );
Yingdi Yuc4d08d22013-10-23 23:07:29 -0700353 m_handler->sendInterest(interest, newClosure);
354 }
355 else
356 invitationRejected(identity);
357}
358
359void
Yingdi Yu42f66462013-10-31 17:38:22 -0700360ChatDialog::onUnverified(ndn::Ptr<ndn::Data> data)
Yingdi Yuc4d08d22013-10-23 23:07:29 -0700361{}
362
Yingdi Yu42f66462013-10-31 17:38:22 -0700363void
364ChatDialog::initializeSync()
365{
366
367 m_sock = new Sync::SyncSocket(m_chatroomPrefix.toUri(),
368 m_syncPolicyManager,
369 bind(&ChatDialog::processTreeUpdateWrapper, this, _1, _2),
370 bind(&ChatDialog::processRemoveWrapper, this, _1));
371
372 usleep(100000);
373
374 QTimer::singleShot(600, this, SLOT(sendJoin()));
375 m_timer->start(FRESHNESS * 1000);
376 disableTreeDisplay();
377 QTimer::singleShot(2200, this, SLOT(enableTreeDisplay()));
378 // Sync::CcnxWrapperPtr handle = boost::make_shared<Sync::CcnxWrapper> ();
379 // handle->setInterestFilter(m_user.getPrefix().toStdString(), bind(&ChatDialog::respondHistoryRequest, this, _1));
380 // _LOG_DEBUG("initializeSync is done!");
381}
382
383void
384ChatDialog::returnPressed()
385{
386 QString text = ui->lineEdit->text();
387 if (text.isEmpty())
388 return;
389
390 ui->lineEdit->clear();
391
392 if (text.startsWith("boruoboluomi"))
393 {
394 summonReaper ();
395 // reapButton->show();
396 fitView();
397 return;
398 }
399
400 if (text.startsWith("minimanihong"))
401 {
402 // reapButton->hide();
403 fitView();
404 return;
405 }
406
407 SyncDemo::ChatMessage msg;
408 formChatMessage(text, msg);
409
410 appendMessage(msg);
411
412 sendMsg(msg);
413
414 fitView();
415}
416
417void
418ChatDialog::treeButtonPressed()
419{
420 if (ui->treeViewer->isVisible())
421 {
422 ui->treeViewer->hide();
423 ui->treeButton->setText("Show ChronoSync Tree");
424 }
425 else
426 {
427 ui->treeViewer->show();
428 ui->treeButton->setText("Hide ChronoSync Tree");
429 }
430
431 fitView();
432}
433
434void ChatDialog::disableTreeDisplay()
435{
436 ui->treeButton->setEnabled(false);
437 ui->treeViewer->hide();
438 fitView();
439}
440
441void ChatDialog::enableTreeDisplay()
442{
443 ui->treeButton->setEnabled(true);
444 // treeViewer->show();
445 // fitView();
446}
447
448void
449ChatDialog::processTreeUpdateWrapper(const std::vector<Sync::MissingDataInfo> v, Sync::SyncSocket *sock)
450{
451 emit treeUpdated(v);
452 _LOG_DEBUG("<<< Tree update signal emitted");
453}
454
455void
456ChatDialog::processRemoveWrapper(std::string prefix)
457{
458 _LOG_DEBUG("Sync REMOVE signal received for prefix: " << prefix);
459}
460
461void
462ChatDialog::processTreeUpdate(const std::vector<Sync::MissingDataInfo> v)
463{
464 _LOG_DEBUG("<<< processing Tree Update");
465
466 if (v.empty())
467 {
468 return;
469 }
470
471 // reflect the changes on digest tree
472 {
473 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
474 m_scene->processUpdate(v, m_sock->getRootDigest().c_str());
475 }
476
477 int n = v.size();
478 int totalMissingPackets = 0;
479 for (int i = 0; i < n; i++)
480 {
481 totalMissingPackets += v[i].high.getSeq() - v[i].low.getSeq() + 1;
482 }
483
484 for (int i = 0; i < n; i++)
485 {
486 if (totalMissingPackets < 4)
487 {
488 for (Sync::SeqNo seq = v[i].low; seq <= v[i].high; ++seq)
489 {
490 m_sock->fetchData(v[i].prefix, seq, bind(&ChatDialog::processDataWrapper, this, _1), 2);
491 _LOG_DEBUG("<<< Fetching " << v[i].prefix << "/" <<seq.getSession() <<"/" << seq.getSeq());
492 }
493 }
494 else
495 {
496 m_sock->fetchData(v[i].prefix, v[i].high, bind(&ChatDialog::processDataNoShowWrapper, this, _1), 2);
497 }
498 }
499
500 // adjust the view
501 fitView();
502
503}
504
505void
506ChatDialog::processDataWrapper(ndn::Ptr<ndn::Data> data)
507{
508 string name = data->getName().toUri();
509 const char* buf = data->content().buf();
510 size_t len = data->content().size();
511
512 char *tempBuf = new char[len];
513 memcpy(tempBuf, buf, len);
514 emit dataReceived(name.c_str(), tempBuf, len, true, false);
515 _LOG_DEBUG("<<< " << name << " fetched");
516}
517
518void
519ChatDialog::processDataNoShowWrapper(ndn::Ptr<ndn::Data> data)
520{
521 string name = data->getName().toUri();
522 const char* buf = data->content().buf();
523 size_t len = data->content().size();
524
525 char *tempBuf = new char[len];
526 memcpy(tempBuf, buf, len);
527 emit dataReceived(name.c_str(), tempBuf, len, false, false);
528
529 // if (!m_historyInitialized)
530 // {
531 // fetchHistory(name);
532 // m_historyInitialized = true;
533 // }
534}
535
536// void
537// ChatDialog::fetchHistory(std::string name)
538// {
539
540// /****************************/
541// /* TODO: fix following part */
542// /****************************/
543// string nameWithoutSeq = name.substr(0, name.find_last_of('/'));
544// string prefix = nameWithoutSeq.substr(0, nameWithoutSeq.find_last_of('/'));
545// prefix += "/history";
546// // Ptr<Wrapper>CcnxWrapperPtr handle = boost::make_shared<Sync::CcnxWrapper> ();
547// // QString randomString = getRandomString();
548// // for (int i = 0; i < MAX_HISTORY_ENTRY; i++)
549// // {
550// // QString interest = QString("%1/%2/%3").arg(prefix.c_str()).arg(randomString).arg(i);
551// // handle->sendInterest(interest.toStdString(), bind(&ChatDialog::processDataHistoryWrapper, this, _1, _2, _3));
552// // }
553// }
554
555void
556ChatDialog::processData(QString name, const char *buf, size_t len, bool show, bool isHistory)
557{
558 SyncDemo::ChatMessage msg;
559 bool corrupted = false;
560 if (!msg.ParseFromArray(buf, len))
561 {
562 _LOG_DEBUG("Errrrr.. Can not parse msg with name: " << name.toStdString() << ". what is happening?");
563 // nasty stuff: as a remedy, we'll form some standard msg for inparsable msgs
564 msg.set_from("inconnu");
565 msg.set_type(SyncDemo::ChatMessage::OTHER);
566 corrupted = true;
567 }
568
569 delete [] buf;
570 buf = NULL;
571
572 // display msg received from network
573 // we have to do so; this function is called by ccnd thread
574 // so if we call appendMsg directly
575 // Qt crash as "QObject: Cannot create children for a parent that is in a different thread"
576 // the "cannonical" way to is use signal-slot
577 if (show && !corrupted)
578 {
579 appendMessage(msg, isHistory);
580 }
581
582 if (!isHistory)
583 {
584 // update the tree view
585 std::string stdStrName = name.toStdString();
586 std::string stdStrNameWithoutSeq = stdStrName.substr(0, stdStrName.find_last_of('/'));
587 std::string prefix = stdStrNameWithoutSeq.substr(0, stdStrNameWithoutSeq.find_last_of('/'));
588 _LOG_DEBUG("<<< updating scene for" << prefix << ": " << msg.from());
589 if (msg.type() == SyncDemo::ChatMessage::LEAVE)
590 {
591 processRemove(prefix.c_str());
592 }
593 else
594 {
595 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
596 m_scene->msgReceived(prefix.c_str(), msg.from().c_str());
597 }
598 }
599 fitView();
600}
601
602void
603ChatDialog::processRemove(QString prefix)
604{
605 _LOG_DEBUG("<<< remove node for prefix" << prefix.toStdString());
606
607 bool removed = m_scene->removeNode(prefix);
608 if (removed)
609 {
610 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
611 m_scene->plot(m_sock->getRootDigest().c_str());
612 }
613}
614
615void
616ChatDialog::sendJoin()
617{
618 m_joined = true;
619 SyncDemo::ChatMessage msg;
620 formControlMessage(msg, SyncDemo::ChatMessage::JOIN);
621 sendMsg(msg);
622 boost::random::random_device rng;
623 boost::random::uniform_int_distribution<> uniform(1, FRESHNESS / 5 * 1000);
624 m_randomizedInterval = HELLO_INTERVAL * 1000 + uniform(rng);
625 QTimer::singleShot(m_randomizedInterval, this, SLOT(sendHello()));
626}
627
628void
629ChatDialog::sendHello()
630{
631 time_t now = time(NULL);
632 int elapsed = now - m_lastMsgTime;
633 if (elapsed >= m_randomizedInterval / 1000)
634 {
635 SyncDemo::ChatMessage msg;
636 formControlMessage(msg, SyncDemo::ChatMessage::HELLO);
637 sendMsg(msg);
638 boost::random::random_device rng;
639 boost::random::uniform_int_distribution<> uniform(1, FRESHNESS / 5 * 1000);
640 m_randomizedInterval = HELLO_INTERVAL * 1000 + uniform(rng);
641 QTimer::singleShot(m_randomizedInterval, this, SLOT(sendHello()));
642 }
643 else
644 {
645 QTimer::singleShot((m_randomizedInterval - elapsed * 1000), this, SLOT(sendHello()));
646 }
647}
648
649void
650ChatDialog::sendLeave()
651{
652 SyncDemo::ChatMessage msg;
653 formControlMessage(msg, SyncDemo::ChatMessage::LEAVE);
654 sendMsg(msg);
655 usleep(500000);
656 m_sock->remove(m_user.getPrefix().toStdString());
657 usleep(5000);
658 m_joined = false;
659 _LOG_DEBUG("Sync REMOVE signal sent");
660}
661
662void
663ChatDialog::replot()
664{
665 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
666 m_scene->plot(m_sock->getRootDigest().c_str());
667 fitView();
668}
669
670void
671ChatDialog::summonReaper()
672{
673 Sync::SyncLogic &logic = m_sock->getLogic ();
674 map<string, bool> branches = logic.getBranchPrefixes();
675 QMap<QString, DisplayUserPtr> roster = m_scene->getRosterFull();
676
677 m_zombieList.clear();
678
679 QMapIterator<QString, DisplayUserPtr> it(roster);
680 map<string, bool>::iterator mapIt;
681 while(it.hasNext())
682 {
683 it.next();
684 DisplayUserPtr p = it.value();
685 if (p != DisplayUserNullPtr)
686 {
687 mapIt = branches.find(p->getPrefix().toStdString());
688 if (mapIt != branches.end())
689 {
690 mapIt->second = true;
691 }
692 }
693 }
694
695 for (mapIt = branches.begin(); mapIt != branches.end(); ++mapIt)
696 {
697 // this is zombie. all active users should have been marked true
698 if (! mapIt->second)
699 {
700 m_zombieList.append(mapIt->first.c_str());
701 }
702 }
703
704 m_zombieIndex = 0;
705
706 // start reaping
707 reap();
708}
709
710void
711ChatDialog::reap()
712{
713 if (m_zombieIndex < m_zombieList.size())
714 {
715 string prefix = m_zombieList.at(m_zombieIndex).toStdString();
716 m_sock->remove(prefix);
717 _LOG_DEBUG("Reaped: prefix = " << prefix);
718 m_zombieIndex++;
719 // reap again in 10 seconds
720 QTimer::singleShot(10000, this, SLOT(reap()));
721 }
722}
723
724void
725ChatDialog::updateRosterList(QStringList staleUserList)
726{
727 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
728 QStringList rosterList = m_scene->getRosterList();
729 m_rosterModel->setStringList(rosterList);
730 QString user;
731 QStringListIterator it(staleUserList);
732 while(it.hasNext())
733 {
734 std::string nick = it.next().toStdString();
735 if (nick.empty())
736 continue;
737
738 SyncDemo::ChatMessage msg;
739 formControlMessage(msg, SyncDemo::ChatMessage::LEAVE);
740 msg.set_from(nick);
741 appendMessage(msg);
742 }
743}
744
745void
746ChatDialog::resizeEvent(QResizeEvent *e)
747{
748 fitView();
749}
750
751void
752ChatDialog::showEvent(QShowEvent *e)
753{
754 fitView();
755}
756
757void
758ChatDialog::fitView()
759{
760 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
761 QRectF rect = m_scene->itemsBoundingRect();
762 m_scene->setSceneRect(rect);
763 ui->treeViewer->fitInView(m_scene->itemsBoundingRect(), Qt::KeepAspectRatio);
764}
765
766void
767ChatDialog::formChatMessage(const QString &text, SyncDemo::ChatMessage &msg) {
768 msg.set_from(m_user.getNick().toStdString());
769 msg.set_to(m_user.getChatroom().toStdString());
770 msg.set_data(text.toUtf8().constData());
771 time_t seconds = time(NULL);
772 msg.set_timestamp(seconds);
773 msg.set_type(SyncDemo::ChatMessage::CHAT);
774}
775
776void
777ChatDialog::formControlMessage(SyncDemo::ChatMessage &msg, SyncDemo::ChatMessage::ChatMessageType type)
778{
779 msg.set_from(m_user.getNick().toStdString());
780 msg.set_to(m_user.getChatroom().toStdString());
781 time_t seconds = time(NULL);
782 msg.set_timestamp(seconds);
783 msg.set_type(type);
784}
785
786void
787ChatDialog::appendMessage(const SyncDemo::ChatMessage msg, bool isHistory)
788{
789 boost::recursive_mutex::scoped_lock lock(m_msgMutex);
790
791 if (msg.type() == SyncDemo::ChatMessage::CHAT)
792 {
793
794 if (!msg.has_data())
795 {
796 return;
797 }
798
799 if (msg.from().empty() || msg.data().empty())
800 {
801 return;
802 }
803
804 if (!msg.has_timestamp())
805 {
806 return;
807 }
808
809 // if (m_history.size() == MAX_HISTORY_ENTRY)
810 // {
811 // m_history.dequeue();
812 // }
813
814 // m_history.enqueue(msg);
815
816 QTextCharFormat nickFormat;
817 nickFormat.setForeground(Qt::darkGreen);
818 nickFormat.setFontWeight(QFont::Bold);
819 nickFormat.setFontUnderline(true);
820 nickFormat.setUnderlineColor(Qt::gray);
821
822 QTextCursor cursor(ui->textEdit->textCursor());
823 cursor.movePosition(QTextCursor::End);
824 QTextTableFormat tableFormat;
825 tableFormat.setBorder(0);
826 QTextTable *table = cursor.insertTable(1, 2, tableFormat);
827 QString from = QString("%1 ").arg(msg.from().c_str());
828 QTextTableCell fromCell = table->cellAt(0, 0);
829 fromCell.setFormat(nickFormat);
830 fromCell.firstCursorPosition().insertText(from);
831
832 time_t timestamp = msg.timestamp();
833 printTimeInCell(table, timestamp);
834
835 QTextCursor nextCursor(ui->textEdit->textCursor());
836 nextCursor.movePosition(QTextCursor::End);
837 table = nextCursor.insertTable(1, 1, tableFormat);
838 table->cellAt(0, 0).firstCursorPosition().insertText(QString::fromUtf8(msg.data().c_str()));
839 if (!isHistory)
840 {
841 showMessage(from, QString::fromUtf8(msg.data().c_str()));
842 }
843 }
844
845 if (msg.type() == SyncDemo::ChatMessage::JOIN || msg.type() == SyncDemo::ChatMessage::LEAVE)
846 {
847 QTextCharFormat nickFormat;
848 nickFormat.setForeground(Qt::gray);
849 nickFormat.setFontWeight(QFont::Bold);
850 nickFormat.setFontUnderline(true);
851 nickFormat.setUnderlineColor(Qt::gray);
852
853 QTextCursor cursor(ui->textEdit->textCursor());
854 cursor.movePosition(QTextCursor::End);
855 QTextTableFormat tableFormat;
856 tableFormat.setBorder(0);
857 QTextTable *table = cursor.insertTable(1, 2, tableFormat);
858 QString action;
859 if (msg.type() == SyncDemo::ChatMessage::JOIN)
860 {
861 action = "enters room";
862 }
863 else
864 {
865 action = "leaves room";
866 }
867
868 QString from = QString("%1 %2 ").arg(msg.from().c_str()).arg(action);
869 QTextTableCell fromCell = table->cellAt(0, 0);
870 fromCell.setFormat(nickFormat);
871 fromCell.firstCursorPosition().insertText(from);
872
873 time_t timestamp = msg.timestamp();
874 printTimeInCell(table, timestamp);
875 }
876
877 QScrollBar *bar = ui->textEdit->verticalScrollBar();
878 bar->setValue(bar->maximum());
879}
880
881QString
882ChatDialog::formatTime(time_t timestamp)
883{
884 struct tm *tm_time = localtime(&timestamp);
885 int hour = tm_time->tm_hour;
886 QString amOrPM;
887 if (hour > 12)
888 {
889 hour -= 12;
890 amOrPM = "PM";
891 }
892 else
893 {
894 amOrPM = "AM";
895 if (hour == 0)
896 {
897 hour = 12;
898 }
899 }
900
901 char textTime[12];
902 sprintf(textTime, "%d:%02d:%02d %s", hour, tm_time->tm_min, tm_time->tm_sec, amOrPM.toStdString().c_str());
903 return QString(textTime);
904}
905
906void
907ChatDialog::printTimeInCell(QTextTable *table, time_t timestamp)
908{
909 QTextCharFormat timeFormat;
910 timeFormat.setForeground(Qt::gray);
911 timeFormat.setFontUnderline(true);
912 timeFormat.setUnderlineColor(Qt::gray);
913 QTextTableCell timeCell = table->cellAt(0, 1);
914 timeCell.setFormat(timeFormat);
915 timeCell.firstCursorPosition().insertText(formatTime(timestamp));
916}
917
918void
919ChatDialog::showMessage(QString from, QString data)
920{
921 if (!isActiveWindow())
922 {
923 //TODO: Notification to be done
924 // trayIcon->showMessage(QString("Chatroom %1 has a new message").arg(m_user.getChatroom()), QString("<%1>: %2").arg(from).arg(data), QSystemTrayIcon::Information, 20000);
925 // trayIcon->setIcon(QIcon(":/images/note.png"));
926 }
927}
928
929void
930ChatDialog::sendMsg(SyncDemo::ChatMessage &msg)
931{
932 // send msg
933 size_t size = msg.ByteSize();
934 char *buf = new char[size];
935 msg.SerializeToArray(buf, size);
936 if (!msg.IsInitialized())
937 {
938 _LOG_DEBUG("Errrrr.. msg was not probally initialized "<<__FILE__ <<":"<<__LINE__<<". what is happening?");
939 abort();
940 }
941 m_sock->publishData(m_user.getPrefix().toStdString(), m_session, buf, size, FRESHNESS);
942
943 delete buf;
944
945 m_lastMsgTime = time(NULL);
946
947 int nextSequence = m_sock->getNextSeq(m_user.getPrefix().toStdString(), m_session);
948 Sync::MissingDataInfo mdi = {m_user.getPrefix().toStdString(), Sync::SeqNo(0), Sync::SeqNo(nextSequence - 1)};
949 std::vector<Sync::MissingDataInfo> v;
950 v.push_back(mdi);
951 {
952 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
953 m_scene->processUpdate(v, m_sock->getRootDigest().c_str());
954 m_scene->msgReceived(m_user.getPrefix(), m_user.getNick());
955 }
956}
957
958void
959ChatDialog::openInviteListDialog()
960{
961 m_inviteListDialog->setInviteLabel(m_chatroomPrefix.toUri());
962 m_inviteListDialog->show();
963}
964
965void
966ChatDialog::sendInvitationWrapper(QString invitee, bool isIntroducer)
967{
968 ndn::Name inviteeNamespace(invitee.toUtf8().constData());
969 ndn::Ptr<ContactItem> inviteeItem = m_contactManager->getContact(inviteeNamespace);
970 sendInvitation(inviteeItem, isIntroducer);
971}
972
973
Yingdi Yu04842232013-10-23 14:03:09 -0700974#if WAF
975#include "chatdialog.moc"
976#include "chatdialog.cpp.moc"
977#endif