blob: ce972c32223898c127e3e362e3229b7b5d007605 [file] [log] [blame]
Alexander Afanasyevb4b92292013-07-09 13:54:59 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
2/*
3 * Copyright (c) 2013, Regents of the University of California
Yingdi Yu5b989132013-10-23 14:03:09 -07004 * Yingdi Yu
Alexander Afanasyevb4b92292013-07-09 13:54:59 -07005 *
Yingdi Yu5b989132013-10-23 14:03:09 -07006 * BSD license, See the LICENSE file for more information
Alexander Afanasyevb4b92292013-07-09 13:54:59 -07007 *
Yingdi Yu7989eb22013-10-31 17:38:22 -07008 * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
9 * Alexander Afanasyev <alexander.afanasyev@ucla.edu>
10 * Yingdi Yu <yingdi@cs.ucla.edu>
Alexander Afanasyevb4b92292013-07-09 13:54:59 -070011 */
12
Zhenkai Zhu6d589aa2012-05-29 17:34:35 -070013#include "chatdialog.h"
Yingdi Yu5b989132013-10-23 14:03:09 -070014#include "ui_chatdialog.h"
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -070015
Yingdi Yu7989eb22013-10-31 17:38:22 -070016#include <QScrollBar>
Yingdi Yu702d6f12013-11-07 17:00:54 -080017#include <QMessageBox>
18#include <QCloseEvent>
Yingdi Yu7989eb22013-10-31 17:38:22 -070019
Yingdi Yueda39aa2013-10-23 23:07:29 -070020#ifndef Q_MOC_RUN
21#include <ndn.cxx/security/identity/identity-manager.h>
Yingdi Yufdb8ab82013-11-10 01:38:21 -080022#include <ndn.cxx/security/policy/no-verify-policy-manager.h>
Yingdi Yueda39aa2013-10-23 23:07:29 -070023#include <ndn.cxx/security/encryption/basic-encryption-manager.h>
Yingdi Yu7989eb22013-10-31 17:38:22 -070024#include <sync-intro-certificate.h>
25#include <boost/random/random_device.hpp>
26#include <boost/random/uniform_int_distribution.hpp>
Yingdi Yueda39aa2013-10-23 23:07:29 -070027#include "logging.h"
28#endif
29
Yingdi Yu5b989132013-10-23 14:03:09 -070030using namespace std;
Alexander Afanasyevf829f4d2013-05-07 15:59:36 -070031
Yingdi Yueda39aa2013-10-23 23:07:29 -070032INIT_LOGGER("ChatDialog");
33
Yingdi Yu7989eb22013-10-31 17:38:22 -070034static const int HELLO_INTERVAL = FRESHNESS * 3 / 4;
35
36Q_DECLARE_METATYPE(std::vector<Sync::MissingDataInfo> )
37Q_DECLARE_METATYPE(size_t)
38
39ChatDialog::ChatDialog(ndn::Ptr<ContactManager> contactManager,
40 const ndn::Name& chatroomPrefix,
41 const ndn::Name& localPrefix,
42 const ndn::Name& defaultIdentity,
Yingdi Yu46948282013-11-06 18:43:31 -080043 const std::string& nick,
44 bool trial,
Yingdi Yu5b989132013-10-23 14:03:09 -070045 QWidget *parent)
Yingdi Yu7989eb22013-10-31 17:38:22 -070046: QDialog(parent)
47 , ui(new Ui::ChatDialog)
48 , m_contactManager(contactManager)
49 , m_chatroomPrefix(chatroomPrefix)
50 , m_localPrefix(localPrefix)
51 , m_defaultIdentity(defaultIdentity)
Yingdi Yue35bdb82013-11-07 11:32:40 -080052 , m_invitationPolicyManager(ndn::Ptr<InvitationPolicyManager>(new InvitationPolicyManager(m_chatroomPrefix.get(-1).toUri(), m_defaultIdentity)))
Yingdi Yu46948282013-11-06 18:43:31 -080053 , m_nick(nick)
Yingdi Yu7989eb22013-10-31 17:38:22 -070054 , m_sock(NULL)
55 , m_lastMsgTime(0)
56 // , m_historyInitialized(false)
57 , m_joined(false)
58 , m_inviteListDialog(new InviteListDialog(m_contactManager))
Zhenkai Zhu6d589aa2012-05-29 17:34:35 -070059{
Yingdi Yu7989eb22013-10-31 17:38:22 -070060 qRegisterMetaType<std::vector<Sync::MissingDataInfo> >("std::vector<Sync::MissingDataInfo>");
61 qRegisterMetaType<size_t>("size_t");
62
Yingdi Yueda39aa2013-10-23 23:07:29 -070063 ui->setupUi(this);
64
Yingdi Yufdb8ab82013-11-10 01:38:21 -080065 QString randString = getRandomString();
Yingdi Yu7989eb22013-10-31 17:38:22 -070066 m_localChatPrefix = m_localPrefix;
Yingdi Yu46948282013-11-06 18:43:31 -080067 m_localChatPrefix.append("%F0.").append(m_defaultIdentity);
Yingdi Yufdb8ab82013-11-10 01:38:21 -080068 m_localChatPrefix.append("chronos").append(m_chatroomPrefix.get(-1)).append(randString.toStdString());
Yingdi Yu7989eb22013-10-31 17:38:22 -070069
70 m_session = time(NULL);
71 m_scene = new DigestTreeScene(this);
72
73 initializeSetting();
74 updateLabels();
75
76 ui->treeViewer->setScene(m_scene);
77 ui->treeViewer->hide();
78 m_scene->plot("Empty");
79 QRectF rect = m_scene->itemsBoundingRect();
80 m_scene->setSceneRect(rect);
81
82 m_rosterModel = new QStringListModel(this);
83 ui->listView->setModel(m_rosterModel);
84
Yingdi Yu83eae842013-11-06 22:07:38 -080085 createActions();
86 createTrayIcon();
87
Yingdi Yu7989eb22013-10-31 17:38:22 -070088 m_timer = new QTimer(this);
89
Yingdi Yu46948282013-11-06 18:43:31 -080090 setWrapper(trial);
Yingdi Yu7989eb22013-10-31 17:38:22 -070091
92 connect(ui->inviteButton, SIGNAL(clicked()),
93 this, SLOT(openInviteListDialog()));
94 connect(m_inviteListDialog, SIGNAL(invitionDetermined(QString, bool)),
95 this, SLOT(sendInvitationWrapper(QString, bool)));
96 connect(ui->lineEdit, SIGNAL(returnPressed()),
97 this, SLOT(returnPressed()));
98 connect(ui->treeButton, SIGNAL(pressed()),
99 this, SLOT(treeButtonPressed()));
100 connect(this, SIGNAL(dataReceived(QString, const char *, size_t, bool, bool)),
101 this, SLOT(processData(QString, const char *, size_t, bool, bool)));
102 connect(this, SIGNAL(treeUpdated(const std::vector<Sync::MissingDataInfo>)),
103 this, SLOT(processTreeUpdate(const std::vector<Sync::MissingDataInfo>)));
104 connect(m_timer, SIGNAL(timeout()),
105 this, SLOT(replot()));
106 connect(m_scene, SIGNAL(replot()),
107 this, SLOT(replot()));
Yingdi Yu83eae842013-11-06 22:07:38 -0800108 connect(trayIcon, SIGNAL(messageClicked()),
109 this, SLOT(showNormal()));
110 connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
111 this, SLOT(iconActivated(QSystemTrayIcon::ActivationReason)));
Yingdi Yu7989eb22013-10-31 17:38:22 -0700112 connect(m_scene, SIGNAL(rosterChanged(QStringList)),
113 this, SLOT(updateRosterList(QStringList)));
114
Yingdi Yu7989eb22013-10-31 17:38:22 -0700115
116 initializeSync();
Zhenkai Zhu5a8d5aa2012-05-30 21:25:23 -0700117}
118
Yingdi Yu7989eb22013-10-31 17:38:22 -0700119
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700120ChatDialog::~ChatDialog()
121{
Yingdi Yu46948282013-11-06 18:43:31 -0800122 if(m_sock != NULL)
123 {
124 sendLeave();
125 delete m_sock;
126 m_sock = NULL;
127 }
Yingdi Yu83eae842013-11-06 22:07:38 -0800128 m_handler->shutdown();
Zhenkai Zhu82a62752012-06-04 17:11:04 -0700129}
130
Zhenkai Zhu86df7412012-09-27 16:30:20 -0700131void
Yingdi Yu46948282013-11-06 18:43:31 -0800132ChatDialog::setWrapper(bool trial)
Zhenkai Zhucf024442012-10-05 10:33:08 -0700133{
Yingdi Yu7989eb22013-10-31 17:38:22 -0700134 m_identityManager = ndn::Ptr<ndn::security::IdentityManager>::Create();
Yingdi Yueda39aa2013-10-23 23:07:29 -0700135
Yingdi Yu7989eb22013-10-31 17:38:22 -0700136 ndn::Name certificateName = m_identityManager->getDefaultCertificateNameByIdentity(m_defaultIdentity);
137 m_syncPolicyManager = ndn::Ptr<SyncPolicyManager>(new SyncPolicyManager(m_defaultIdentity, certificateName, m_chatroomPrefix));
Yingdi Yueda39aa2013-10-23 23:07:29 -0700138
Yingdi Yu7989eb22013-10-31 17:38:22 -0700139 m_keychain = ndn::Ptr<ndn::security::Keychain>(new ndn::security::Keychain(m_identityManager, m_invitationPolicyManager, NULL));
140
Yingdi Yufdb8ab82013-11-10 01:38:21 -0800141 ndn::Ptr<ndn::security::Keychain> noVerifyKeychain = ndn::Ptr<ndn::security::Keychain>(new ndn::security::Keychain(m_identityManager,
142ndn::Ptr<ndn::security::NoVerifyPolicyManager>::Create(), NULL));
Yingdi Yu8e135832013-11-09 20:12:31 -0800143 try{
144 m_handler = ndn::Ptr<ndn::Wrapper>(new ndn::Wrapper(m_keychain));
Yingdi Yufdb8ab82013-11-10 01:38:21 -0800145 m_localPrefixHandler = ndn::Ptr<ndn::Wrapper>(new ndn::Wrapper(noVerifyKeychain));
Yingdi Yu8e135832013-11-09 20:12:31 -0800146 }catch(ndn::Error::ndnOperation& e){
147 emit noNdnConnection(QString::fromStdString("Cannot conect to ndnd!\n Have you started your ndnd?"));
148 }
Zhenkai Zhud13acd02012-06-04 15:25:20 -0700149}
Alexander Afanasyevb4b92292013-07-09 13:54:59 -0700150
Yingdi Yueda39aa2013-10-23 23:07:29 -0700151void
Yingdi Yu7989eb22013-10-31 17:38:22 -0700152ChatDialog::initializeSetting()
Yingdi Yueda39aa2013-10-23 23:07:29 -0700153{
Yingdi Yu46948282013-11-06 18:43:31 -0800154 m_user.setNick(QString::fromStdString(m_nick));
Yingdi Yu7989eb22013-10-31 17:38:22 -0700155 m_user.setChatroom(QString::fromStdString(m_chatroomPrefix.get(-1).toUri()));
156 m_user.setOriginPrefix(QString::fromStdString(m_localPrefix.toUri()));
157 m_user.setPrefix(QString::fromStdString(m_localChatPrefix.toUri()));
158 m_scene->setCurrentPrefix(QString::fromStdString(m_localChatPrefix.toUri()));
159}
Yingdi Yueda39aa2013-10-23 23:07:29 -0700160
Yingdi Yu7989eb22013-10-31 17:38:22 -0700161void
162ChatDialog::updateLabels()
163{
164 QString settingDisp = QString("Chatroom: %1").arg(m_user.getChatroom());
165 ui->infoLabel->setStyleSheet("QLabel {color: #630; font-size: 16px; font: bold \"Verdana\";}");
166 ui->infoLabel->setText(settingDisp);
167 QString prefixDisp;
168 if (m_user.getPrefix().startsWith("/private/local"))
169 {
170 prefixDisp = QString("<Warning: no connection to hub or hub does not support prefix autoconfig.>\n <Prefix = %1>").arg(m_user.getPrefix());
171 ui->prefixLabel->setStyleSheet("QLabel {color: red; font-size: 12px; font: bold \"Verdana\";}");
172 }
173 else
174 {
175 prefixDisp = QString("<Prefix = %1>").arg(m_user.getPrefix());
176 ui->prefixLabel->setStyleSheet("QLabel {color: Green; font-size: 12px; font: bold \"Verdana\";}");
177 }
178 ui->prefixLabel->setText(prefixDisp);
179}
Yingdi Yueda39aa2013-10-23 23:07:29 -0700180
Yingdi Yu7989eb22013-10-31 17:38:22 -0700181void
182ChatDialog::sendInvitation(ndn::Ptr<ContactItem> contact, bool isIntroducer)
183{
184 m_invitationPolicyManager->addTrustAnchor(contact->getSelfEndorseCertificate());
185
186 ndn::Name certificateName = m_identityManager->getDefaultCertificateNameByIdentity(m_defaultIdentity);
187
188 ndn::Name interestName("/ndn/broadcast/chronos/invitation");
Yingdi Yueda39aa2013-10-23 23:07:29 -0700189 interestName.append(contact->getNameSpace());
190 interestName.append("chatroom");
191 interestName.append(m_chatroomPrefix.get(-1));
192 interestName.append("inviter-prefix");
193 interestName.append(m_localPrefix);
194 interestName.append("inviter");
195 interestName.append(certificateName);
196
197 string signedUri = interestName.toUri();
Yingdi Yu7989eb22013-10-31 17:38:22 -0700198 ndn::Blob signedBlob(signedUri.c_str(), signedUri.size());
Yingdi Yueda39aa2013-10-23 23:07:29 -0700199
Yingdi Yu7989eb22013-10-31 17:38:22 -0700200 ndn::Ptr<const ndn::signature::Sha256WithRsa> sha256sig = ndn::DynamicCast<const ndn::signature::Sha256WithRsa>(m_identityManager->signByCertificate(signedBlob, certificateName));
201 const ndn::Blob& sigBits = sha256sig->getSignatureBits();
Yingdi Yueda39aa2013-10-23 23:07:29 -0700202
203 interestName.append(sigBits.buf(), sigBits.size());
Yingdi Yu46948282013-11-06 18:43:31 -0800204 interestName.appendVersion();
205
Yingdi Yu7989eb22013-10-31 17:38:22 -0700206 ndn::Ptr<ndn::Interest> interest = ndn::Ptr<ndn::Interest>(new ndn::Interest(interestName));
207 ndn::Ptr<ndn::Closure> closure = ndn::Ptr<ndn::Closure>(new ndn::Closure(boost::bind(&ChatDialog::onInviteReplyVerified,
208 this,
209 _1,
210 contact->getNameSpace(),
211 isIntroducer),
212 boost::bind(&ChatDialog::onInviteTimeout,
213 this,
214 _1,
215 _2,
216 contact->getNameSpace(),
217 7),
218 boost::bind(&ChatDialog::onUnverified,
219 this,
220 _1)));
Yingdi Yueda39aa2013-10-23 23:07:29 -0700221
222 m_handler->sendInterest(interest, closure);
223}
224
225void
Yingdi Yu7989eb22013-10-31 17:38:22 -0700226ChatDialog::addTrustAnchor(const EndorseCertificate& selfEndorseCertificate)
227{ m_invitationPolicyManager->addTrustAnchor(selfEndorseCertificate); }
228
229void
230ChatDialog::addChatDataRule(const ndn::Name& prefix,
231 const ndn::security::IdentityCertificate& identityCertificate,
232 bool isIntroducer)
233{ m_syncPolicyManager->addChatDataRule(prefix, identityCertificate, isIntroducer); }
234
235void
Yingdi Yu83eae842013-11-06 22:07:38 -0800236ChatDialog::publishIntroCert(const ndn::security::IdentityCertificate& dskCertificate, bool isIntroducer)
Yingdi Yueda39aa2013-10-23 23:07:29 -0700237{
Yingdi Yu7989eb22013-10-31 17:38:22 -0700238 SyncIntroCertificate syncIntroCertificate(m_chatroomPrefix,
Yingdi Yu83eae842013-11-06 22:07:38 -0800239 dskCertificate.getPublicKeyName(),
Yingdi Yu7989eb22013-10-31 17:38:22 -0700240 m_identityManager->getDefaultKeyNameForIdentity(m_defaultIdentity),
Yingdi Yu83eae842013-11-06 22:07:38 -0800241 dskCertificate.getNotBefore(),
242 dskCertificate.getNotAfter(),
243 dskCertificate.getPublicKeyInfo(),
Yingdi Yu7989eb22013-10-31 17:38:22 -0700244 (isIntroducer ? SyncIntroCertificate::INTRODUCER : SyncIntroCertificate::PRODUCER));
245 ndn::Name certName = m_identityManager->getDefaultCertificateNameByIdentity(m_defaultIdentity);
Yingdi Yu72781e52013-11-06 23:00:21 -0800246 _LOG_DEBUG("Publish Intro Certificate: " << syncIntroCertificate.getName());
Yingdi Yu7989eb22013-10-31 17:38:22 -0700247 m_identityManager->signByCertificate(syncIntroCertificate, certName);
248 m_handler->putToNdnd(*syncIntroCertificate.encodeToWire());
Yingdi Yueda39aa2013-10-23 23:07:29 -0700249}
250
251void
Yingdi Yu7989eb22013-10-31 17:38:22 -0700252ChatDialog::invitationRejected(const ndn::Name& identity)
253{
Yingdi Yu72781e52013-11-06 23:00:21 -0800254 _LOG_DEBUG(" " << identity.toUri() << " Rejected your invitation!");
Yingdi Yu7989eb22013-10-31 17:38:22 -0700255}
256
257void
258ChatDialog::invitationAccepted(const ndn::Name& identity, ndn::Ptr<ndn::Data> data, const string& inviteePrefix, bool isIntroducer)
Yingdi Yueda39aa2013-10-23 23:07:29 -0700259{
Yingdi Yu72781e52013-11-06 23:00:21 -0800260 _LOG_DEBUG(" " << identity.toUri() << " Accepted your invitation!");
Yingdi Yu7989eb22013-10-31 17:38:22 -0700261 ndn::Ptr<const ndn::signature::Sha256WithRsa> sha256sig = boost::dynamic_pointer_cast<const ndn::signature::Sha256WithRsa> (data->getSignature());
262 const ndn::Name & keyLocatorName = sha256sig->getKeyLocator().getKeyName();
263 ndn::Ptr<ndn::security::IdentityCertificate> dskCertificate = m_invitationPolicyManager->getValidatedDskCertificate(keyLocatorName);
Yingdi Yue6476cd2013-11-06 18:51:19 -0800264 m_syncPolicyManager->addChatDataRule(inviteePrefix, *dskCertificate, isIntroducer);
Yingdi Yu83eae842013-11-06 22:07:38 -0800265 publishIntroCert(*dskCertificate, isIntroducer);
Yingdi Yueda39aa2013-10-23 23:07:29 -0700266}
267
268void
Yingdi Yu7989eb22013-10-31 17:38:22 -0700269ChatDialog::onInviteReplyVerified(ndn::Ptr<ndn::Data> data, const ndn::Name& identity, bool isIntroducer)
Yingdi Yueda39aa2013-10-23 23:07:29 -0700270{
271 string content(data->content().buf(), data->content().size());
Yingdi Yue9195fd2013-11-08 14:13:42 -0800272 if(content == string("nack"))
Yingdi Yueda39aa2013-10-23 23:07:29 -0700273 invitationRejected(identity);
274 else
Yingdi Yu7989eb22013-10-31 17:38:22 -0700275 invitationAccepted(identity, data, content, isIntroducer);
Yingdi Yueda39aa2013-10-23 23:07:29 -0700276}
277
278void
Yingdi Yu7989eb22013-10-31 17:38:22 -0700279ChatDialog::onInviteTimeout(ndn::Ptr<ndn::Closure> closure, ndn::Ptr<ndn::Interest> interest, const ndn::Name& identity, int retry)
Yingdi Yueda39aa2013-10-23 23:07:29 -0700280{
281 if(retry > 0)
282 {
Yingdi Yu7989eb22013-10-31 17:38:22 -0700283 ndn::Ptr<ndn::Closure> newClosure = ndn::Ptr<ndn::Closure>(new ndn::Closure(closure->m_dataCallback,
284 boost::bind(&ChatDialog::onInviteTimeout,
285 this,
286 _1,
287 _2,
288 identity,
289 retry - 1),
290 closure->m_unverifiedCallback,
291 closure->m_stepCount)
292 );
Yingdi Yueda39aa2013-10-23 23:07:29 -0700293 m_handler->sendInterest(interest, newClosure);
294 }
295 else
296 invitationRejected(identity);
297}
298
299void
Yingdi Yu7989eb22013-10-31 17:38:22 -0700300ChatDialog::onUnverified(ndn::Ptr<ndn::Data> data)
Yingdi Yueda39aa2013-10-23 23:07:29 -0700301{}
302
Yingdi Yu7989eb22013-10-31 17:38:22 -0700303void
Yingdi Yu46948282013-11-06 18:43:31 -0800304ChatDialog::onTimeout(ndn::Ptr<ndn::Closure> closure,
305 ndn::Ptr<ndn::Interest> interest)
306{}
307
308void
Yingdi Yu7989eb22013-10-31 17:38:22 -0700309ChatDialog::initializeSync()
310{
311
312 m_sock = new Sync::SyncSocket(m_chatroomPrefix.toUri(),
313 m_syncPolicyManager,
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);
321 disableTreeDisplay();
322 QTimer::singleShot(2200, this, SLOT(enableTreeDisplay()));
323 // Sync::CcnxWrapperPtr handle = boost::make_shared<Sync::CcnxWrapper> ();
324 // handle->setInterestFilter(m_user.getPrefix().toStdString(), bind(&ChatDialog::respondHistoryRequest, this, _1));
Yingdi Yu7989eb22013-10-31 17:38:22 -0700325}
326
327void
328ChatDialog::returnPressed()
329{
330 QString text = ui->lineEdit->text();
331 if (text.isEmpty())
332 return;
333
334 ui->lineEdit->clear();
335
336 if (text.startsWith("boruoboluomi"))
337 {
338 summonReaper ();
339 // reapButton->show();
340 fitView();
341 return;
342 }
343
344 if (text.startsWith("minimanihong"))
345 {
346 // reapButton->hide();
347 fitView();
348 return;
349 }
350
351 SyncDemo::ChatMessage msg;
352 formChatMessage(text, msg);
353
354 appendMessage(msg);
355
356 sendMsg(msg);
357
358 fitView();
359}
360
361void
362ChatDialog::treeButtonPressed()
363{
364 if (ui->treeViewer->isVisible())
365 {
366 ui->treeViewer->hide();
367 ui->treeButton->setText("Show ChronoSync Tree");
368 }
369 else
370 {
371 ui->treeViewer->show();
372 ui->treeButton->setText("Hide ChronoSync Tree");
373 }
374
375 fitView();
376}
377
378void ChatDialog::disableTreeDisplay()
379{
380 ui->treeButton->setEnabled(false);
381 ui->treeViewer->hide();
382 fitView();
383}
384
385void ChatDialog::enableTreeDisplay()
386{
387 ui->treeButton->setEnabled(true);
388 // treeViewer->show();
389 // fitView();
390}
391
392void
393ChatDialog::processTreeUpdateWrapper(const std::vector<Sync::MissingDataInfo> v, Sync::SyncSocket *sock)
394{
395 emit treeUpdated(v);
396 _LOG_DEBUG("<<< Tree update signal emitted");
397}
398
399void
400ChatDialog::processRemoveWrapper(std::string prefix)
401{
402 _LOG_DEBUG("Sync REMOVE signal received for prefix: " << prefix);
403}
404
405void
406ChatDialog::processTreeUpdate(const std::vector<Sync::MissingDataInfo> v)
407{
408 _LOG_DEBUG("<<< processing Tree Update");
409
410 if (v.empty())
411 {
412 return;
413 }
414
415 // reflect the changes on digest tree
416 {
417 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
418 m_scene->processUpdate(v, m_sock->getRootDigest().c_str());
419 }
420
421 int n = v.size();
422 int totalMissingPackets = 0;
423 for (int i = 0; i < n; i++)
424 {
425 totalMissingPackets += v[i].high.getSeq() - v[i].low.getSeq() + 1;
426 }
427
428 for (int i = 0; i < n; i++)
429 {
430 if (totalMissingPackets < 4)
431 {
432 for (Sync::SeqNo seq = v[i].low; seq <= v[i].high; ++seq)
433 {
434 m_sock->fetchData(v[i].prefix, seq, bind(&ChatDialog::processDataWrapper, this, _1), 2);
435 _LOG_DEBUG("<<< Fetching " << v[i].prefix << "/" <<seq.getSession() <<"/" << seq.getSeq());
436 }
437 }
438 else
439 {
440 m_sock->fetchData(v[i].prefix, v[i].high, bind(&ChatDialog::processDataNoShowWrapper, this, _1), 2);
441 }
442 }
443
444 // adjust the view
445 fitView();
446
447}
448
449void
450ChatDialog::processDataWrapper(ndn::Ptr<ndn::Data> data)
451{
452 string name = data->getName().toUri();
453 const char* buf = data->content().buf();
454 size_t len = data->content().size();
455
456 char *tempBuf = new char[len];
457 memcpy(tempBuf, buf, len);
458 emit dataReceived(name.c_str(), tempBuf, len, true, false);
459 _LOG_DEBUG("<<< " << name << " fetched");
460}
461
462void
463ChatDialog::processDataNoShowWrapper(ndn::Ptr<ndn::Data> data)
464{
465 string name = data->getName().toUri();
466 const char* buf = data->content().buf();
467 size_t len = data->content().size();
468
469 char *tempBuf = new char[len];
470 memcpy(tempBuf, buf, len);
471 emit dataReceived(name.c_str(), tempBuf, len, false, false);
472
473 // if (!m_historyInitialized)
474 // {
475 // fetchHistory(name);
476 // m_historyInitialized = true;
477 // }
478}
479
480// void
481// ChatDialog::fetchHistory(std::string name)
482// {
483
484// /****************************/
485// /* TODO: fix following part */
486// /****************************/
487// string nameWithoutSeq = name.substr(0, name.find_last_of('/'));
488// string prefix = nameWithoutSeq.substr(0, nameWithoutSeq.find_last_of('/'));
489// prefix += "/history";
490// // Ptr<Wrapper>CcnxWrapperPtr handle = boost::make_shared<Sync::CcnxWrapper> ();
491// // QString randomString = getRandomString();
492// // for (int i = 0; i < MAX_HISTORY_ENTRY; i++)
493// // {
494// // QString interest = QString("%1/%2/%3").arg(prefix.c_str()).arg(randomString).arg(i);
495// // handle->sendInterest(interest.toStdString(), bind(&ChatDialog::processDataHistoryWrapper, this, _1, _2, _3));
496// // }
497// }
498
499void
500ChatDialog::processData(QString name, const char *buf, size_t len, bool show, bool isHistory)
501{
502 SyncDemo::ChatMessage msg;
503 bool corrupted = false;
504 if (!msg.ParseFromArray(buf, len))
505 {
506 _LOG_DEBUG("Errrrr.. Can not parse msg with name: " << name.toStdString() << ". what is happening?");
507 // nasty stuff: as a remedy, we'll form some standard msg for inparsable msgs
508 msg.set_from("inconnu");
509 msg.set_type(SyncDemo::ChatMessage::OTHER);
510 corrupted = true;
511 }
512
513 delete [] buf;
514 buf = NULL;
515
516 // display msg received from network
517 // we have to do so; this function is called by ccnd thread
518 // so if we call appendMsg directly
519 // Qt crash as "QObject: Cannot create children for a parent that is in a different thread"
520 // the "cannonical" way to is use signal-slot
521 if (show && !corrupted)
522 {
523 appendMessage(msg, isHistory);
524 }
525
526 if (!isHistory)
527 {
528 // update the tree view
529 std::string stdStrName = name.toStdString();
530 std::string stdStrNameWithoutSeq = stdStrName.substr(0, stdStrName.find_last_of('/'));
531 std::string prefix = stdStrNameWithoutSeq.substr(0, stdStrNameWithoutSeq.find_last_of('/'));
532 _LOG_DEBUG("<<< updating scene for" << prefix << ": " << msg.from());
533 if (msg.type() == SyncDemo::ChatMessage::LEAVE)
534 {
535 processRemove(prefix.c_str());
536 }
537 else
538 {
539 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
540 m_scene->msgReceived(prefix.c_str(), msg.from().c_str());
541 }
542 }
543 fitView();
544}
545
546void
547ChatDialog::processRemove(QString prefix)
548{
549 _LOG_DEBUG("<<< remove node for prefix" << prefix.toStdString());
550
551 bool removed = m_scene->removeNode(prefix);
552 if (removed)
553 {
554 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
555 m_scene->plot(m_sock->getRootDigest().c_str());
556 }
557}
558
559void
560ChatDialog::sendJoin()
561{
562 m_joined = true;
563 SyncDemo::ChatMessage msg;
564 formControlMessage(msg, SyncDemo::ChatMessage::JOIN);
565 sendMsg(msg);
566 boost::random::random_device rng;
567 boost::random::uniform_int_distribution<> uniform(1, FRESHNESS / 5 * 1000);
568 m_randomizedInterval = HELLO_INTERVAL * 1000 + uniform(rng);
569 QTimer::singleShot(m_randomizedInterval, this, SLOT(sendHello()));
570}
571
572void
573ChatDialog::sendHello()
574{
575 time_t now = time(NULL);
576 int elapsed = now - m_lastMsgTime;
577 if (elapsed >= m_randomizedInterval / 1000)
578 {
579 SyncDemo::ChatMessage msg;
580 formControlMessage(msg, SyncDemo::ChatMessage::HELLO);
581 sendMsg(msg);
582 boost::random::random_device rng;
583 boost::random::uniform_int_distribution<> uniform(1, FRESHNESS / 5 * 1000);
584 m_randomizedInterval = HELLO_INTERVAL * 1000 + uniform(rng);
585 QTimer::singleShot(m_randomizedInterval, this, SLOT(sendHello()));
586 }
587 else
588 {
589 QTimer::singleShot((m_randomizedInterval - elapsed * 1000), this, SLOT(sendHello()));
590 }
591}
592
593void
594ChatDialog::sendLeave()
595{
596 SyncDemo::ChatMessage msg;
597 formControlMessage(msg, SyncDemo::ChatMessage::LEAVE);
598 sendMsg(msg);
599 usleep(500000);
600 m_sock->remove(m_user.getPrefix().toStdString());
601 usleep(5000);
602 m_joined = false;
603 _LOG_DEBUG("Sync REMOVE signal sent");
604}
605
606void
607ChatDialog::replot()
608{
609 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
610 m_scene->plot(m_sock->getRootDigest().c_str());
611 fitView();
612}
613
614void
615ChatDialog::summonReaper()
616{
617 Sync::SyncLogic &logic = m_sock->getLogic ();
618 map<string, bool> branches = logic.getBranchPrefixes();
619 QMap<QString, DisplayUserPtr> roster = m_scene->getRosterFull();
620
621 m_zombieList.clear();
622
623 QMapIterator<QString, DisplayUserPtr> it(roster);
624 map<string, bool>::iterator mapIt;
625 while(it.hasNext())
626 {
627 it.next();
628 DisplayUserPtr p = it.value();
629 if (p != DisplayUserNullPtr)
630 {
631 mapIt = branches.find(p->getPrefix().toStdString());
632 if (mapIt != branches.end())
633 {
634 mapIt->second = true;
635 }
636 }
637 }
638
639 for (mapIt = branches.begin(); mapIt != branches.end(); ++mapIt)
640 {
641 // this is zombie. all active users should have been marked true
642 if (! mapIt->second)
643 {
644 m_zombieList.append(mapIt->first.c_str());
645 }
646 }
647
648 m_zombieIndex = 0;
649
650 // start reaping
651 reap();
652}
653
654void
655ChatDialog::reap()
656{
657 if (m_zombieIndex < m_zombieList.size())
658 {
659 string prefix = m_zombieList.at(m_zombieIndex).toStdString();
660 m_sock->remove(prefix);
661 _LOG_DEBUG("Reaped: prefix = " << prefix);
662 m_zombieIndex++;
663 // reap again in 10 seconds
664 QTimer::singleShot(10000, this, SLOT(reap()));
665 }
666}
667
668void
669ChatDialog::updateRosterList(QStringList staleUserList)
670{
671 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
672 QStringList rosterList = m_scene->getRosterList();
673 m_rosterModel->setStringList(rosterList);
674 QString user;
675 QStringListIterator it(staleUserList);
676 while(it.hasNext())
677 {
678 std::string nick = it.next().toStdString();
679 if (nick.empty())
680 continue;
681
682 SyncDemo::ChatMessage msg;
683 formControlMessage(msg, SyncDemo::ChatMessage::LEAVE);
684 msg.set_from(nick);
685 appendMessage(msg);
686 }
687}
688
689void
Yingdi Yufdb8ab82013-11-10 01:38:21 -0800690ChatDialog::settingUpdated(QString nick, QString chatroom, QString originPrefix)
691{
692 QString randString = getRandomString();
693 bool needWrite = false;
694 bool needFresh = false;
695
696 QString oldPrefix = m_user.getPrefix();
697 if (!originPrefix.isEmpty() && originPrefix != m_user.getOriginPrefix()) {
698 m_user.setOriginPrefix(originPrefix);
699
700 m_localPrefix = ndn::Name(originPrefix.toStdString());
701 m_localChatPrefix = m_localPrefix;
702 m_localChatPrefix.append("%F0.").append(m_defaultIdentity);
703 m_localChatPrefix.append("chronos").append(m_chatroomPrefix.get(-1)).append(randString.toStdString());
704 m_user.setPrefix(QString::fromStdString(m_localChatPrefix.toUri()));
705 m_scene->setCurrentPrefix(QString::fromStdString(m_localChatPrefix.toUri()));
706 needWrite = true;
707 needFresh = true;
708 }
709
710 if (needWrite) {
711 updateLabels();
712 }
713
714 if (needFresh && m_sock != NULL)
715 {
716
717 {
718 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
719 m_scene->clearAll();
720 m_scene->plot("Empty");
721 }
722
723 // ui->textEdit->clear();
724
725 // keep the new prefix
726 QString newPrefix = m_user.getPrefix();
727 // send leave for the old
728 m_user.setPrefix(oldPrefix);
729 // there is no point to send leave if we haven't joined yet
730 if (m_joined)
731 {
732 sendLeave();
733 }
734 // resume new prefix
735 m_user.setPrefix(newPrefix);
736 // Sync::CcnxWrapperPtr handle = Sync::CcnxWrapper::Create();
737 // handle->clearInterestFilter(oldPrefix.toStdString());
738 delete m_sock;
739 m_sock = NULL;
740
741 try
742 {
743 usleep(100000);
744 m_sock = new Sync::SyncSocket(m_chatroomPrefix.toUri(),
745 m_syncPolicyManager,
746 bind(&ChatDialog::processTreeUpdateWrapper, this, _1, _2),
747 bind(&ChatDialog::processRemoveWrapper, this, _1));
748 usleep(100000);
749 // Sync::CcnxWrapperPtr handle = boost::make_shared<Sync::CcnxWrapper> ();
750 // handle->setInterestFilter(m_user.getPrefix().toStdString(), bind(&ChatDialog::respondHistoryRequest, this, _1));
751 sendJoin();
752 m_timer->start(FRESHNESS * 1000);
753 disableTreeDisplay();
754 enableTreeDisplay();
755 }catch(ndn::Error::ndnOperation& e){
756 emit noNdnConnection(QString::fromStdString("Cannot conect to ndnd!\n Have you started your ndnd?"));
757 }
758 }
759 else if (needFresh && m_sock == NULL)
760 {
761 initializeSync();
762 }
763 else if (m_sock == NULL)
764 {
765 initializeSync();
766 }
767 else
768 {
769// #ifdef __DEBUG
770// std::cout << "Just changing nicks, we're good. " << std::endl;
771// #endif
772 }
773
774 fitView();
775}
776
777void
Yingdi Yu83eae842013-11-06 22:07:38 -0800778ChatDialog::iconActivated(QSystemTrayIcon::ActivationReason reason)
779{
780 switch (reason)
781 {
782 case QSystemTrayIcon::Trigger:
783 case QSystemTrayIcon::DoubleClick:
784 break;
785 case QSystemTrayIcon::MiddleClick:
786 // showMessage();
787 break;
788 default:;
789 }
790}
791
792
793void
794ChatDialog::messageClicked()
795{
796 this->showMaximized();
797}
798
799
800void
801ChatDialog::createActions()
802{
Yingdi Yu702d6f12013-11-07 17:00:54 -0800803 minimizeAction = new QAction(tr("Mi&nimize"), this);
804 connect(minimizeAction, SIGNAL(triggered()), this, SLOT(hide()));
Yingdi Yu83eae842013-11-06 22:07:38 -0800805
Yingdi Yu702d6f12013-11-07 17:00:54 -0800806 maximizeAction = new QAction(tr("Ma&ximize"), this);
807 connect(maximizeAction, SIGNAL(triggered()), this, SLOT(showMaximized()));
Yingdi Yu83eae842013-11-06 22:07:38 -0800808
Yingdi Yu702d6f12013-11-07 17:00:54 -0800809 restoreAction = new QAction(tr("&Restore"), this);
810 connect(restoreAction, SIGNAL(triggered()), this, SLOT(showNormal()));
Yingdi Yu83eae842013-11-06 22:07:38 -0800811
812 // settingsAction = new QAction(tr("Settings"), this);
813 // connect (settingsAction, SIGNAL(triggered()), this, SLOT(buttonPressed()));
814
815 // settingsAction->setMenuRole (QAction::PreferencesRole);
816
Yingdi Yufdb8ab82013-11-10 01:38:21 -0800817 updateLocalPrefixAction = new QAction(tr("Update local prefix"), this);
818 connect (updateLocalPrefixAction, SIGNAL(triggered()), this, SLOT(updateLocalPrefix()));
Yingdi Yu83eae842013-11-06 22:07:38 -0800819
Yingdi Yu702d6f12013-11-07 17:00:54 -0800820 quitAction = new QAction(tr("Quit"), this);
821 connect(quitAction, SIGNAL(triggered()), this, SLOT(quit()));
Yingdi Yu83eae842013-11-06 22:07:38 -0800822}
823
824void
825ChatDialog::createTrayIcon()
826{
Yingdi Yu702d6f12013-11-07 17:00:54 -0800827 trayIconMenu = new QMenu(this);
828 trayIconMenu->addAction(minimizeAction);
829 trayIconMenu->addAction(maximizeAction);
830 trayIconMenu->addAction(restoreAction);
Yingdi Yu83eae842013-11-06 22:07:38 -0800831 // trayIconMenu->addSeparator();
832 // trayIconMenu->addAction(settingsAction);
Yingdi Yufdb8ab82013-11-10 01:38:21 -0800833 trayIconMenu->addSeparator();
834 trayIconMenu->addAction(updateLocalPrefixAction);
Yingdi Yu702d6f12013-11-07 17:00:54 -0800835 trayIconMenu->addSeparator();
836 trayIconMenu->addAction(quitAction);
Yingdi Yu83eae842013-11-06 22:07:38 -0800837
838 trayIcon = new QSystemTrayIcon(this);
Yingdi Yu702d6f12013-11-07 17:00:54 -0800839 trayIcon->setContextMenu(trayIconMenu);
Yingdi Yu83eae842013-11-06 22:07:38 -0800840
841 QIcon icon(":/images/icon_small.png");
842 trayIcon->setIcon(icon);
843 setWindowIcon(icon);
844 trayIcon->setToolTip("ChronoChat System Tray Icon");
845 trayIcon->setVisible(true);
Yingdi Yu83eae842013-11-06 22:07:38 -0800846}
847
848
849void
Yingdi Yu7989eb22013-10-31 17:38:22 -0700850ChatDialog::resizeEvent(QResizeEvent *e)
851{
852 fitView();
853}
854
855void
856ChatDialog::showEvent(QShowEvent *e)
857{
858 fitView();
859}
860
861void
862ChatDialog::fitView()
863{
864 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
865 QRectF rect = m_scene->itemsBoundingRect();
866 m_scene->setSceneRect(rect);
867 ui->treeViewer->fitInView(m_scene->itemsBoundingRect(), Qt::KeepAspectRatio);
868}
869
870void
871ChatDialog::formChatMessage(const QString &text, SyncDemo::ChatMessage &msg) {
872 msg.set_from(m_user.getNick().toStdString());
873 msg.set_to(m_user.getChatroom().toStdString());
874 msg.set_data(text.toUtf8().constData());
875 time_t seconds = time(NULL);
876 msg.set_timestamp(seconds);
877 msg.set_type(SyncDemo::ChatMessage::CHAT);
878}
879
880void
881ChatDialog::formControlMessage(SyncDemo::ChatMessage &msg, SyncDemo::ChatMessage::ChatMessageType type)
882{
883 msg.set_from(m_user.getNick().toStdString());
884 msg.set_to(m_user.getChatroom().toStdString());
885 time_t seconds = time(NULL);
886 msg.set_timestamp(seconds);
887 msg.set_type(type);
888}
889
890void
Yingdi Yufdb8ab82013-11-10 01:38:21 -0800891ChatDialog::updateLocalPrefix()
892{
893 ndn::Ptr<ndn::Interest> interest = ndn::Ptr<ndn::Interest>(new ndn::Interest(ndn::Name("/local/ndn/prefix")));
894 interest->setChildSelector(ndn::Interest::CHILD_RIGHT);
895
896 ndn::Ptr<ndn::Closure> closure = ndn::Ptr<ndn::Closure>(new ndn::Closure(boost::bind(&ChatDialog::getLocalPrefix,
897 this,
898 _1),
899 boost::bind(&ChatDialog::getLocalPrefixTimeout,
900 this,
901 _1,
902 _2),
903 boost::bind(&ChatDialog::getLocalPrefix,
904 this,
905 _1)));
906
907 m_localPrefixHandler->sendInterest(interest, closure);
908
909}
910
911static std::string chars2("qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM0123456789");
912
913QString
914ChatDialog::getRandomString()
915{
916 std::string randStr;
917 boost::random::random_device rng;
918 boost::random::uniform_int_distribution<> index_dist(0, chars2.size() - 1);
919 for (int i = 0; i < 10; i ++)
920 {
921 randStr += chars2[index_dist(rng)];
922 }
923 return randStr.c_str();
924}
925
926void
927ChatDialog::getLocalPrefix(ndn::Ptr<ndn::Data> data)
928{
929 string dataString(data->content().buf(), data->content().size());
930 QString originPrefix = QString::fromStdString (dataString).trimmed ();
931
932 if (originPrefix != "" && m_user.getOriginPrefix () != originPrefix)
933 emit settingUpdated(m_user.getNick (), m_user.getChatroom (), originPrefix);
934}
935
936void
937ChatDialog::getLocalPrefixTimeout(ndn::Ptr<ndn::Closure> closure, ndn::Ptr<ndn::Interest> interest)
938{
939}
940
941void
Yingdi Yu83eae842013-11-06 22:07:38 -0800942ChatDialog::changeEvent(QEvent *e)
943{
944 switch(e->type())
945 {
946 case QEvent::ActivationChange:
947 if (isActiveWindow())
948 {
949 trayIcon->setIcon(QIcon(":/images/icon_small.png"));
950 }
951 break;
952 default:
953 break;
954 }
955}
956
957void
Yingdi Yu7989eb22013-10-31 17:38:22 -0700958ChatDialog::appendMessage(const SyncDemo::ChatMessage msg, bool isHistory)
959{
960 boost::recursive_mutex::scoped_lock lock(m_msgMutex);
961
962 if (msg.type() == SyncDemo::ChatMessage::CHAT)
963 {
964
965 if (!msg.has_data())
966 {
967 return;
968 }
969
970 if (msg.from().empty() || msg.data().empty())
971 {
972 return;
973 }
974
975 if (!msg.has_timestamp())
976 {
977 return;
978 }
979
980 // if (m_history.size() == MAX_HISTORY_ENTRY)
981 // {
982 // m_history.dequeue();
983 // }
984
985 // m_history.enqueue(msg);
986
987 QTextCharFormat nickFormat;
988 nickFormat.setForeground(Qt::darkGreen);
989 nickFormat.setFontWeight(QFont::Bold);
990 nickFormat.setFontUnderline(true);
991 nickFormat.setUnderlineColor(Qt::gray);
992
993 QTextCursor cursor(ui->textEdit->textCursor());
994 cursor.movePosition(QTextCursor::End);
995 QTextTableFormat tableFormat;
996 tableFormat.setBorder(0);
997 QTextTable *table = cursor.insertTable(1, 2, tableFormat);
998 QString from = QString("%1 ").arg(msg.from().c_str());
999 QTextTableCell fromCell = table->cellAt(0, 0);
1000 fromCell.setFormat(nickFormat);
1001 fromCell.firstCursorPosition().insertText(from);
1002
1003 time_t timestamp = msg.timestamp();
1004 printTimeInCell(table, timestamp);
1005
1006 QTextCursor nextCursor(ui->textEdit->textCursor());
1007 nextCursor.movePosition(QTextCursor::End);
1008 table = nextCursor.insertTable(1, 1, tableFormat);
1009 table->cellAt(0, 0).firstCursorPosition().insertText(QString::fromUtf8(msg.data().c_str()));
1010 if (!isHistory)
1011 {
1012 showMessage(from, QString::fromUtf8(msg.data().c_str()));
1013 }
1014 }
1015
1016 if (msg.type() == SyncDemo::ChatMessage::JOIN || msg.type() == SyncDemo::ChatMessage::LEAVE)
1017 {
1018 QTextCharFormat nickFormat;
1019 nickFormat.setForeground(Qt::gray);
1020 nickFormat.setFontWeight(QFont::Bold);
1021 nickFormat.setFontUnderline(true);
1022 nickFormat.setUnderlineColor(Qt::gray);
1023
1024 QTextCursor cursor(ui->textEdit->textCursor());
1025 cursor.movePosition(QTextCursor::End);
1026 QTextTableFormat tableFormat;
1027 tableFormat.setBorder(0);
1028 QTextTable *table = cursor.insertTable(1, 2, tableFormat);
1029 QString action;
1030 if (msg.type() == SyncDemo::ChatMessage::JOIN)
1031 {
1032 action = "enters room";
1033 }
1034 else
1035 {
1036 action = "leaves room";
1037 }
1038
1039 QString from = QString("%1 %2 ").arg(msg.from().c_str()).arg(action);
1040 QTextTableCell fromCell = table->cellAt(0, 0);
1041 fromCell.setFormat(nickFormat);
1042 fromCell.firstCursorPosition().insertText(from);
1043
1044 time_t timestamp = msg.timestamp();
1045 printTimeInCell(table, timestamp);
1046 }
1047
1048 QScrollBar *bar = ui->textEdit->verticalScrollBar();
1049 bar->setValue(bar->maximum());
1050}
1051
1052QString
1053ChatDialog::formatTime(time_t timestamp)
1054{
1055 struct tm *tm_time = localtime(&timestamp);
1056 int hour = tm_time->tm_hour;
1057 QString amOrPM;
1058 if (hour > 12)
1059 {
1060 hour -= 12;
1061 amOrPM = "PM";
1062 }
1063 else
1064 {
1065 amOrPM = "AM";
1066 if (hour == 0)
1067 {
1068 hour = 12;
1069 }
1070 }
1071
1072 char textTime[12];
1073 sprintf(textTime, "%d:%02d:%02d %s", hour, tm_time->tm_min, tm_time->tm_sec, amOrPM.toStdString().c_str());
1074 return QString(textTime);
1075}
1076
1077void
1078ChatDialog::printTimeInCell(QTextTable *table, time_t timestamp)
1079{
1080 QTextCharFormat timeFormat;
1081 timeFormat.setForeground(Qt::gray);
1082 timeFormat.setFontUnderline(true);
1083 timeFormat.setUnderlineColor(Qt::gray);
1084 QTextTableCell timeCell = table->cellAt(0, 1);
1085 timeCell.setFormat(timeFormat);
1086 timeCell.firstCursorPosition().insertText(formatTime(timestamp));
1087}
1088
1089void
1090ChatDialog::showMessage(QString from, QString data)
1091{
1092 if (!isActiveWindow())
1093 {
Yingdi Yu83eae842013-11-06 22:07:38 -08001094 trayIcon->showMessage(QString("Chatroom %1 has a new message").arg(m_user.getChatroom()), QString("<%1>: %2").arg(from).arg(data), QSystemTrayIcon::Information, 20000);
1095 trayIcon->setIcon(QIcon(":/images/note.png"));
Yingdi Yu7989eb22013-10-31 17:38:22 -07001096 }
1097}
1098
1099void
1100ChatDialog::sendMsg(SyncDemo::ChatMessage &msg)
1101{
1102 // send msg
1103 size_t size = msg.ByteSize();
1104 char *buf = new char[size];
1105 msg.SerializeToArray(buf, size);
1106 if (!msg.IsInitialized())
1107 {
1108 _LOG_DEBUG("Errrrr.. msg was not probally initialized "<<__FILE__ <<":"<<__LINE__<<". what is happening?");
1109 abort();
1110 }
1111 m_sock->publishData(m_user.getPrefix().toStdString(), m_session, buf, size, FRESHNESS);
1112
1113 delete buf;
1114
1115 m_lastMsgTime = time(NULL);
1116
1117 int nextSequence = m_sock->getNextSeq(m_user.getPrefix().toStdString(), m_session);
1118 Sync::MissingDataInfo mdi = {m_user.getPrefix().toStdString(), Sync::SeqNo(0), Sync::SeqNo(nextSequence - 1)};
1119 std::vector<Sync::MissingDataInfo> v;
1120 v.push_back(mdi);
1121 {
1122 boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
1123 m_scene->processUpdate(v, m_sock->getRootDigest().c_str());
1124 m_scene->msgReceived(m_user.getPrefix(), m_user.getNick());
1125 }
1126}
1127
1128void
1129ChatDialog::openInviteListDialog()
1130{
1131 m_inviteListDialog->setInviteLabel(m_chatroomPrefix.toUri());
1132 m_inviteListDialog->show();
1133}
1134
1135void
1136ChatDialog::sendInvitationWrapper(QString invitee, bool isIntroducer)
1137{
1138 ndn::Name inviteeNamespace(invitee.toUtf8().constData());
1139 ndn::Ptr<ContactItem> inviteeItem = m_contactManager->getContact(inviteeNamespace);
1140 sendInvitation(inviteeItem, isIntroducer);
1141}
1142
Yingdi Yu46948282013-11-06 18:43:31 -08001143void
1144ChatDialog::closeEvent(QCloseEvent *e)
1145{
Yingdi Yu702d6f12013-11-07 17:00:54 -08001146 if (trayIcon->isVisible())
1147 {
1148 QMessageBox::information(this, tr("Chronos"),
1149 tr("The program will keep running in the "
1150 "system tray. To terminate the program"
1151 "choose <b>Quit</b> in the context memu"
1152 "of the system tray entry."));
1153 hide();
1154 e->ignore();
1155 }
1156}
1157
1158void
1159ChatDialog::quit()
1160{
Yingdi Yu46948282013-11-06 18:43:31 -08001161 hide();
Yingdi Yu46948282013-11-06 18:43:31 -08001162 emit closeChatDialog(m_chatroomPrefix);
1163}
1164
1165
1166
Yingdi Yu7989eb22013-10-31 17:38:22 -07001167
Alexander Afanasyevb4b92292013-07-09 13:54:59 -07001168#if WAF
1169#include "chatdialog.moc"
1170#include "chatdialog.cpp.moc"
1171#endif