blob: 28b6d36dab6f815993bb9bb1a56747b443797bf7 [file] [log] [blame]
taylorchuc27dd482014-05-17 20:06:49 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Qi Zhao86f2b212016-12-06 12:44:16 -08003 * Copyright (c) 2013-2017, Regents of the University of California.
taylorchuc27dd482014-05-17 20:06:49 -07004 *
5 * This file is part of NFD Control Center. See AUTHORS.md for complete list of NFD
6 * authors and contributors.
7 *
8 * NFD Control Center is free software: you can redistribute it and/or modify it under the
9 * terms of the GNU General Public License as published by the Free Software Foundation,
10 * either version 3 of the License, or (at your option) any later version.
11 *
12 * NFD Control Center is distributed in the hope that it will be useful, but WITHOUT ANY
13 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
14 * PARTICULAR PURPOSE. See the GNU General Public License for more details.
15 *
Qi Zhao0e043e52016-12-05 18:27:09 -080016 * You should have received a copy of the GNU General Public License along with NFD
taylorchuc27dd482014-05-17 20:06:49 -070017 * Control Center, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include "config.hpp"
21#include "tray-menu.hpp"
22
23#include <ndn-cxx/face.hpp>
24#include <ndn-cxx/interest.hpp>
25
26
27#ifdef OSX_BUILD
Alexander Afanasyev0621cec2016-03-20 23:18:27 -070028#define CONNECT_ICON ":/res/icon-connected-black.png"
29#define DISCONNECT_ICON ":/res/icon-disconnected-black.png"
Alexander Afanasyev11ae34d2016-03-21 11:55:16 -070030
31#include <Security/Authorization.h>
32#include <Security/AuthorizationTags.h>
taylorchuc27dd482014-05-17 20:06:49 -070033#else
Alexander Afanasyev0621cec2016-03-20 23:18:27 -070034#define CONNECT_ICON ":/res/icon-connected-white.png"
35#define DISCONNECT_ICON ":/res/icon-disconnected-white.png"
Alexander Afanasyev11ae34d2016-03-21 11:55:16 -070036#endif // OSX_BUILD
taylorchuc27dd482014-05-17 20:06:49 -070037
38#ifdef WAF
39#include "tray-menu.moc"
taylorchuc27dd482014-05-17 20:06:49 -070040#endif
41
42namespace ndn {
43
Alexander Afanasyev81509f32016-03-21 17:02:38 -070044TrayMenu::TrayMenu(QQmlContext* context, Face& face)
Alexander Afanasyev4086d512014-07-11 15:56:33 -070045 : m_context(context)
46 , m_isNfdRunning(false)
Yingdi Yu53c11c12016-03-20 12:56:49 -070047 , m_menu(new QMenu(this))
48 , m_entryPref(new QAction("Preferences...", m_menu))
Alexander Afanasyev11ae34d2016-03-21 11:55:16 -070049 , m_entrySec(new QAction("Security...", m_menu))
50#ifdef OSX_BUILD
51 , m_entryEnableCli(new QAction("Enable Command Terminal Usage...", m_menu))
52#endif
Yingdi Yu53c11c12016-03-20 12:56:49 -070053 , m_entryQuit(new QAction("Quit", m_menu))
Yingdi Yu1f824642016-03-20 17:07:22 -070054 , m_keyViewerDialog(new ncc::KeyViewerDialog)
Alexander Afanasyev81509f32016-03-21 17:02:38 -070055 , m_face(face)
Qi Zhao86f2b212016-12-06 12:44:16 -080056 , m_acProc(new QProcess())
57 , m_settings(new QSettings())
Yingdi Yu53c11c12016-03-20 12:56:49 -070058{
59 connect(m_entryPref, SIGNAL(triggered()), this, SIGNAL(showApp()));
Qi Zhao86f2b212016-12-06 12:44:16 -080060 connect(this, SIGNAL(showApp()), this, SLOT(showPref()));
Yingdi Yu1f824642016-03-20 17:07:22 -070061 connect(m_entrySec, SIGNAL(triggered()), m_keyViewerDialog, SLOT(present()));
Yingdi Yu53c11c12016-03-20 12:56:49 -070062 connect(m_entryQuit, SIGNAL(triggered()), this, SLOT(quitApp()));
taylorchuc27dd482014-05-17 20:06:49 -070063
Alexander Afanasyev11ae34d2016-03-21 11:55:16 -070064#ifdef OSX_BUILD
65 connect(m_entryEnableCli, SIGNAL(triggered()), this, SLOT(enableCli()));
66#endif
Yingdi Yu1f824642016-03-20 17:07:22 -070067
Alexander Afanasyev4086d512014-07-11 15:56:33 -070068 connect(this, SIGNAL(nfdActivityUpdate(bool)), this, SLOT(updateNfdActivityIcon(bool)),
69 Qt::QueuedConnection);
70
71 m_context->setContextProperty("startStopButtonText", QVariant::fromValue(QString("Start NFD")));
Qi Zhao86f2b212016-12-06 12:44:16 -080072 m_context->setContextProperty("acText", QVariant::fromValue(QString("")));
taylorchuc27dd482014-05-17 20:06:49 -070073
Yingdi Yu53c11c12016-03-20 12:56:49 -070074 m_menu->addAction(m_entryPref);
75 m_menu->addAction(m_entrySec);
susmit50607912016-03-21 12:00:15 -070076#ifdef OSX_BUILD
Alexander Afanasyev11ae34d2016-03-21 11:55:16 -070077 m_menu->addAction(m_entryEnableCli);
susmit50607912016-03-21 12:00:15 -070078#endif
Yingdi Yu53c11c12016-03-20 12:56:49 -070079 m_menu->addAction(m_entryQuit);
80 m_tray = new QSystemTrayIcon(this);
81 m_tray->setContextMenu(m_menu);
82 connect(m_tray, SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
taylorchuc27dd482014-05-17 20:06:49 -070083 this, SLOT(iconActivated(QSystemTrayIcon::ActivationReason)));
Yingdi Yu53c11c12016-03-20 12:56:49 -070084 m_tray->setIcon(QIcon(DISCONNECT_ICON));
85 m_tray->show();
Qi Zhao86f2b212016-12-06 12:44:16 -080086 if (isAutoConfigEnabled()) {
87 stopAutoConfig(); // Make sure no more than one auto-config process exist
88 QTimer* mTimer = new QTimer(this);
89 mTimer->setSingleShot(true);
90 connect(mTimer, SIGNAL(timeout()), SLOT(startAutoConfig()));
91 mTimer->start(2000);
92 }
taylorchuc27dd482014-05-17 20:06:49 -070093}
94
95TrayMenu::~TrayMenu()
96{
97}
98
Qi Zhao86f2b212016-12-06 12:44:16 -080099void
100TrayMenu::appendMsg(QString &target, QString source)
taylorchuc27dd482014-05-17 20:06:49 -0700101{
Qi Zhao86f2b212016-12-06 12:44:16 -0800102 int maxLine = 100; // Max line that will show in auto-config status tab view
103 if (target.count(QString("\n")) > maxLine) { // Only when target QString has more line than maxLine, it needs remove line
104 int end = target.indexOf(QString("\n"));
105 target.remove(0, end + 1); // Remove the first line of target
106 }
107 target.append(source);
108}
109
110void
111TrayMenu::showPref()
112{
113 m_context->setContextProperty("acText", QVariant::fromValue(m_autoConfigMsg)); // Update auto-config status tab view
114}
115
116void
117TrayMenu::processOutput()
118{
119 std::string msg = m_acProc->readAllStandardOutput().toStdString();
120 if (msg != "") {
121 appendMsg(m_autoConfigMsg, QString::fromStdString(msg));
122 }
123 msg = m_acProc->readAllStandardError().toStdString();
124 if (msg != "") {
125 appendMsg(m_autoConfigMsg, QString::fromStdString(msg));
126 }
127 m_context->setContextProperty("acText", QVariant::fromValue(m_autoConfigMsg));
128}
129
130Q_INVOKABLE bool
131TrayMenu::isAutoConfigEnabled()
132{
133 bool sAutoConfig = m_settings.value("main/auto-config", QVariant(false)).toBool();
134 return sAutoConfig;
135}
136
137void
138TrayMenu::startAutoConfig()
139{
140 if (m_isNfdRunning) {
141 appendMsg(m_autoConfigMsg, QString("NDN auto configuration will start...\n"));
142 connect(m_acProc, SIGNAL(readyReadStandardOutput()), this, SLOT(processOutput()));
143 connect(m_acProc, SIGNAL(readyReadStandardError()), this, SLOT(processOutput()));
144 m_acProc->start((QCoreApplication::applicationDirPath().toStdString() + "/../Platform/ndn-autoconfig").c_str(),
145 QStringList()
146 << "--daemon");
147 }
148}
149
150void
151TrayMenu::stopAutoConfig()
152{
153#ifdef OSX_BUILD
taylorchuc27dd482014-05-17 20:06:49 -0700154 QProcess* proc = new QProcess();
Alexander Afanasyev4086d512014-07-11 15:56:33 -0700155 connect(proc, SIGNAL(finished(int)), proc, SLOT(deleteLater()));
Qi Zhao86f2b212016-12-06 12:44:16 -0800156 proc->startDetached("killall", QStringList() << "ndn-autoconfig");
157#endif
158}
159
160Q_INVOKABLE void
161TrayMenu::startStopAutoConfig(bool autoConfig)
162{
163 if (m_isNfdRunning) {
164 if (autoConfig) {
165 stopAutoConfig(); // Make sure no more than one auto-config process exist
166 QTimer* mTimer = new QTimer(this);
167 mTimer->setSingleShot(true);
168 connect(mTimer, SIGNAL(timeout()), SLOT(startAutoConfig()));
169 mTimer->start(2000);
170 m_context->setContextProperty("acText", QVariant::fromValue(m_autoConfigMsg));
171 m_settings.setValue("main/auto-config", true);
172 }
173 else {
174 stopAutoConfig();
175 appendMsg(m_autoConfigMsg, QString("NDN auto configuration will be stopped!\n"));
176 m_context->setContextProperty("acText", QVariant::fromValue(m_autoConfigMsg));
177 m_settings.setValue("main/auto-config", false);
178 }
179 }
180 else { // No need to start or stop auto-config when NFD is not running, but it needs to update settings
181 if (autoConfig) {
182 m_settings.setValue("main/auto-config", true);
183 }
184 else {
185 m_settings.setValue("main/auto-config", false);
186 }
187 }
taylorchuc27dd482014-05-17 20:06:49 -0700188}
189
190void
191TrayMenu::quitApp()
192{
193 QCoreApplication::exit(0);
194}
195
196void
197TrayMenu::iconActivated(QSystemTrayIcon::ActivationReason reason)
198{
199 switch (reason) {
200 // case QSystemTrayIcon::Trigger:
201 // emit showApp();
202 // break;
203 case QSystemTrayIcon::Context:
204 break;
205 default:
206 break;
207 }
208}
209
Alexander Afanasyev4086d512014-07-11 15:56:33 -0700210Q_INVOKABLE void
Qi Zhao86f2b212016-12-06 12:44:16 -0800211TrayMenu::startStopNfd(bool autoConfig)
Alexander Afanasyev4086d512014-07-11 15:56:33 -0700212{
213 if (!m_isNfdRunning) {
214 startNfd();
Qi Zhao86f2b212016-12-06 12:44:16 -0800215 if (autoConfig) {
216 stopAutoConfig(); // Make sure no more than one auto-config process exist
217 QTimer* mTimer = new QTimer(this);
218 mTimer->setSingleShot(true);
219 connect(mTimer, SIGNAL(timeout()), SLOT(startAutoConfig()));
220 mTimer->start(2000);
221 m_context->setContextProperty("acText", QVariant::fromValue(m_autoConfigMsg));
222 }
Alexander Afanasyev4086d512014-07-11 15:56:33 -0700223 }
224 else {
225 stopNfd();
Qi Zhao86f2b212016-12-06 12:44:16 -0800226 stopAutoConfig();
227 appendMsg(m_autoConfigMsg, QString("NDN auto configuration will be stopped!\n"));
228 m_context->setContextProperty("acText", QVariant::fromValue(m_autoConfigMsg));
Alexander Afanasyev4086d512014-07-11 15:56:33 -0700229 }
230}
231
taylorchuc27dd482014-05-17 20:06:49 -0700232void
233TrayMenu::startNfd()
234{
Alexander Afanasyev8e986f82016-03-21 14:19:15 -0700235#ifdef OSX_BUILD
236 QProcess* proc = new QProcess();
237 connect(proc, SIGNAL(finished(int)), proc, SLOT(deleteLater()));
238 proc->startDetached((QCoreApplication::applicationDirPath().toStdString() + "/../Platform/nfd").c_str(),
239 QStringList()
240 << "--config"
Alexander Afanasyev964feb92016-03-22 13:03:11 -0700241 << (QCoreApplication::applicationDirPath().toStdString() + "/../etc/ndn/nfd.conf").c_str());
Qi Zhao86f2b212016-12-06 12:44:16 -0800242
243
244 // #endif
245 // QProcess * proc = new QProcess();
246 // connect(proc, SIGNAL(finished(int)), proc, SLOT(deleteLater()));
247 // #ifdef __linux__
248 // proc->start("gksudo", QStringList() << NFD_START_COMMAND);
249 // #else
250 // proc->start("osascript", QStringList()
251 // << "-e"
252 // << "do shell script \"" NFD_START_COMMAND "\" with administrator privileges");
Alexander Afanasyev8e986f82016-03-21 14:19:15 -0700253#endif
taylorchuc27dd482014-05-17 20:06:49 -0700254}
255
256void
257TrayMenu::stopNfd()
258{
Alexander Afanasyev8e986f82016-03-21 14:19:15 -0700259#ifdef OSX_BUILD
260 QProcess* proc = new QProcess();
261 connect(proc, SIGNAL(finished(int)), proc, SLOT(deleteLater()));
262 proc->startDetached("killall", QStringList() << "nfd");
263#endif
taylorchuc27dd482014-05-17 20:06:49 -0700264}
265
susmit4fe3cb92016-03-20 17:08:41 -0700266Q_INVOKABLE void
267TrayMenu::addDeleteRoute()
268{
269 addRoute();
270}
271
272Q_INVOKABLE void
273TrayMenu::addRoute()
274{
275 std::cout << "Adding route" << std::endl;
276 QString cmd = "nfdc register /test tcp4://localhost";
277 QProcess *addNewRoute = new QProcess();
278 connect(addNewRoute,SIGNAL(finished(int)), addNewRoute, SLOT(deleteLater()));
279 addNewRoute->start("bash", QStringList() << "-c" << cmd);
280 std::cout << "Done" << std::endl;
susmit4fe3cb92016-03-20 17:08:41 -0700281}
282
283void
284TrayMenu::deleteRoute()
285{
286 std::cout << "Deleting route" << std::endl;
287 QString cmd = "nfdc unregister /test tcp4://localhost";
288 QProcess *addNewRoute = new QProcess();
289 connect(addNewRoute,SIGNAL(finished(int)), addNewRoute, SLOT(deleteLater()));
290 addNewRoute->start("bash", QStringList() << "-c" << cmd);
291 std::cout << "Done" << std::endl;
292
293}
294
taylorchuc27dd482014-05-17 20:06:49 -0700295void
296TrayMenu::updateNfdActivityIcon(bool isActive)
297{
Alexander Afanasyev4086d512014-07-11 15:56:33 -0700298 m_isNfdRunning = isActive;
299
taylorchuc27dd482014-05-17 20:06:49 -0700300 if (isActive) {
Yingdi Yu53c11c12016-03-20 12:56:49 -0700301 m_tray->setIcon(QIcon(CONNECT_ICON));
Alexander Afanasyev4086d512014-07-11 15:56:33 -0700302 m_context->setContextProperty("startStopButtonText", QVariant::fromValue(QString("Stop NFD")));
taylorchuc27dd482014-05-17 20:06:49 -0700303 }
304 else {
Yingdi Yu53c11c12016-03-20 12:56:49 -0700305 m_tray->setIcon(QIcon(DISCONNECT_ICON));
Alexander Afanasyev4086d512014-07-11 15:56:33 -0700306 m_context->setContextProperty("startStopButtonText", QVariant::fromValue(QString("Start NFD")));
taylorchuc27dd482014-05-17 20:06:49 -0700307 }
308}
309
Alexander Afanasyev11ae34d2016-03-21 11:55:16 -0700310void
311TrayMenu::enableCli()
312{
313#ifdef OSX_BUILD
314 AuthorizationRef authorizationRef;
315 OSStatus status = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment,
316 kAuthorizationFlagDefaults, &authorizationRef);
317 if (status != errAuthorizationSuccess)
318 return;
319
320 AuthorizationItem item = { kAuthorizationRightExecute, 0, 0, 0 };
321 AuthorizationRights rights = { 1, &item };
322 const AuthorizationFlags flags = kAuthorizationFlagDefaults | kAuthorizationFlagInteractionAllowed
323 | kAuthorizationFlagPreAuthorize | kAuthorizationFlagExtendRights;
324
325 status = AuthorizationCopyRights(authorizationRef, &rights, kAuthorizationEmptyEnvironment,
326 flags, 0);
327 if (status != errAuthorizationSuccess)
328 return;
329
330 char const* mkdir_arg[] = { "-p", "/usr/local/bin", nullptr };
331 char const* mkdir = "/bin/mkdir";
332 AuthorizationExecuteWithPrivileges(authorizationRef,
333 mkdir,
334 kAuthorizationFlagDefaults, (char**)mkdir_arg, nullptr);
335
Alexander Afanasyev964feb92016-03-22 13:03:11 -0700336 std::vector<std::string> arguments = { "-f", "-s",
Alexander Afanasyev11ae34d2016-03-21 11:55:16 -0700337 QCoreApplication::applicationDirPath().toStdString() + "/../Resources/ndn",
338 "/usr/local/bin/ndn" };
339 std::vector<const char*> args;
340 for (const auto& i : arguments) {
341 args.push_back(i.c_str());
342 }
343 args.push_back(nullptr);
344
Qi Zhao0e043e52016-12-05 18:27:09 -0800345 char const* helperTool = "/bin/ln";
Alexander Afanasyev11ae34d2016-03-21 11:55:16 -0700346 AuthorizationExecuteWithPrivileges(authorizationRef,
347 helperTool,
348 kAuthorizationFlagDefaults,
349 (char**)args.data(), NULL);
350
Alexander Afanasyev11ae34d2016-03-21 11:55:16 -0700351 AuthorizationFree(authorizationRef, kAuthorizationFlagDestroyRights);
352#endif
353}
354
taylorchuc27dd482014-05-17 20:06:49 -0700355} // namespace ndn