blob: d4d2637eb7f27337e433cb4f5f244063088ad3b5 [file] [log] [blame]
taylorchuc27dd482014-05-17 20:06:49 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Alexander Afanasyev37667752017-02-02 13:52:12 -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
taylorchuc27dd482014-05-17 20:06:49 -070020#include "tray-menu.hpp"
Alexander Afanasyev37667752017-02-02 13:52:12 -080021#include "tray-menu.moc"
taylorchuc27dd482014-05-17 20:06:49 -070022
23#include <ndn-cxx/face.hpp>
24#include <ndn-cxx/interest.hpp>
25
taylorchuc27dd482014-05-17 20:06:49 -070026#ifdef OSX_BUILD
Alexander Afanasyev0621cec2016-03-20 23:18:27 -070027#define CONNECT_ICON ":/res/icon-connected-black.png"
28#define DISCONNECT_ICON ":/res/icon-disconnected-black.png"
Alexander Afanasyev11ae34d2016-03-21 11:55:16 -070029
30#include <Security/Authorization.h>
31#include <Security/AuthorizationTags.h>
taylorchuc27dd482014-05-17 20:06:49 -070032#else
Alexander Afanasyev0621cec2016-03-20 23:18:27 -070033#define CONNECT_ICON ":/res/icon-connected-white.png"
34#define DISCONNECT_ICON ":/res/icon-disconnected-white.png"
Alexander Afanasyev11ae34d2016-03-21 11:55:16 -070035#endif // OSX_BUILD
taylorchuc27dd482014-05-17 20:06:49 -070036
taylorchuc27dd482014-05-17 20:06:49 -070037namespace ndn {
38
Alexander Afanasyev81509f32016-03-21 17:02:38 -070039TrayMenu::TrayMenu(QQmlContext* context, Face& face)
Alexander Afanasyev4086d512014-07-11 15:56:33 -070040 : m_context(context)
41 , m_isNfdRunning(false)
Yingdi Yu53c11c12016-03-20 12:56:49 -070042 , m_menu(new QMenu(this))
43 , m_entryPref(new QAction("Preferences...", m_menu))
Alexander Afanasyev11ae34d2016-03-21 11:55:16 -070044 , m_entrySec(new QAction("Security...", m_menu))
45#ifdef OSX_BUILD
46 , m_entryEnableCli(new QAction("Enable Command Terminal Usage...", m_menu))
47#endif
Yingdi Yu53c11c12016-03-20 12:56:49 -070048 , m_entryQuit(new QAction("Quit", m_menu))
Yingdi Yu1f824642016-03-20 17:07:22 -070049 , m_keyViewerDialog(new ncc::KeyViewerDialog)
Alexander Afanasyev81509f32016-03-21 17:02:38 -070050 , m_face(face)
Qi Zhao86f2b212016-12-06 12:44:16 -080051 , m_acProc(new QProcess())
52 , m_settings(new QSettings())
Yingdi Yu53c11c12016-03-20 12:56:49 -070053{
54 connect(m_entryPref, SIGNAL(triggered()), this, SIGNAL(showApp()));
Qi Zhao86f2b212016-12-06 12:44:16 -080055 connect(this, SIGNAL(showApp()), this, SLOT(showPref()));
Yingdi Yu1f824642016-03-20 17:07:22 -070056 connect(m_entrySec, SIGNAL(triggered()), m_keyViewerDialog, SLOT(present()));
Yingdi Yu53c11c12016-03-20 12:56:49 -070057 connect(m_entryQuit, SIGNAL(triggered()), this, SLOT(quitApp()));
taylorchuc27dd482014-05-17 20:06:49 -070058
Alexander Afanasyev11ae34d2016-03-21 11:55:16 -070059#ifdef OSX_BUILD
60 connect(m_entryEnableCli, SIGNAL(triggered()), this, SLOT(enableCli()));
61#endif
Yingdi Yu1f824642016-03-20 17:07:22 -070062
Alexander Afanasyev4086d512014-07-11 15:56:33 -070063 connect(this, SIGNAL(nfdActivityUpdate(bool)), this, SLOT(updateNfdActivityIcon(bool)),
64 Qt::QueuedConnection);
65
66 m_context->setContextProperty("startStopButtonText", QVariant::fromValue(QString("Start NFD")));
Qi Zhao86f2b212016-12-06 12:44:16 -080067 m_context->setContextProperty("acText", QVariant::fromValue(QString("")));
taylorchuc27dd482014-05-17 20:06:49 -070068
Yingdi Yu53c11c12016-03-20 12:56:49 -070069 m_menu->addAction(m_entryPref);
70 m_menu->addAction(m_entrySec);
susmit50607912016-03-21 12:00:15 -070071#ifdef OSX_BUILD
Alexander Afanasyev11ae34d2016-03-21 11:55:16 -070072 m_menu->addAction(m_entryEnableCli);
susmit50607912016-03-21 12:00:15 -070073#endif
Yingdi Yu53c11c12016-03-20 12:56:49 -070074 m_menu->addAction(m_entryQuit);
75 m_tray = new QSystemTrayIcon(this);
76 m_tray->setContextMenu(m_menu);
77 connect(m_tray, SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
taylorchuc27dd482014-05-17 20:06:49 -070078 this, SLOT(iconActivated(QSystemTrayIcon::ActivationReason)));
Yingdi Yu53c11c12016-03-20 12:56:49 -070079 m_tray->setIcon(QIcon(DISCONNECT_ICON));
80 m_tray->show();
Qi Zhao86f2b212016-12-06 12:44:16 -080081 if (isAutoConfigEnabled()) {
82 stopAutoConfig(); // Make sure no more than one auto-config process exist
83 QTimer* mTimer = new QTimer(this);
84 mTimer->setSingleShot(true);
85 connect(mTimer, SIGNAL(timeout()), SLOT(startAutoConfig()));
86 mTimer->start(2000);
87 }
taylorchuc27dd482014-05-17 20:06:49 -070088}
89
90TrayMenu::~TrayMenu()
91{
92}
93
Qi Zhao86f2b212016-12-06 12:44:16 -080094void
95TrayMenu::appendMsg(QString &target, QString source)
taylorchuc27dd482014-05-17 20:06:49 -070096{
Qi Zhao86f2b212016-12-06 12:44:16 -080097 int maxLine = 100; // Max line that will show in auto-config status tab view
98 if (target.count(QString("\n")) > maxLine) { // Only when target QString has more line than maxLine, it needs remove line
99 int end = target.indexOf(QString("\n"));
100 target.remove(0, end + 1); // Remove the first line of target
101 }
102 target.append(source);
103}
104
105void
106TrayMenu::showPref()
107{
108 m_context->setContextProperty("acText", QVariant::fromValue(m_autoConfigMsg)); // Update auto-config status tab view
109}
110
111void
112TrayMenu::processOutput()
113{
114 std::string msg = m_acProc->readAllStandardOutput().toStdString();
115 if (msg != "") {
116 appendMsg(m_autoConfigMsg, QString::fromStdString(msg));
117 }
118 msg = m_acProc->readAllStandardError().toStdString();
119 if (msg != "") {
120 appendMsg(m_autoConfigMsg, QString::fromStdString(msg));
121 }
122 m_context->setContextProperty("acText", QVariant::fromValue(m_autoConfigMsg));
123}
124
125Q_INVOKABLE bool
126TrayMenu::isAutoConfigEnabled()
127{
128 bool sAutoConfig = m_settings.value("main/auto-config", QVariant(false)).toBool();
129 return sAutoConfig;
130}
131
132void
133TrayMenu::startAutoConfig()
134{
135 if (m_isNfdRunning) {
136 appendMsg(m_autoConfigMsg, QString("NDN auto configuration will start...\n"));
137 connect(m_acProc, SIGNAL(readyReadStandardOutput()), this, SLOT(processOutput()));
138 connect(m_acProc, SIGNAL(readyReadStandardError()), this, SLOT(processOutput()));
139 m_acProc->start((QCoreApplication::applicationDirPath().toStdString() + "/../Platform/ndn-autoconfig").c_str(),
140 QStringList()
141 << "--daemon");
142 }
143}
144
145void
146TrayMenu::stopAutoConfig()
147{
148#ifdef OSX_BUILD
taylorchuc27dd482014-05-17 20:06:49 -0700149 QProcess* proc = new QProcess();
Alexander Afanasyev4086d512014-07-11 15:56:33 -0700150 connect(proc, SIGNAL(finished(int)), proc, SLOT(deleteLater()));
Qi Zhao86f2b212016-12-06 12:44:16 -0800151 proc->startDetached("killall", QStringList() << "ndn-autoconfig");
152#endif
153}
154
155Q_INVOKABLE void
156TrayMenu::startStopAutoConfig(bool autoConfig)
157{
158 if (m_isNfdRunning) {
159 if (autoConfig) {
160 stopAutoConfig(); // Make sure no more than one auto-config process exist
161 QTimer* mTimer = new QTimer(this);
162 mTimer->setSingleShot(true);
163 connect(mTimer, SIGNAL(timeout()), SLOT(startAutoConfig()));
164 mTimer->start(2000);
165 m_context->setContextProperty("acText", QVariant::fromValue(m_autoConfigMsg));
166 m_settings.setValue("main/auto-config", true);
167 }
168 else {
169 stopAutoConfig();
170 appendMsg(m_autoConfigMsg, QString("NDN auto configuration will be stopped!\n"));
171 m_context->setContextProperty("acText", QVariant::fromValue(m_autoConfigMsg));
172 m_settings.setValue("main/auto-config", false);
173 }
174 }
175 else { // No need to start or stop auto-config when NFD is not running, but it needs to update settings
176 if (autoConfig) {
177 m_settings.setValue("main/auto-config", true);
178 }
179 else {
180 m_settings.setValue("main/auto-config", false);
181 }
182 }
taylorchuc27dd482014-05-17 20:06:49 -0700183}
184
185void
186TrayMenu::quitApp()
187{
188 QCoreApplication::exit(0);
189}
190
191void
192TrayMenu::iconActivated(QSystemTrayIcon::ActivationReason reason)
193{
194 switch (reason) {
195 // case QSystemTrayIcon::Trigger:
196 // emit showApp();
197 // break;
198 case QSystemTrayIcon::Context:
199 break;
200 default:
201 break;
202 }
203}
204
Alexander Afanasyev4086d512014-07-11 15:56:33 -0700205Q_INVOKABLE void
Qi Zhao86f2b212016-12-06 12:44:16 -0800206TrayMenu::startStopNfd(bool autoConfig)
Alexander Afanasyev4086d512014-07-11 15:56:33 -0700207{
208 if (!m_isNfdRunning) {
209 startNfd();
Qi Zhao86f2b212016-12-06 12:44:16 -0800210 if (autoConfig) {
211 stopAutoConfig(); // Make sure no more than one auto-config process exist
212 QTimer* mTimer = new QTimer(this);
213 mTimer->setSingleShot(true);
214 connect(mTimer, SIGNAL(timeout()), SLOT(startAutoConfig()));
215 mTimer->start(2000);
216 m_context->setContextProperty("acText", QVariant::fromValue(m_autoConfigMsg));
217 }
Alexander Afanasyev4086d512014-07-11 15:56:33 -0700218 }
219 else {
220 stopNfd();
Qi Zhao86f2b212016-12-06 12:44:16 -0800221 stopAutoConfig();
222 appendMsg(m_autoConfigMsg, QString("NDN auto configuration will be stopped!\n"));
223 m_context->setContextProperty("acText", QVariant::fromValue(m_autoConfigMsg));
Alexander Afanasyev4086d512014-07-11 15:56:33 -0700224 }
225}
226
taylorchuc27dd482014-05-17 20:06:49 -0700227void
228TrayMenu::startNfd()
229{
Alexander Afanasyev8e986f82016-03-21 14:19:15 -0700230#ifdef OSX_BUILD
231 QProcess* proc = new QProcess();
232 connect(proc, SIGNAL(finished(int)), proc, SLOT(deleteLater()));
233 proc->startDetached((QCoreApplication::applicationDirPath().toStdString() + "/../Platform/nfd").c_str(),
234 QStringList()
235 << "--config"
Alexander Afanasyev964feb92016-03-22 13:03:11 -0700236 << (QCoreApplication::applicationDirPath().toStdString() + "/../etc/ndn/nfd.conf").c_str());
Qi Zhao86f2b212016-12-06 12:44:16 -0800237
238
239 // #endif
240 // QProcess * proc = new QProcess();
241 // connect(proc, SIGNAL(finished(int)), proc, SLOT(deleteLater()));
242 // #ifdef __linux__
243 // proc->start("gksudo", QStringList() << NFD_START_COMMAND);
244 // #else
245 // proc->start("osascript", QStringList()
246 // << "-e"
247 // << "do shell script \"" NFD_START_COMMAND "\" with administrator privileges");
Alexander Afanasyev8e986f82016-03-21 14:19:15 -0700248#endif
taylorchuc27dd482014-05-17 20:06:49 -0700249}
250
251void
252TrayMenu::stopNfd()
253{
Alexander Afanasyev8e986f82016-03-21 14:19:15 -0700254#ifdef OSX_BUILD
255 QProcess* proc = new QProcess();
256 connect(proc, SIGNAL(finished(int)), proc, SLOT(deleteLater()));
257 proc->startDetached("killall", QStringList() << "nfd");
258#endif
taylorchuc27dd482014-05-17 20:06:49 -0700259}
260
susmit4fe3cb92016-03-20 17:08:41 -0700261Q_INVOKABLE void
262TrayMenu::addDeleteRoute()
263{
264 addRoute();
265}
266
267Q_INVOKABLE void
268TrayMenu::addRoute()
269{
270 std::cout << "Adding route" << std::endl;
271 QString cmd = "nfdc register /test tcp4://localhost";
272 QProcess *addNewRoute = new QProcess();
273 connect(addNewRoute,SIGNAL(finished(int)), addNewRoute, SLOT(deleteLater()));
274 addNewRoute->start("bash", QStringList() << "-c" << cmd);
275 std::cout << "Done" << std::endl;
susmit4fe3cb92016-03-20 17:08:41 -0700276}
277
278void
279TrayMenu::deleteRoute()
280{
281 std::cout << "Deleting route" << std::endl;
282 QString cmd = "nfdc unregister /test tcp4://localhost";
283 QProcess *addNewRoute = new QProcess();
284 connect(addNewRoute,SIGNAL(finished(int)), addNewRoute, SLOT(deleteLater()));
285 addNewRoute->start("bash", QStringList() << "-c" << cmd);
286 std::cout << "Done" << std::endl;
287
288}
289
taylorchuc27dd482014-05-17 20:06:49 -0700290void
291TrayMenu::updateNfdActivityIcon(bool isActive)
292{
Alexander Afanasyev4086d512014-07-11 15:56:33 -0700293 m_isNfdRunning = isActive;
294
taylorchuc27dd482014-05-17 20:06:49 -0700295 if (isActive) {
Yingdi Yu53c11c12016-03-20 12:56:49 -0700296 m_tray->setIcon(QIcon(CONNECT_ICON));
Alexander Afanasyev4086d512014-07-11 15:56:33 -0700297 m_context->setContextProperty("startStopButtonText", QVariant::fromValue(QString("Stop NFD")));
taylorchuc27dd482014-05-17 20:06:49 -0700298 }
299 else {
Yingdi Yu53c11c12016-03-20 12:56:49 -0700300 m_tray->setIcon(QIcon(DISCONNECT_ICON));
Alexander Afanasyev4086d512014-07-11 15:56:33 -0700301 m_context->setContextProperty("startStopButtonText", QVariant::fromValue(QString("Start NFD")));
taylorchuc27dd482014-05-17 20:06:49 -0700302 }
303}
304
Alexander Afanasyev11ae34d2016-03-21 11:55:16 -0700305void
306TrayMenu::enableCli()
307{
308#ifdef OSX_BUILD
309 AuthorizationRef authorizationRef;
310 OSStatus status = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment,
311 kAuthorizationFlagDefaults, &authorizationRef);
312 if (status != errAuthorizationSuccess)
313 return;
314
315 AuthorizationItem item = { kAuthorizationRightExecute, 0, 0, 0 };
316 AuthorizationRights rights = { 1, &item };
317 const AuthorizationFlags flags = kAuthorizationFlagDefaults | kAuthorizationFlagInteractionAllowed
318 | kAuthorizationFlagPreAuthorize | kAuthorizationFlagExtendRights;
319
320 status = AuthorizationCopyRights(authorizationRef, &rights, kAuthorizationEmptyEnvironment,
321 flags, 0);
322 if (status != errAuthorizationSuccess)
323 return;
324
325 char const* mkdir_arg[] = { "-p", "/usr/local/bin", nullptr };
326 char const* mkdir = "/bin/mkdir";
327 AuthorizationExecuteWithPrivileges(authorizationRef,
328 mkdir,
329 kAuthorizationFlagDefaults, (char**)mkdir_arg, nullptr);
330
Alexander Afanasyev964feb92016-03-22 13:03:11 -0700331 std::vector<std::string> arguments = { "-f", "-s",
Alexander Afanasyev11ae34d2016-03-21 11:55:16 -0700332 QCoreApplication::applicationDirPath().toStdString() + "/../Resources/ndn",
333 "/usr/local/bin/ndn" };
334 std::vector<const char*> args;
335 for (const auto& i : arguments) {
336 args.push_back(i.c_str());
337 }
338 args.push_back(nullptr);
339
Qi Zhao0e043e52016-12-05 18:27:09 -0800340 char const* helperTool = "/bin/ln";
Alexander Afanasyev11ae34d2016-03-21 11:55:16 -0700341 AuthorizationExecuteWithPrivileges(authorizationRef,
342 helperTool,
343 kAuthorizationFlagDefaults,
344 (char**)args.data(), NULL);
345
Alexander Afanasyev11ae34d2016-03-21 11:55:16 -0700346 AuthorizationFree(authorizationRef, kAuthorizationFlagDestroyRights);
347#endif
348}
349
taylorchuc27dd482014-05-17 20:06:49 -0700350} // namespace ndn