2012-06-10 16:50:54 +00:00
|
|
|
/*
|
|
|
|
* synergy -- mouse and keyboard sharing utility
|
2012-09-04 02:09:56 +00:00
|
|
|
* Copyright (C) 2012 Bolton Software Ltd.
|
|
|
|
* Copyright (C) 2002 Chris Schoeneman
|
2012-06-10 16:50:54 +00:00
|
|
|
*
|
|
|
|
* This package is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* found in the file COPYING that should have accompanied this file.
|
|
|
|
*
|
|
|
|
* This package is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "CApp.h"
|
|
|
|
#include "CLog.h"
|
|
|
|
#include "Version.h"
|
|
|
|
#include "ProtocolTypes.h"
|
|
|
|
#include "CArch.h"
|
|
|
|
#include "XBase.h"
|
|
|
|
#include "XArch.h"
|
|
|
|
#include "LogOutputters.h"
|
|
|
|
#include "XSynergy.h"
|
|
|
|
#include "CArgsBase.h"
|
2012-07-05 18:05:35 +00:00
|
|
|
#include "CIpcServerProxy.h"
|
|
|
|
#include "TMethodEventJob.h"
|
|
|
|
#include "CIpcMessage.h"
|
|
|
|
#include "Ipc.h"
|
2012-07-14 00:15:07 +00:00
|
|
|
#include "CEventQueue.h"
|
2012-06-10 16:50:54 +00:00
|
|
|
|
|
|
|
#if SYSAPI_WIN32
|
|
|
|
#include "CArchMiscWindows.h"
|
|
|
|
#include "IEventQueue.h"
|
|
|
|
#include "TMethodJob.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <iostream>
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
#if WINAPI_CARBON
|
|
|
|
#include <ApplicationServices/ApplicationServices.h>
|
|
|
|
#endif
|
|
|
|
|
2013-09-18 14:12:19 +00:00
|
|
|
#if defined(__APPLE__)
|
|
|
|
#include "COSXDragSimulator.h"
|
|
|
|
#endif
|
|
|
|
|
2012-06-10 16:50:54 +00:00
|
|
|
CApp* CApp::s_instance = nullptr;
|
|
|
|
|
2013-06-29 14:17:49 +00:00
|
|
|
CApp::CApp(IEventQueue* events, CreateTaskBarReceiverFunc createTaskBarReceiver, CArgsBase* args) :
|
|
|
|
m_bye(&exit),
|
|
|
|
m_taskBarReceiver(NULL),
|
|
|
|
m_suspended(false),
|
2014-02-25 15:03:43 +00:00
|
|
|
m_events(events),
|
|
|
|
m_args(args),
|
|
|
|
m_createTaskBarReceiver(createTaskBarReceiver),
|
|
|
|
m_appUtil(events),
|
|
|
|
m_ipcClient(nullptr)
|
2012-06-10 16:50:54 +00:00
|
|
|
{
|
|
|
|
assert(s_instance == nullptr);
|
|
|
|
s_instance = this;
|
|
|
|
}
|
|
|
|
|
|
|
|
CApp::~CApp()
|
|
|
|
{
|
|
|
|
delete m_args;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
CApp::isArg(
|
|
|
|
int argi, int argc, const char* const* argv,
|
|
|
|
const char* name1, const char* name2,
|
|
|
|
int minRequiredParameters)
|
|
|
|
{
|
|
|
|
if ((name1 != NULL && strcmp(argv[argi], name1) == 0) ||
|
|
|
|
(name2 != NULL && strcmp(argv[argi], name2) == 0)) {
|
|
|
|
// match. check args left.
|
|
|
|
if (argi + minRequiredParameters >= argc) {
|
|
|
|
LOG((CLOG_PRINT "%s: missing arguments for `%s'" BYE,
|
|
|
|
argsBase().m_pname, argv[argi], argsBase().m_pname));
|
|
|
|
m_bye(kExitArgs);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// no match
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
CApp::parseArg(const int& argc, const char* const* argv, int& i)
|
|
|
|
{
|
|
|
|
if (appUtil().parseArg(argc, argv, i)) {
|
|
|
|
// handled by platform util
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (isArg(i, argc, argv, "-d", "--debug", 1)) {
|
|
|
|
// change logging level
|
|
|
|
argsBase().m_logFilter = argv[++i];
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (isArg(i, argc, argv, "-l", "--log", 1)) {
|
|
|
|
argsBase().m_logFile = argv[++i];
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (isArg(i, argc, argv, "-f", "--no-daemon")) {
|
|
|
|
// not a daemon
|
|
|
|
argsBase().m_daemon = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (isArg(i, argc, argv, NULL, "--daemon")) {
|
|
|
|
// daemonize
|
|
|
|
argsBase().m_daemon = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (isArg(i, argc, argv, "-n", "--name", 1)) {
|
|
|
|
// save screen name
|
|
|
|
argsBase().m_name = argv[++i];
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (isArg(i, argc, argv, "-1", "--no-restart")) {
|
|
|
|
// don't try to restart
|
|
|
|
argsBase().m_restartable = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (isArg(i, argc, argv, NULL, "--restart")) {
|
|
|
|
// try to restart
|
|
|
|
argsBase().m_restartable = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (isArg(i, argc, argv, "-z", NULL)) {
|
|
|
|
argsBase().m_backend = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (isArg(i, argc, argv, NULL, "--no-hooks")) {
|
|
|
|
argsBase().m_noHooks = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (isArg(i, argc, argv, "-h", "--help")) {
|
|
|
|
help();
|
|
|
|
m_bye(kExitSuccess);
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (isArg(i, argc, argv, NULL, "--version")) {
|
|
|
|
version();
|
|
|
|
m_bye(kExitSuccess);
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (isArg(i, argc, argv, NULL, "--no-tray")) {
|
|
|
|
argsBase().m_disableTray = true;
|
|
|
|
}
|
|
|
|
|
2012-07-05 18:05:35 +00:00
|
|
|
else if (isArg(i, argc, argv, NULL, "--ipc")) {
|
|
|
|
argsBase().m_enableIpc = true;
|
|
|
|
}
|
|
|
|
|
2013-03-15 16:14:43 +00:00
|
|
|
else if (isArg(i, argc, argv, NULL, "--server")) {
|
|
|
|
// HACK: stop error happening when using portable (synergyp)
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (isArg(i, argc, argv, NULL, "--client")) {
|
|
|
|
// HACK: stop error happening when using portable (synergyp)
|
|
|
|
}
|
|
|
|
|
2013-04-09 21:57:07 +00:00
|
|
|
else if (isArg(i, argc, argv, NULL, "--crypto-pass")) {
|
|
|
|
argsBase().m_crypto.m_pass = argv[++i];
|
2013-08-16 18:06:30 +00:00
|
|
|
argsBase().m_crypto.setMode("cfb");
|
2013-04-09 21:57:07 +00:00
|
|
|
}
|
|
|
|
|
2013-09-18 08:34:32 +00:00
|
|
|
else if (isArg(i, argc, argv, NULL, "--enable-drag-drop")) {
|
2014-01-28 16:50:40 +00:00
|
|
|
bool useDragDrop = true;
|
|
|
|
|
2013-09-18 08:34:32 +00:00
|
|
|
#ifdef WINAPI_XWINDOWS
|
2014-01-28 16:50:40 +00:00
|
|
|
|
|
|
|
useDragDrop = false;
|
|
|
|
LOG((CLOG_INFO "ignoring --enable-drag-drop, not supported on linux."));
|
|
|
|
|
2013-09-18 08:34:32 +00:00
|
|
|
#endif
|
2014-01-28 16:50:40 +00:00
|
|
|
|
2014-02-17 19:38:26 +00:00
|
|
|
#ifdef WINAPI_MSWINDOWS
|
|
|
|
|
|
|
|
OSVERSIONINFO osvi;
|
|
|
|
ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
|
|
|
|
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
|
|
|
GetVersionEx(&osvi);
|
|
|
|
|
2014-01-28 17:21:49 +00:00
|
|
|
if (osvi.dwMajorVersion < 6) {
|
2014-01-28 16:50:40 +00:00
|
|
|
useDragDrop = false;
|
|
|
|
LOG((CLOG_INFO "ignoring --enable-drag-drop, not supported below vista."));
|
2014-02-17 19:38:26 +00:00
|
|
|
}
|
|
|
|
#endif
|
2014-01-28 16:50:40 +00:00
|
|
|
|
|
|
|
if (useDragDrop) {
|
|
|
|
argsBase().m_enableDragDrop = true;
|
|
|
|
}
|
2013-09-18 08:34:32 +00:00
|
|
|
}
|
|
|
|
|
2012-06-10 16:50:54 +00:00
|
|
|
else {
|
|
|
|
// option not supported here
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
CApp::parseArgs(int argc, const char* const* argv, int& i)
|
|
|
|
{
|
|
|
|
// about these use of assert() here:
|
|
|
|
// previously an /analyze warning was displayed if we only used assert and
|
|
|
|
// did not return on failure. however, this warning does not appear to show
|
|
|
|
// any more (could be because new compiler args have been added).
|
|
|
|
// the asserts are programmer benefit only; the os should never pass 0 args,
|
|
|
|
// because the first is always the binary name. the only way assert would
|
|
|
|
// evaluate to true, is if this parse function were implemented incorrectly,
|
|
|
|
// which is unlikely because it's old code and has a specific use.
|
|
|
|
// we should avoid using anything other than assert here, because it will
|
|
|
|
// look like important code, which it's not really.
|
|
|
|
assert(argsBase().m_pname != NULL);
|
|
|
|
assert(argv != NULL);
|
|
|
|
assert(argc >= 1);
|
|
|
|
|
|
|
|
// set defaults
|
|
|
|
argsBase().m_name = ARCH->getHostName();
|
|
|
|
|
|
|
|
// parse options
|
|
|
|
for (i = 1; i < argc; ++i) {
|
|
|
|
|
|
|
|
if (parseArg(argc, argv, i)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (isArg(i, argc, argv, "--", NULL)) {
|
|
|
|
// remaining arguments are not options
|
|
|
|
++i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (argv[i][0] == '-') {
|
|
|
|
std::cerr << "Unrecognized option: " << argv[i] << std::endl;
|
|
|
|
m_bye(kExitArgs);
|
|
|
|
}
|
|
|
|
|
|
|
|
else {
|
|
|
|
// this and remaining arguments are not options
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#if SYSAPI_WIN32
|
|
|
|
// suggest that user installs as a windows service. when launched as
|
|
|
|
// service, process should automatically detect that it should run in
|
|
|
|
// daemon mode.
|
|
|
|
if (argsBase().m_daemon) {
|
|
|
|
LOG((CLOG_ERR
|
|
|
|
"the --daemon argument is not supported on windows. "
|
|
|
|
"instead, install %s as a service (--service install)",
|
|
|
|
argsBase().m_pname));
|
|
|
|
m_bye(kExitArgs);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
CApp::version()
|
|
|
|
{
|
|
|
|
char buffer[500];
|
|
|
|
sprintf(
|
|
|
|
buffer,
|
|
|
|
"%s %s, protocol version %d.%d\n%s",
|
|
|
|
argsBase().m_pname,
|
|
|
|
kVersion,
|
|
|
|
kProtocolMajorVersion,
|
|
|
|
kProtocolMinorVersion,
|
|
|
|
kCopyright
|
|
|
|
);
|
|
|
|
|
|
|
|
std::cout << buffer << std::endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
CApp::run(int argc, char** argv)
|
2013-03-15 16:14:43 +00:00
|
|
|
{
|
2012-06-10 16:50:54 +00:00
|
|
|
#if MAC_OS_X_VERSION_10_7
|
|
|
|
// dock hide only supported on lion :(
|
|
|
|
ProcessSerialNumber psn = { 0, kCurrentProcess };
|
2014-02-25 15:03:43 +00:00
|
|
|
|
|
|
|
#pragma GCC diagnostic push
|
|
|
|
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
2012-06-10 16:50:54 +00:00
|
|
|
GetCurrentProcess(&psn);
|
2014-02-25 15:03:43 +00:00
|
|
|
#pragma GCC diagnostic pop
|
|
|
|
|
2012-06-10 16:50:54 +00:00
|
|
|
TransformProcessType(&psn, kProcessTransformToBackgroundApplication);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// install application in to arch
|
|
|
|
appUtil().adoptApp(this);
|
|
|
|
|
|
|
|
// HACK: fail by default (saves us setting result in each catch)
|
|
|
|
int result = kExitFailed;
|
|
|
|
|
|
|
|
try {
|
|
|
|
result = appUtil().run(argc, argv);
|
|
|
|
}
|
|
|
|
catch (XExitApp& e) {
|
|
|
|
// instead of showing a nasty error, just exit with the error code.
|
|
|
|
// not sure if i like this behaviour, but it's probably better than
|
|
|
|
// using the exit(int) function!
|
|
|
|
result = e.getCode();
|
|
|
|
}
|
|
|
|
catch (XBase& e) {
|
|
|
|
LOG((CLOG_CRIT "Exception: %s\n", e.what()));
|
|
|
|
}
|
|
|
|
catch (XArch& e) {
|
|
|
|
LOG((CLOG_CRIT "Init failed: %s" BYE, e.what().c_str(), argsBase().m_pname));
|
|
|
|
}
|
|
|
|
catch (std::exception& e) {
|
|
|
|
LOG((CLOG_CRIT "Exception: %s\n", e.what()));
|
|
|
|
}
|
|
|
|
catch (...) {
|
|
|
|
LOG((CLOG_CRIT "An unexpected exception occurred.\n"));
|
|
|
|
}
|
|
|
|
|
|
|
|
appUtil().beforeAppExit();
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
CApp::daemonMainLoop(int, const char**)
|
|
|
|
{
|
|
|
|
#if SYSAPI_WIN32
|
|
|
|
CSystemLogger sysLogger(daemonName(), false);
|
|
|
|
#else
|
|
|
|
CSystemLogger sysLogger(daemonName(), true);
|
|
|
|
#endif
|
|
|
|
return mainLoop();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
CApp::setupFileLogging()
|
|
|
|
{
|
|
|
|
if (argsBase().m_logFile != NULL) {
|
|
|
|
m_fileLog = new CFileLogOutputter(argsBase().m_logFile);
|
|
|
|
CLOG->insert(m_fileLog);
|
|
|
|
LOG((CLOG_DEBUG1 "logging to file (%s) enabled", argsBase().m_logFile));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
CApp::loggingFilterWarning()
|
|
|
|
{
|
|
|
|
if (CLOG->getFilter() > CLOG->getConsoleMaxLevel()) {
|
|
|
|
if (argsBase().m_logFile == NULL) {
|
|
|
|
LOG((CLOG_WARN "log messages above %s are NOT sent to console (use file logging)",
|
|
|
|
CLOG->getFilterName(CLOG->getConsoleMaxLevel())));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
CApp::initApp(int argc, const char** argv)
|
|
|
|
{
|
|
|
|
// parse command line
|
|
|
|
parseArgs(argc, argv);
|
|
|
|
|
|
|
|
// setup file logging after parsing args
|
|
|
|
setupFileLogging();
|
|
|
|
|
|
|
|
// load configuration
|
|
|
|
loadConfig();
|
|
|
|
|
|
|
|
if (!argsBase().m_disableTray) {
|
|
|
|
|
|
|
|
// create a log buffer so we can show the latest message
|
|
|
|
// as a tray icon tooltip
|
|
|
|
CBufferedLogOutputter* logBuffer = new CBufferedLogOutputter(1000);
|
|
|
|
CLOG->insert(logBuffer, true);
|
|
|
|
|
|
|
|
// make the task bar receiver. the user can control this app
|
|
|
|
// through the task bar.
|
2013-06-29 14:17:49 +00:00
|
|
|
m_taskBarReceiver = m_createTaskBarReceiver(logBuffer, m_events);
|
2012-06-10 16:50:54 +00:00
|
|
|
}
|
|
|
|
}
|
2012-07-05 18:05:35 +00:00
|
|
|
|
|
|
|
void
|
|
|
|
CApp::initIpcClient()
|
|
|
|
{
|
2013-07-16 19:02:30 +00:00
|
|
|
m_ipcClient = new CIpcClient(m_events, m_socketMultiplexer);
|
2012-07-05 18:05:35 +00:00
|
|
|
m_ipcClient->connect();
|
|
|
|
|
2013-06-29 14:17:49 +00:00
|
|
|
m_events->adoptHandler(
|
|
|
|
m_events->forCIpcClient().messageReceived(), m_ipcClient,
|
2012-07-10 01:51:51 +00:00
|
|
|
new TMethodEventJob<CApp>(this, &CApp::handleIpcMessage));
|
2012-07-05 18:05:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2012-07-10 01:51:51 +00:00
|
|
|
CApp::cleanupIpcClient()
|
2012-07-05 18:05:35 +00:00
|
|
|
{
|
2012-07-10 01:51:51 +00:00
|
|
|
m_ipcClient->disconnect();
|
2013-06-29 14:17:49 +00:00
|
|
|
m_events->removeHandler(m_events->forCIpcClient().messageReceived(), m_ipcClient);
|
2012-07-10 01:51:51 +00:00
|
|
|
delete m_ipcClient;
|
2012-07-05 18:05:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
CApp::handleIpcMessage(const CEvent& e, void*)
|
|
|
|
{
|
2012-07-10 01:51:51 +00:00
|
|
|
CIpcMessage* m = static_cast<CIpcMessage*>(e.getDataObject());
|
|
|
|
if (m->type() == kIpcShutdown) {
|
2012-07-05 18:05:35 +00:00
|
|
|
LOG((CLOG_INFO "got ipc shutdown message"));
|
2013-06-29 14:17:49 +00:00
|
|
|
m_events->addEvent(CEvent(CEvent::kQuit));
|
2013-09-16 15:21:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
CApp::runEventsLoop(void*)
|
|
|
|
{
|
|
|
|
m_events->loop();
|
2013-09-18 14:12:19 +00:00
|
|
|
|
|
|
|
#if defined(MAC_OS_X_VERSION_10_7)
|
|
|
|
|
|
|
|
stopCocoaLoop();
|
|
|
|
|
|
|
|
#endif
|
2012-07-05 18:05:35 +00:00
|
|
|
}
|