/**************************************************************************/ /* */ /* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */ /* Copyright (c) 2008-2014 Oleksandr Shneyder */ /* Copyright (c) 2011-2016 Mike Gabriel */ /* Copyright (c) 2014-2016 Mihai Moldovan */ /* Copyright (c) 2014-2016 Ulrich Sibiller */ /* 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 #include #include #include #include #include #include "scrnintstr.h" #include "Agent.h" #include #include "opaque.h" #include "Args.h" #include "Display.h" #include "Dialog.h" #include #include "compext/Compext.h" #include /* * 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) { char dialogDisplay[256]; sigset_t set, oldSet; int *pid; char *type; char *message; 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; 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; 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; 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; 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; 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; 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 if (dialogType == DIALOG_FAILED_RECONNECTION) { snprintf(dialogDisplay, sizeof(dialogDisplay), "%s", nxagentDisplayName); } else { snprintf(dialogDisplay, sizeof(dialogDisplay), ":%s", display); } /* * 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, message, window, type, local, dialogDisplay); #ifdef TEST fprintf(stderr, "nxagentLaunchDialog: Launched dialog %s with pid [%d] on display %s.\n", DECODE_DIALOG_TYPE(dialogType), *pid, dialogDisplay); #endif dialogDisplay[0] = '\0'; /* * 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; timeout.tv_sec = 30; timeout.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) { DialogType type; #ifdef DEBUG fprintf(stderr, "nxagentTerminateDialogs: Terminating all the running dialogs.\n"); #endif for (type = DIALOG_FIRST_TAG; type < DIALOG_LAST_TAG; type++) { nxagentTerminateDialog(type); } }