594 lines
16 KiB
C
594 lines
16 KiB
C
/**************************************************************************/
|
|
/* */
|
|
/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */
|
|
/* Copyright (c) 2008-2017 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */
|
|
/* Copyright (c) 2011-2022 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/
|
|
/* Copyright (c) 2014-2019 Mihai Moldovan <ionic@ionic.de> */
|
|
/* Copyright (c) 2014-2022 Ulrich Sibiller <uli42@gmx.de> */
|
|
/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */
|
|
/* */
|
|
/* NXAGENT, NX protocol compression and NX extensions to this software */
|
|
/* are copyright of the aforementioned persons and companies. */
|
|
/* */
|
|
/* Redistribution and use of the present software is allowed according */
|
|
/* to terms specified in the file LICENSE which comes in the source */
|
|
/* distribution. */
|
|
/* */
|
|
/* All rights reserved. */
|
|
/* */
|
|
/* NOTE: This software has received contributions from various other */
|
|
/* contributors, only the core maintainers and supporters are listed as */
|
|
/* copyright holders. Please contact us, if you feel you should be listed */
|
|
/* as copyright holder, as well. */
|
|
/* */
|
|
/**************************************************************************/
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <signal.h>
|
|
#include <errno.h>
|
|
#include <sys/types.h>
|
|
#include <sys/wait.h>
|
|
|
|
#include "scrnintstr.h"
|
|
#include "Agent.h"
|
|
|
|
#include <nx-X11/Xlib.h>
|
|
|
|
#include "opaque.h"
|
|
|
|
#include "Args.h"
|
|
#include "Display.h"
|
|
#include "Dialog.h"
|
|
#include "Utils.h"
|
|
#include "Keystroke.h"
|
|
|
|
#include <nx/NX.h>
|
|
#include "compext/Compext.h"
|
|
#include <nx/NXalert.h>
|
|
|
|
/*
|
|
* Set here the required log level.
|
|
*/
|
|
|
|
#define PANIC
|
|
#define WARNING
|
|
#undef TEST
|
|
#undef DEBUG
|
|
|
|
int nxagentKillDialogPid = 0;
|
|
int nxagentSuspendDialogPid = 0;
|
|
int nxagentRootlessDialogPid = 0;
|
|
int nxagentPulldownDialogPid = 0;
|
|
int nxagentFontsReplacementDialogPid = 0;
|
|
int nxagentEnableRandRModeDialogPid = 0;
|
|
int nxagentDisableRandRModeDialogPid = 0;
|
|
int nxagentEnableDeferModePid = 0;
|
|
int nxagentDisableDeferModePid = 0;
|
|
int nxagentEnableAutograbModePid = 0;
|
|
int nxagentDisableAutograbModePid = 0;
|
|
|
|
static int nxagentFailedReconnectionDialogPid = 0;
|
|
|
|
char nxagentPulldownWindow[NXAGENTPULLDOWNWINDOWLENGTH];
|
|
|
|
char nxagentFailedReconnectionMessage[NXAGENTFAILEDRECONNECTIONMESSAGELENGTH];
|
|
|
|
void nxagentResetDialog(int pid)
|
|
{
|
|
if (pid == nxagentRootlessDialogPid)
|
|
{
|
|
#ifdef TEST
|
|
fprintf(stderr, "nxagentResetDialog: Resetting rootless dialog pid [%d].\n", nxagentRootlessDialogPid);
|
|
#endif
|
|
|
|
nxagentRootlessDialogPid = 0;
|
|
}
|
|
else if (pid == nxagentPulldownDialogPid)
|
|
{
|
|
#ifdef TEST
|
|
fprintf(stderr, "nxagentResetDialog: Resetting pulldown dialog pid [%d].\n", nxagentPulldownDialogPid);
|
|
#endif
|
|
|
|
nxagentPulldownDialogPid = 0;
|
|
}
|
|
else if (pid == nxagentFontsReplacementDialogPid)
|
|
{
|
|
#ifdef TEST
|
|
fprintf(stderr, "nxagentResetDialog: Resetting fonts replacement dialog pid [%d].\n",
|
|
nxagentFontsReplacementDialogPid);
|
|
#endif
|
|
|
|
nxagentFontsReplacementDialogPid = 0;
|
|
}
|
|
else if (pid == nxagentKillDialogPid)
|
|
{
|
|
#ifdef TEST
|
|
fprintf(stderr, "nxagentResetDialog: Resetting kill dialog pid [%d].\n", nxagentKillDialogPid);
|
|
#endif
|
|
|
|
nxagentKillDialogPid = 0;
|
|
}
|
|
else if (pid == nxagentSuspendDialogPid)
|
|
{
|
|
#ifdef TEST
|
|
fprintf(stderr, "nxagentResetDialog: Resetting suspend dialog pid [%d].\n", nxagentSuspendDialogPid);
|
|
#endif
|
|
|
|
nxagentSuspendDialogPid = 0;
|
|
}
|
|
else if (pid == nxagentFailedReconnectionDialogPid)
|
|
{
|
|
#ifdef TEST
|
|
fprintf(stderr, "nxagentResetDialog: Resetting Failed Reconnection dialog pid [%d].\n",
|
|
nxagentFailedReconnectionDialogPid);
|
|
#endif
|
|
|
|
nxagentFailedReconnectionDialogPid = 0;
|
|
}
|
|
else if (pid == nxagentEnableRandRModeDialogPid)
|
|
{
|
|
#ifdef TEST
|
|
fprintf(stderr, "nxagentResetDialog: Resetting RandR mode dialog pid [%d].\n",
|
|
nxagentEnableRandRModeDialogPid);
|
|
#endif
|
|
|
|
nxagentEnableRandRModeDialogPid = 0;
|
|
}
|
|
else if (pid == nxagentDisableRandRModeDialogPid)
|
|
{
|
|
#ifdef TEST
|
|
fprintf(stderr, "nxagentResetDialog: Resetting NoRandR mode dialog pid [%d].\n",
|
|
nxagentDisableRandRModeDialogPid);
|
|
#endif
|
|
|
|
nxagentDisableRandRModeDialogPid = 0;
|
|
}
|
|
else if (pid == nxagentEnableDeferModePid)
|
|
{
|
|
#ifdef TEST
|
|
fprintf(stderr, "nxagentResetDialog: Resetting enable defer mode dialog pid [%d].\n",
|
|
nxagentEnableDeferModePid);
|
|
#endif
|
|
|
|
nxagentEnableDeferModePid = 0;
|
|
}
|
|
else if (pid == nxagentDisableDeferModePid)
|
|
{
|
|
#ifdef TEST
|
|
fprintf(stderr, "nxagentResetDialog: Resetting disable defer mode dialog pid [%d].\n",
|
|
nxagentDisableDeferModePid);
|
|
#endif
|
|
|
|
nxagentDisableDeferModePid = 0;
|
|
}
|
|
else if (pid == nxagentEnableAutograbModePid)
|
|
{
|
|
#ifdef TEST
|
|
fprintf(stderr, "nxagentResetDialog: Resetting enable autograb mode dialog pid [%d].\n",
|
|
nxagentEnableAutograbModePid);
|
|
#endif
|
|
|
|
nxagentEnableAutograbModePid = 0;
|
|
}
|
|
else if (pid == nxagentDisableAutograbModePid)
|
|
{
|
|
#ifdef TEST
|
|
fprintf(stderr, "nxagentResetDialog: Resetting disable autograb mode dialog pid [%d].\n",
|
|
nxagentDisableAutograbModePid);
|
|
#endif
|
|
|
|
nxagentDisableAutograbModePid = 0;
|
|
}
|
|
}
|
|
|
|
void nxagentLaunchDialog(DialogType dialogType)
|
|
{
|
|
sigset_t set, oldSet;
|
|
int *pid;
|
|
char *type;
|
|
char *message;
|
|
char *strings[2] = {NULL}; /* don't forget to add free() calls if you change the number */
|
|
int local;
|
|
const char *window = NULL;
|
|
|
|
switch (dialogType)
|
|
{
|
|
case DIALOG_KILL_SESSION:
|
|
{
|
|
message = DIALOG_KILL_SESSION_MESSAGE;
|
|
type = DIALOG_KILL_SESSION_TYPE;
|
|
local = DIALOG_KILL_SESSION_LOCAL;
|
|
pid = &nxagentKillDialogPid;
|
|
break;
|
|
}
|
|
case DIALOG_SUSPEND_SESSION:
|
|
{
|
|
message = DIALOG_SUSPEND_SESSION_MESSAGE;
|
|
type = DIALOG_SUSPEND_SESSION_TYPE;
|
|
local = DIALOG_SUSPEND_SESSION_LOCAL;
|
|
pid = &nxagentSuspendDialogPid;
|
|
break;
|
|
}
|
|
case DIALOG_ROOTLESS:
|
|
{
|
|
message = DIALOG_ROOTLESS_MESSAGE;
|
|
type = DIALOG_ROOTLESS_TYPE;
|
|
local = DIALOG_ROOTLESS_LOCAL;
|
|
pid = &nxagentRootlessDialogPid;
|
|
break;
|
|
}
|
|
case DIALOG_PULLDOWN:
|
|
{
|
|
message = DIALOG_PULLDOWN_MESSAGE;
|
|
type = DIALOG_PULLDOWN_TYPE;
|
|
local = DIALOG_PULLDOWN_LOCAL;
|
|
pid = &nxagentPulldownDialogPid;
|
|
window = nxagentPulldownWindow;
|
|
break;
|
|
}
|
|
case DIALOG_FONT_REPLACEMENT:
|
|
{
|
|
message = DIALOG_FONT_REPLACEMENT_MESSAGE;
|
|
type = DIALOG_FONT_REPLACEMENT_TYPE;
|
|
local = DIALOG_FONT_REPLACEMENT_LOCAL;
|
|
pid = &nxagentFontsReplacementDialogPid;
|
|
break;
|
|
}
|
|
case DIALOG_FAILED_RECONNECTION:
|
|
{
|
|
message = DIALOG_FAILED_RECONNECTION_MESSAGE;
|
|
type = DIALOG_FAILED_RECONNECTION_TYPE;
|
|
local = DIALOG_FAILED_RECONNECTION_LOCAL;
|
|
pid = &nxagentFailedReconnectionDialogPid;
|
|
break;
|
|
}
|
|
case DIALOG_ENABLE_DESKTOP_RESIZE_MODE:
|
|
{
|
|
message = DIALOG_ENABLE_DESKTOP_RESIZE_MODE_MESSAGE;
|
|
type = DIALOG_ENABLE_DESKTOP_RESIZE_MODE_TYPE;
|
|
local = DIALOG_ENABLE_DESKTOP_RESIZE_MODE_LOCAL;
|
|
pid = &nxagentEnableRandRModeDialogPid;
|
|
strings[0] = nxagentFindFirstKeystroke("resize");
|
|
break;
|
|
}
|
|
case DIALOG_DISABLE_DESKTOP_RESIZE_MODE:
|
|
{
|
|
message = DIALOG_DISABLE_DESKTOP_RESIZE_MODE_MESSAGE;
|
|
type = DIALOG_DISABLE_DESKTOP_RESIZE_MODE_TYPE;
|
|
local = DIALOG_DISABLE_DESKTOP_RESIZE_MODE_LOCAL;
|
|
pid = &nxagentDisableRandRModeDialogPid;
|
|
strings[0] = nxagentFindFirstKeystroke("resize");
|
|
strings[1] = nxagentFindMatchingKeystrokes("viewport_");
|
|
break;
|
|
}
|
|
case DIALOG_ENABLE_DEFER_MODE:
|
|
{
|
|
message = DIALOG_ENABLE_DEFER_MODE_MESSAGE;
|
|
type = DIALOG_ENABLE_DEFER_MODE_TYPE;
|
|
local = DIALOG_ENABLE_DEFER_MODE_LOCAL;
|
|
pid = &nxagentEnableDeferModePid;
|
|
strings[0] = nxagentFindFirstKeystroke("defer");
|
|
break;
|
|
}
|
|
case DIALOG_DISABLE_DEFER_MODE:
|
|
{
|
|
message = DIALOG_DISABLE_DEFER_MODE_MESSAGE;
|
|
type = DIALOG_DISABLE_DEFER_MODE_TYPE;
|
|
local = DIALOG_DISABLE_DEFER_MODE_LOCAL;
|
|
pid = &nxagentDisableDeferModePid;
|
|
strings[0] = nxagentFindFirstKeystroke("defer");
|
|
break;
|
|
}
|
|
case DIALOG_ENABLE_AUTOGRAB_MODE:
|
|
{
|
|
message = DIALOG_ENABLE_AUTOGRAB_MODE_MESSAGE;
|
|
type = DIALOG_ENABLE_AUTOGRAB_MODE_TYPE;
|
|
local = DIALOG_ENABLE_AUTOGRAB_MODE_LOCAL;
|
|
pid = &nxagentEnableAutograbModePid;
|
|
strings[0] = nxagentFindFirstKeystroke("autograb");
|
|
break;
|
|
}
|
|
case DIALOG_DISABLE_AUTOGRAB_MODE:
|
|
{
|
|
message = DIALOG_DISABLE_AUTOGRAB_MODE_MESSAGE;
|
|
type = DIALOG_DISABLE_AUTOGRAB_MODE_TYPE;
|
|
local = DIALOG_DISABLE_AUTOGRAB_MODE_LOCAL;
|
|
pid = &nxagentDisableAutograbModePid;
|
|
strings[0] = nxagentFindFirstKeystroke("autograb");
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
#ifdef WARNING
|
|
fprintf(stderr, "nxagentLaunchDialog: Unknown Dialog type [%d].\n", dialogType);
|
|
#endif
|
|
return;
|
|
}
|
|
}
|
|
|
|
#ifdef TEST
|
|
fprintf(stderr, "nxagentLaunchDialog: Launching dialog type [%d] message [%s].\n", type, message);
|
|
#endif
|
|
|
|
char *dialogDisplay = NULL;
|
|
int len = 0;
|
|
if (dialogType == DIALOG_FAILED_RECONNECTION)
|
|
{
|
|
len = asprintf(&dialogDisplay, "%s", nxagentDisplayName);
|
|
}
|
|
else
|
|
{
|
|
len = asprintf(&dialogDisplay, ":%s", display);
|
|
}
|
|
|
|
if (len == -1)
|
|
{
|
|
#ifdef DEBUG
|
|
fprintf(stderr, "%s: could not allocate display string.\n", __func__);
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
char *msg = NULL;
|
|
if (-1 == asprintf(&msg, message, strings[0], strings[1]))
|
|
{
|
|
#ifdef DEBUG
|
|
fprintf(stderr, "%s: could not allocate message string.\n", __func__);
|
|
#endif
|
|
SAFE_free(strings[0]);
|
|
SAFE_free(strings[1]);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* We don't want to receive SIGCHLD before we store the child pid.
|
|
*/
|
|
|
|
sigemptyset(&set);
|
|
|
|
sigaddset(&set, SIGCHLD);
|
|
|
|
sigprocmask(SIG_BLOCK, &set, &oldSet);
|
|
|
|
*pid = NXTransDialog(nxagentDialogName, msg, window,
|
|
type, local, dialogDisplay);
|
|
|
|
SAFE_free(strings[0]);
|
|
SAFE_free(strings[1]);
|
|
SAFE_free(msg);
|
|
|
|
#ifdef TEST
|
|
fprintf(stderr, "nxagentLaunchDialog: Launched dialog %s with pid [%d] on display %s.\n",
|
|
DECODE_DIALOG_TYPE(dialogType), *pid, dialogDisplay);
|
|
#endif
|
|
|
|
SAFE_free(dialogDisplay);
|
|
|
|
/*
|
|
* Restore the previous set of blocked signal.
|
|
*/
|
|
|
|
sigprocmask(SIG_SETMASK, &oldSet, NULL);
|
|
}
|
|
|
|
void nxagentPulldownDialog(Window wid)
|
|
{
|
|
snprintf(nxagentPulldownWindow, NXAGENTPULLDOWNWINDOWLENGTH, "%ld", (long int) wid);
|
|
|
|
#ifdef TEST
|
|
fprintf(stderr, "nxagentPulldownDialog: Going to launch pulldown "
|
|
"dialog on window [%s].\n", nxagentPulldownWindow);
|
|
#endif
|
|
|
|
nxagentLaunchDialog(DIALOG_PULLDOWN);
|
|
|
|
nxagentPulldownWindow[0] = '\0';
|
|
}
|
|
|
|
void nxagentFailedReconnectionDialog(int alert, char *error)
|
|
{
|
|
if (alert == 0)
|
|
{
|
|
#ifdef WARNING
|
|
fprintf(stderr, "nxagentFailedReconnectionDialog: WARNING! No valid alert provided. "
|
|
"Using the default.\n");
|
|
#endif
|
|
|
|
alert = FAILED_RESUME_DISPLAY_ALERT;
|
|
}
|
|
|
|
if (NXDisplayError(nxagentDisplay) == 0 &&
|
|
NXTransRunning(NX_FD_ANY) == 1)
|
|
{
|
|
NXTransAlert(alert, NX_ALERT_REMOTE);
|
|
|
|
/*
|
|
* Make it possible to interrupt the loop with a signal.
|
|
*/
|
|
|
|
while (NXDisplayError(nxagentDisplay) == 0 &&
|
|
NXTransRunning(NX_FD_ANY) == 1)
|
|
{
|
|
struct timeval timeout = {
|
|
.tv_sec = 30,
|
|
.tv_usec = 0,
|
|
};
|
|
|
|
NXTransContinue(&timeout);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int pid;
|
|
int status;
|
|
int options = 0;
|
|
|
|
snprintf(nxagentFailedReconnectionMessage, NXAGENTFAILEDRECONNECTIONMESSAGELENGTH, "Reconnection failed: %s", error);
|
|
|
|
nxagentLaunchDialog(DIALOG_FAILED_RECONNECTION);
|
|
|
|
while ((pid = waitpid(nxagentFailedReconnectionDialogPid, &status, options)) == -1 &&
|
|
errno == EINTR);
|
|
|
|
if (pid == -1)
|
|
{
|
|
if (errno == ECHILD)
|
|
{
|
|
#ifdef WARNING
|
|
fprintf(stderr, "nxagentFailedReconnectionDialog: Got ECHILD waiting for child [%d].\n",
|
|
nxagentFailedReconnectionDialogPid);
|
|
#endif
|
|
|
|
nxagentFailedReconnectionDialogPid = 0;
|
|
}
|
|
else
|
|
{
|
|
fprintf(stderr, "nxagentFailedReconnectionDialog: PANIC! Got unexpected error [%s] waiting "
|
|
"for child [%d].\n", strerror(errno), nxagentFailedReconnectionDialogPid);
|
|
}
|
|
}
|
|
else if (pid > 0)
|
|
{
|
|
if (WIFSTOPPED(status))
|
|
{
|
|
#ifdef WARNING
|
|
fprintf(stderr, "nxagentFailedReconnectionDialog: Child process [%d] was stopped "
|
|
"with signal [%d].\n", pid, (WSTOPSIG(status)));
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
#ifdef WARNING
|
|
|
|
if (WIFEXITED(status))
|
|
{
|
|
fprintf(stderr, "nxagentFailedReconnectionDialog: Child process [%d] exited "
|
|
"with status [%d].\n", pid, (WEXITSTATUS(status)));
|
|
}
|
|
else if (WIFSIGNALED(status))
|
|
{
|
|
fprintf(stderr, "nxagentFailedReconnectionDialog: Child process [%d] died "
|
|
"because of signal [%d].\n", pid, (WTERMSIG(status)));
|
|
}
|
|
|
|
#endif
|
|
|
|
nxagentResetDialog(pid);
|
|
}
|
|
}
|
|
#ifdef WARNING
|
|
else if (pid == 0)
|
|
{
|
|
fprintf(stderr, "nxagentFailedReconnectionDialog: No own child process exited.\n");
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void nxagentTerminateDialog(DialogType type)
|
|
{
|
|
int pid;
|
|
|
|
switch (type)
|
|
{
|
|
case DIALOG_KILL_SESSION:
|
|
{
|
|
pid = nxagentKillDialogPid;
|
|
break;
|
|
}
|
|
case DIALOG_SUSPEND_SESSION:
|
|
{
|
|
pid = nxagentSuspendDialogPid;
|
|
break;
|
|
}
|
|
case DIALOG_ROOTLESS:
|
|
{
|
|
pid = nxagentRootlessDialogPid;
|
|
break;
|
|
}
|
|
case DIALOG_PULLDOWN:
|
|
{
|
|
pid = nxagentPulldownDialogPid;
|
|
break;
|
|
}
|
|
case DIALOG_FONT_REPLACEMENT:
|
|
{
|
|
pid = nxagentFontsReplacementDialogPid;
|
|
break;
|
|
}
|
|
case DIALOG_FAILED_RECONNECTION:
|
|
{
|
|
pid = nxagentFailedReconnectionDialogPid;
|
|
break;
|
|
}
|
|
case DIALOG_ENABLE_DESKTOP_RESIZE_MODE:
|
|
{
|
|
pid = nxagentEnableRandRModeDialogPid;
|
|
break;
|
|
}
|
|
case DIALOG_DISABLE_DESKTOP_RESIZE_MODE:
|
|
{
|
|
pid = nxagentDisableRandRModeDialogPid;
|
|
break;
|
|
}
|
|
case DIALOG_ENABLE_DEFER_MODE:
|
|
{
|
|
pid = nxagentEnableDeferModePid;
|
|
break;
|
|
}
|
|
case DIALOG_DISABLE_DEFER_MODE:
|
|
{
|
|
pid = nxagentDisableDeferModePid;
|
|
break;
|
|
}
|
|
case DIALOG_ENABLE_AUTOGRAB_MODE:
|
|
{
|
|
pid = nxagentEnableAutograbModePid;
|
|
break;
|
|
}
|
|
case DIALOG_DISABLE_AUTOGRAB_MODE:
|
|
{
|
|
pid = nxagentDisableAutograbModePid;
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
#ifdef WARNING
|
|
fprintf(stderr, "nxagentTerminateDialog: Unknown dialog type [%d].\n", type);
|
|
#endif
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (pid > 0)
|
|
{
|
|
if (kill(pid, SIGTERM) == -1)
|
|
{
|
|
#ifdef WARNING
|
|
fprintf(stderr, "nxagentTerminateDialog: Failed to terminate dialog pid [%d]: %s.\n",
|
|
pid, strerror(errno));
|
|
#endif
|
|
}
|
|
}
|
|
#ifdef DEBUG
|
|
else
|
|
{
|
|
fprintf(stderr, "nxagentTerminateDialog: Dialog type [%d] is not running.\n",
|
|
type);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void nxagentTerminateDialogs(void)
|
|
{
|
|
#ifdef DEBUG
|
|
fprintf(stderr, "nxagentTerminateDialogs: Terminating all the running dialogs.\n");
|
|
#endif
|
|
|
|
for (DialogType type = DIALOG_FIRST_TAG; type < DIALOG_LAST_TAG; type++)
|
|
{
|
|
nxagentTerminateDialog(type);
|
|
}
|
|
}
|