1492 lines
35 KiB
C
1492 lines
35 KiB
C
/*
|
|
* CDE - Common Desktop Environment
|
|
*
|
|
* Copyright (c) 1993-2012, The Open Group. All rights reserved.
|
|
*
|
|
* These libraries and programs are free software; you can
|
|
* redistribute them and/or modify them under the terms of the GNU
|
|
* Lesser General Public License as published by the Free Software
|
|
* Foundation; either version 2 of the License, or (at your option)
|
|
* any later version.
|
|
*
|
|
* These libraries and programs are distributed in the hope that
|
|
* they will be useful, but WITHOUT ANY WARRANTY; without even the
|
|
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
* PURPOSE. See the GNU Lesser General Public License for more
|
|
* details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with these libraries and programs; if not, write
|
|
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
|
|
* Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
/*
|
|
* (c) Copyright 1995 Digital Equipment Corporation.
|
|
* (c) Copyright 1993, 1994, 1995 Hewlett-Packard Company
|
|
* (c) Copyright 1993, 1994, 1995 International Business Machines Corp.
|
|
* (c) Copyright 1993, 1994, 1995 Sun Microsystems, Inc.
|
|
* (c) Copyright 1993, 1994, 1995 Novell, Inc.
|
|
* (c) Copyright 1995 FUJITSU LIMITED.
|
|
* (c) Copyright 1995 Hitachi.
|
|
*
|
|
* $TOG: SmXSMP.c /main/40 1999/01/18 15:42:07 samborn $
|
|
*/
|
|
|
|
/*************************************<+>*************************************
|
|
*****************************************************************************
|
|
**
|
|
** File: SmXSMP.c
|
|
**
|
|
** Project: DT Session Manager (dtsession)
|
|
**
|
|
*****************************************************************************
|
|
*************************************<+>*************************************/
|
|
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
|
|
#include "SmXSMP.h"
|
|
#include "SmAuth.h"
|
|
#include "SmWatch.h"
|
|
#include "SmProp.h"
|
|
#include "Sm.h"
|
|
#include "SmUI.h"
|
|
#include "SmSave.h"
|
|
#include "SmRestore.h"
|
|
#include "SmGlobals.h"
|
|
|
|
#include <X11/Xlib.h>
|
|
#include <X11/Intrinsic.h>
|
|
#include <X11/Xatom.h>
|
|
#include <X11/SM/SMlib.h>
|
|
|
|
#include <Dt/MsgLog.h>
|
|
#include <Dt/Lock.h>
|
|
#include <Dt/Wsm.h>
|
|
|
|
#include <Tt/tt_c.h>
|
|
|
|
/*
|
|
* Private constants
|
|
*/
|
|
#define ERRORMSGLEN 256
|
|
#define GET_CLIENT_WORKSPACE_MSG "GetWsmClients"
|
|
|
|
|
|
/*
|
|
* Private variables
|
|
*/
|
|
static Boolean authenticationInitialized = False;
|
|
static char * networkIds;
|
|
|
|
/*
|
|
* Private functions
|
|
*/
|
|
static void InitializeXSMPGlobals ();
|
|
|
|
static void PutSessionManagerOnRootWindow (
|
|
char *networkIds);
|
|
|
|
static void InitializeSaveState (
|
|
Boolean startUp);
|
|
|
|
static Boolean SendGetWsmClientsMessage ();
|
|
|
|
static int GetCurrentWorkspaceNumber ();
|
|
|
|
static void ProcessInteract (
|
|
ClientRecPtr client,
|
|
Boolean getWsmClientOK);
|
|
|
|
static void CancelShutdown ();
|
|
|
|
static void FreeProps (
|
|
PropertyRecPtr pProp);
|
|
|
|
static void ProcessSaveYourselfResponses ();
|
|
|
|
|
|
/*
|
|
* Public variables
|
|
*/
|
|
XSMPSettings smXSMP;
|
|
ClientRecPtr connectedList;
|
|
Atom XaSmClientId;
|
|
|
|
|
|
/*
|
|
* Public functins
|
|
*/
|
|
void InstallIOErrorHandler ();
|
|
|
|
Status NewClientProc (
|
|
SmsConn smsConn,
|
|
SmPointer managerData,
|
|
unsigned long *maskRet,
|
|
SmsCallbacks *callbacksRet,
|
|
char **failureReasonRet);
|
|
|
|
void NewConnectionXtProc (
|
|
XtPointer client_data,
|
|
int *source,
|
|
XtInputId *id);
|
|
|
|
Status RegisterClientProc (
|
|
SmsConn smsConn,
|
|
SmPointer managerData,
|
|
char *previousId);
|
|
|
|
void InteractRequestProc (
|
|
SmsConn smsConn,
|
|
SmPointer managerData,
|
|
int dialogType);
|
|
|
|
void InteractDoneProc (
|
|
SmsConn smsConn,
|
|
SmPointer managerData,
|
|
Bool cancelShutdown);
|
|
|
|
void SaveYourselfReqProc (
|
|
SmsConn smsConn,
|
|
SmPointer managerData,
|
|
int saveType,
|
|
Bool shutdown,
|
|
int interactStyle,
|
|
Bool fast,
|
|
Bool global);
|
|
|
|
void SaveYourselfPhase2ReqProc (
|
|
SmsConn smsConn,
|
|
SmPointer managerData);
|
|
|
|
void SaveYourselfDoneProc (
|
|
SmsConn smsConn,
|
|
SmPointer managerData,
|
|
Bool success);
|
|
|
|
void CloseConnectionProc (
|
|
SmsConn smsConn,
|
|
SmPointer managerData,
|
|
int count,
|
|
char **reasonMsgs);
|
|
|
|
void CompleteXSMPSave ();
|
|
|
|
void CloseDownClient (
|
|
ClientRecPtr client );
|
|
|
|
/*
|
|
* List manipulation functions
|
|
*/
|
|
void AddClient (
|
|
ClientRecPtr newClient);
|
|
|
|
/*
|
|
* Functions
|
|
*/
|
|
|
|
Boolean InitXSMP (void)
|
|
{
|
|
char errorMsg[ERRORMSGLEN];
|
|
char *env;
|
|
int i;
|
|
|
|
InitializeXSMPGlobals ();
|
|
|
|
InstallIOErrorHandler ();
|
|
|
|
if (!SmsInitialize (SM_VENDOR_NAME, SM_RELEASE_NAME,
|
|
NewClientProc, NULL,
|
|
HostBasedAuthProc,
|
|
ERRORMSGLEN, errorMsg)) {
|
|
DtMsgLogMessage (smGD.programName, DtMsgLogError, errorMsg);
|
|
PostXSMPFailureDialog (XSMP_FAILURE_SMS_INITIALIZE, True);
|
|
}
|
|
|
|
if (!IceListenForConnections (&smXSMP.numTransports,
|
|
&smXSMP.listenObjs,
|
|
ERRORMSGLEN, errorMsg)) {
|
|
DtMsgLogMessage (smGD.programName, DtMsgLogError, errorMsg);
|
|
PostXSMPFailureDialog (XSMP_FAILURE_ICE_LISTEN, True);
|
|
}
|
|
|
|
if (!SetAuthentication (smXSMP.numTransports,
|
|
smXSMP.listenObjs,
|
|
&smXSMP.authDataEntries))
|
|
PostXSMPFailureDialog (XSMP_FAILURE_AUTHENTICATION, False);
|
|
|
|
authenticationInitialized = True;
|
|
|
|
if (!InitWatchProcs (smGD.appCon))
|
|
PostXSMPFailureDialog (XSMP_FAILURE_ICE_ADD_WATCH, False);
|
|
|
|
for (i = 0; i < smXSMP.numTransports; i++) {
|
|
XtAppAddInput (smGD.appCon,
|
|
IceGetListenConnectionNumber (smXSMP.listenObjs[i]),
|
|
(XtPointer) XtInputReadMask,
|
|
NewConnectionXtProc, (XtPointer) smXSMP.listenObjs[i]);
|
|
}
|
|
|
|
networkIds = IceComposeNetworkIdList (smXSMP.numTransports,
|
|
smXSMP.listenObjs);
|
|
if (!networkIds)
|
|
PostXSMPFailureDialog (XSMP_FAILURE_ICE_COMPOSE_IDS, False);
|
|
|
|
env = (char *) XtMalloc (strlen (SM_SESSION_MANAGER) +
|
|
strlen (networkIds) + 2);
|
|
if (!env) {
|
|
free (networkIds);
|
|
PostXSMPFailureDialog (XSMP_FAILURE_MALLOC, False);
|
|
} else {
|
|
(void) sprintf (env, "%s=%s", SM_SESSION_MANAGER, networkIds);
|
|
(void) putenv (env);
|
|
}
|
|
|
|
PutSessionManagerOnRootWindow (networkIds);
|
|
|
|
XaSmClientId = XInternAtom(smGD.display, SM_CLIENT_ID, False);
|
|
|
|
#ifdef DEBUG
|
|
printf ("%s\n", env);
|
|
#endif /* DEBUG */
|
|
|
|
return (True);
|
|
}
|
|
|
|
|
|
static void
|
|
PutSessionManagerOnRootWindow (
|
|
char *networkIds)
|
|
{
|
|
Atom sessionManager;
|
|
|
|
sessionManager = XInternAtom(smGD.display, SM_SESSION_MANAGER, False);
|
|
|
|
XChangeProperty(smGD.display, RootWindow(smGD.display, 0),
|
|
sessionManager, XA_STRING, 8, PropModeReplace,
|
|
(unsigned char *) networkIds, strlen((char *)networkIds));
|
|
}
|
|
|
|
|
|
static void
|
|
InitializeSaveState (
|
|
Boolean startUp)
|
|
{
|
|
smXSMP.saveState.global = False;
|
|
smXSMP.saveState.shutdown = False;
|
|
smXSMP.saveState.interactStyle = SmInteractStyleAny;
|
|
smXSMP.saveState.clientInteracting = False;
|
|
smXSMP.saveState.inProgress = False;
|
|
smXSMP.saveState.doneSuccess = True;
|
|
smXSMP.saveState.saveComplete = False;
|
|
smXSMP.saveState.interactCount = 0;
|
|
smXSMP.saveState.numClientIds = 0;
|
|
smXSMP.saveState.interactClient = NULL;
|
|
if (startUp) {
|
|
smXSMP.saveState.clientIds = NULL;
|
|
smXSMP.saveState.workspaceNums = NULL;
|
|
} else {
|
|
if (smXSMP.saveState.clientIds) {
|
|
free (smXSMP.saveState.clientIds);
|
|
smXSMP.saveState.clientIds = NULL;
|
|
}
|
|
if (smXSMP.saveState.workspaceNums) {
|
|
free (smXSMP.saveState.workspaceNums);
|
|
smXSMP.saveState.workspaceNums = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
InitializeXSMPGlobals (void)
|
|
{
|
|
smXSMP.authDataEntries = NULL;
|
|
|
|
connectedList = NULL;
|
|
|
|
smXSMP.xsmpDbList = NULL;
|
|
|
|
smXSMP.dbVersion = SM_VENDOR_NAME;
|
|
|
|
smXSMP.dbSessionId = SM_RELEASE_NAME;
|
|
|
|
InitializeSaveState (True);
|
|
}
|
|
|
|
|
|
/*ARGSUSED*/
|
|
Status
|
|
NewClientProc (
|
|
SmsConn smsConn,
|
|
SmPointer managerData,
|
|
unsigned long *maskRet,
|
|
SmsCallbacks *callbacksRet,
|
|
char **failureReasonRet)
|
|
{
|
|
ClientRecPtr newClient;
|
|
|
|
#ifdef DEBUG
|
|
(void) printf ("\nNewClientProc: IceConn fd = %d\n",
|
|
IceConnectionNumber (SmsGetIceConnection (smsConn)));
|
|
#endif /* DEBUG */
|
|
|
|
newClient = (ClientRecPtr) XtMalloc (sizeof (ClientRec));
|
|
if (!newClient) {
|
|
char *str;
|
|
|
|
str = strdup ((char *) GETMESSAGE (4, 5,
|
|
"Unable to malloc memory for operation."));
|
|
if (str) {
|
|
if ((*failureReasonRet = (char *)
|
|
XtMalloc ( strlen (str) + 1)) != NULL)
|
|
strcpy (*failureReasonRet, str);
|
|
|
|
DtMsgLogMessage (smGD.programName, DtMsgLogError, str);
|
|
free (str);
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
*maskRet = 0;
|
|
|
|
newClient->smConn = smsConn;
|
|
newClient->iceConn = SmsGetIceConnection (smsConn);
|
|
newClient->clientId = NULL;
|
|
newClient->clientHost = NULL;
|
|
newClient->screenNum = 0;
|
|
newClient->restartHint = SmRestartIfRunning;
|
|
newClient->props = NULL;
|
|
newClient->active = False;
|
|
newClient->saveYourselfDone = False;
|
|
newClient->saveYourselfP2Requested = False;
|
|
newClient->interactRequested = False;
|
|
newClient->next = NULL;
|
|
|
|
AddClient (newClient);
|
|
|
|
*maskRet |= SmsRegisterClientProcMask;
|
|
callbacksRet->register_client.callback = RegisterClientProc;
|
|
callbacksRet->register_client.manager_data = (SmPointer) newClient;
|
|
|
|
*maskRet |= SmsInteractRequestProcMask;
|
|
callbacksRet->interact_request.callback = InteractRequestProc;
|
|
callbacksRet->interact_request.manager_data = (SmPointer) newClient;
|
|
|
|
*maskRet |= SmsInteractDoneProcMask;
|
|
callbacksRet->interact_done.callback = InteractDoneProc;
|
|
callbacksRet->interact_done.manager_data = (SmPointer) newClient;
|
|
|
|
*maskRet |= SmsSaveYourselfRequestProcMask;
|
|
callbacksRet->save_yourself_request.callback = SaveYourselfReqProc;
|
|
callbacksRet->save_yourself_request.manager_data =
|
|
(SmPointer) newClient;
|
|
|
|
*maskRet |= SmsSaveYourselfP2RequestProcMask;
|
|
callbacksRet->save_yourself_phase2_request.callback =
|
|
SaveYourselfPhase2ReqProc;
|
|
callbacksRet->save_yourself_phase2_request.manager_data =
|
|
(SmPointer) newClient;
|
|
|
|
*maskRet |= SmsSaveYourselfDoneProcMask;
|
|
callbacksRet->save_yourself_done.callback = SaveYourselfDoneProc;
|
|
callbacksRet->save_yourself_done.manager_data = (SmPointer) newClient;
|
|
|
|
*maskRet |= SmsCloseConnectionProcMask;
|
|
callbacksRet->close_connection.callback = CloseConnectionProc;
|
|
callbacksRet->close_connection.manager_data = (SmPointer) newClient;
|
|
|
|
*maskRet |= SmsSetPropertiesProcMask;
|
|
callbacksRet->set_properties.callback = SetPropertiesProc;
|
|
callbacksRet->set_properties.manager_data = (SmPointer) newClient;
|
|
|
|
*maskRet |= SmsDeletePropertiesProcMask;
|
|
callbacksRet->delete_properties.callback = DeletePropertiesProc;
|
|
callbacksRet->delete_properties.manager_data = (SmPointer) newClient;
|
|
|
|
*maskRet |= SmsGetPropertiesProcMask;
|
|
callbacksRet->get_properties.callback = GetPropertiesProc;
|
|
callbacksRet->get_properties.manager_data = (SmPointer) newClient;
|
|
|
|
return (True);
|
|
}
|
|
|
|
|
|
/*ARGSUSED*/
|
|
void
|
|
NewConnectionXtProc (
|
|
XtPointer client_data,
|
|
int *source,
|
|
XtInputId *id)
|
|
{
|
|
IceConn ice_conn;
|
|
IceAcceptStatus status;
|
|
|
|
#ifdef DEBUG
|
|
(void) printf ("NewConnectionXtProc [fd = %d]\n", *source);
|
|
#endif /* DEBUG */
|
|
|
|
if (smXSMP.saveState.shutdown == True)
|
|
{
|
|
/*
|
|
* Don't accept new connections if we are in the middle
|
|
* of a shutdown.
|
|
*/
|
|
|
|
return;
|
|
}
|
|
|
|
ice_conn = IceAcceptConnection((IceListenObj) client_data, &status);
|
|
|
|
if (!ice_conn) {
|
|
char *message;
|
|
|
|
message = strdup ((char *) GETMESSAGE (40, 20,
|
|
"IceAcceptConnection failed."));
|
|
|
|
if (message) {
|
|
DtMsgLogMessage (smGD.programName, DtMsgLogError,
|
|
message);
|
|
free (message);
|
|
}
|
|
} else {
|
|
IceConnectStatus cstatus;
|
|
|
|
while ((cstatus = IceConnectionStatus (ice_conn)) ==
|
|
IceConnectPending) {
|
|
XtAppProcessEvent (smGD.appCon, XtIMAll);
|
|
}
|
|
|
|
if (cstatus == IceConnectAccepted) {
|
|
#ifdef DEBUG
|
|
char *connstr;
|
|
printf ("ICE Connection opened IceConn fd = %d, ",
|
|
IceConnectionNumber (ice_conn));
|
|
connstr = IceConnectionString (ice_conn);
|
|
printf ("\tAccept at networkId %s\n\n", connstr);
|
|
free (connstr);
|
|
#else
|
|
return;
|
|
#endif /* DEBUG */
|
|
} else {
|
|
#ifdef DEBUG
|
|
if (cstatus == IceConnectIOError)
|
|
printf ("IO error opening ICE Connection!\n");
|
|
else
|
|
printf ("ICE Connection rejected!\n");
|
|
#endif /* DEBUG */
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
Status
|
|
RegisterClientProc (
|
|
SmsConn smsConn,
|
|
SmPointer managerData,
|
|
char *previousId)
|
|
{
|
|
ClientRec *client = (ClientRec *) managerData;
|
|
char *id = previousId;
|
|
Boolean sendSave = False;
|
|
char *pchar;
|
|
#ifdef DEBUG
|
|
int i;
|
|
#endif /* DEBUG */
|
|
|
|
#ifdef DEBUG
|
|
(void) printf ("Received REGISTER CLIENT [%d] - id = %s\n",
|
|
smsConn, previousId ? previousId : "New Client");
|
|
#endif /* DEBUG */
|
|
|
|
if (!previousId) {
|
|
id = SmsGenerateClientID (smsConn);
|
|
sendSave = True;
|
|
}
|
|
else {
|
|
ClientRecPtr pClientRec;
|
|
XSMPClientDBRecPtr pDbRec;
|
|
Boolean found = False;
|
|
|
|
for (pClientRec = connectedList; pClientRec != NULL;
|
|
pClientRec = pClientRec->next) {
|
|
if (!strcmp (pClientRec->clientId, previousId)) {
|
|
#ifdef DEBUG
|
|
(void) printf ("\tAlready connected.\n");
|
|
#endif /* DEBUG */
|
|
if (!pClientRec->active)
|
|
/*
|
|
* A client that terminated is
|
|
* re-using its id
|
|
*/
|
|
found = True;
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (pDbRec = smXSMP.xsmpDbList;
|
|
pDbRec != NULL && found == False;
|
|
pDbRec = pDbRec->next) {
|
|
if (!strcmp (pDbRec->clientId, previousId)) {
|
|
#ifdef DEBUG
|
|
(void) printf ("\tClient in DB.\n");
|
|
#endif /* DEBUG */
|
|
found = True;
|
|
}
|
|
}
|
|
|
|
if (!found) {
|
|
/*
|
|
* The client is using an invalid id or
|
|
* this clientID is already being used.
|
|
* Reject the connection.
|
|
*/
|
|
#ifdef DEBUG
|
|
(void) printf ("\tID is NOT valid.\n");
|
|
#endif /* DEBUG */
|
|
free (previousId);
|
|
return (0);
|
|
}
|
|
}
|
|
|
|
client->clientId = strdup (id);
|
|
pchar = SmsClientHostName (smsConn);
|
|
if (pchar)
|
|
client->clientHost = (strchr (pchar, '/')) + 1;
|
|
else
|
|
client->clientHost = pchar;
|
|
client->active = True;
|
|
|
|
SmsRegisterClientReply (smsConn, id);
|
|
|
|
if (sendSave)
|
|
SmsSaveYourself (smsConn, SmSaveLocal, False,
|
|
SmInteractStyleNone, False);
|
|
|
|
#ifdef DEBUG
|
|
(void) printf ("CLIENTS REGISTERED:\n");
|
|
|
|
for (i = 1, client = connectedList;
|
|
client != NULL;
|
|
i++, client = client->next) {
|
|
|
|
if (client->active)
|
|
(void) printf ("\t[%2d] = %s\n", i, client->clientId);
|
|
}
|
|
#endif /* DEBUG */
|
|
|
|
return (1);
|
|
}
|
|
|
|
|
|
/*ARGSUSED*/
|
|
void
|
|
InteractRequestProc (
|
|
SmsConn smsConn,
|
|
SmPointer managerData,
|
|
int dialogType)
|
|
{
|
|
ClientRecPtr client = (ClientRecPtr) managerData;
|
|
Boolean getWsmClientOK = True;
|
|
|
|
#ifdef DEBUG
|
|
(void) printf ("Received INTERACT REQUEST [%d]\n", smsConn);
|
|
if (dialogType == SmDialogError)
|
|
(void) printf ("\tSmDialogError\n");
|
|
else if (dialogType == SmDialogNormal)
|
|
(void) printf ("\tSmDialogNormal\n");
|
|
else
|
|
(void) printf ("\tSMlib Error: should have checked for bad value\n");
|
|
#endif /* DEBUG */
|
|
|
|
client->interactRequested = True;
|
|
|
|
if (smXSMP.saveState.interactCount == 0) {
|
|
/*
|
|
* Only need to get the Wkspace list once for a save
|
|
*/
|
|
smXSMP.saveState.interactCount++;
|
|
|
|
if (!SendGetWsmClientsMessage ()) {
|
|
char *pch;
|
|
|
|
pch = strdup ((char *) GETMESSAGE (40, 17,
|
|
"An attempt to get a client list from the 'Window Manager' failed."));
|
|
if (pch) {
|
|
DtMsgLogMessage (smGD.programName,
|
|
DtMsgLogWarning, pch);
|
|
free (pch);
|
|
}
|
|
getWsmClientOK = False;
|
|
} else {
|
|
/*
|
|
* Cann't do anything else until the GetWsmClients
|
|
* message handler is invoked.
|
|
*
|
|
* Must cache this client because it is needed in the
|
|
* GetWsmClients callback and ToolTalk apparently
|
|
* doesn't allow 'client_data' to be assigned to its
|
|
* callback funtions.
|
|
*/
|
|
smXSMP.saveState.interactClient = client;
|
|
return;
|
|
}
|
|
}
|
|
|
|
ProcessInteract (client, getWsmClientOK);
|
|
}
|
|
|
|
|
|
/*ARGSUSED*/
|
|
void
|
|
InteractDoneProc (
|
|
SmsConn smsConn,
|
|
SmPointer managerData,
|
|
Bool cancelShutdown)
|
|
{
|
|
ClientRecPtr client = (ClientRecPtr) managerData;
|
|
|
|
#ifdef DEBUG
|
|
(void) printf ("Received INTERACT DONE [%d] - Cancel Shutdown = %s\n",
|
|
smsConn, cancelShutdown ? "True" : "False");
|
|
#endif /* DEBUG */
|
|
|
|
client->interactRequested = False;
|
|
smXSMP.saveState.clientInteracting = False;
|
|
|
|
if (cancelShutdown)
|
|
smXSMP.saveState.shutdownCanceled = True;
|
|
|
|
if (cancelShutdown &&
|
|
smXSMP.saveState.shutdown == True &&
|
|
(smXSMP.saveState.interactStyle == SmInteractStyleErrors ||
|
|
(smXSMP.saveState.interactStyle == SmInteractStyleAny))) {
|
|
|
|
ClientRecPtr pClientRec;
|
|
char *pch;
|
|
|
|
for (pClientRec = connectedList; pClientRec != NULL;
|
|
pClientRec = pClientRec->next) {
|
|
|
|
SmsShutdownCancelled (pClientRec->smConn);
|
|
#ifdef DEBUG
|
|
(void) printf ("Sent ShutdownCancelled to %d\n",
|
|
pClientRec->smConn);
|
|
#endif /* DEBUG */
|
|
}
|
|
|
|
pch = strdup ((char *) GETMESSAGE (40, 22, "A session shutdown was cancelled by the application '%s'."));
|
|
if (pch) {
|
|
DtMsgLogMessage (smGD.programName,
|
|
DtMsgLogInformation,
|
|
pch,
|
|
GetArrayPropertyValue (client,
|
|
SmProgram));
|
|
free (pch);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
ProcessInteract (client, True);
|
|
}
|
|
|
|
|
|
/*ARGSUSED*/
|
|
void
|
|
SaveYourselfReqProc (
|
|
SmsConn smsConn,
|
|
SmPointer managerData,
|
|
int saveType,
|
|
Bool shutdown,
|
|
int interactStyle,
|
|
Bool fast,
|
|
Bool global)
|
|
{
|
|
ClientRecPtr tmpClient;
|
|
ClientRecPtr pClientRec;
|
|
Boolean notify = True;
|
|
|
|
#ifdef DEBUG
|
|
(void) printf ("Received SAVE YOURSELF REQUEST [%d].\n", smsConn);
|
|
(void) printf ("\tglobal = %s\n", global ? "True" : "False");
|
|
(void) printf ("\tshutdown = %s\n", shutdown ? "True" : "False");
|
|
(void) printf ("\tfast = %s\n", fast ? "True" : "False");
|
|
(void) printf ("\tsaveType = ");
|
|
switch (saveType) {
|
|
case SmSaveLocal: printf ("SmSaveLocal\n"); break;
|
|
case SmSaveGlobal: printf ("SmSaveGlobal\n"); break;
|
|
case SmSaveBoth: printf ("SmSaveBoth\n"); break;
|
|
default: printf ("save type NOT supported\n");
|
|
}
|
|
(void) printf ("\tinteractStyle = ");
|
|
switch (saveType) {
|
|
case SmInteractStyleNone: printf ("SmInteractStyleNone\n");
|
|
break;
|
|
case SmInteractStyleErrors: printf ("SmInteractStyleErrors\n");
|
|
break;
|
|
case SmInteractStyleAny: printf ("SmInteractStyleAny\n");
|
|
break;
|
|
default: printf ("interact style NOT supported\n");
|
|
}
|
|
#endif /* DEBUG */
|
|
|
|
if (smXSMP.saveState.inProgress) {
|
|
char *pch;
|
|
|
|
pch = strdup ((char *) GETMESSAGE (40, 21, "The session will not be saved because a Save Session is in progress."));
|
|
if (pch) {
|
|
DtMsgLogMessage (smGD.programName, DtMsgLogError, pch);
|
|
free (pch);
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (!global) {
|
|
/*
|
|
* The client wants to be told to save itself but
|
|
* no other clients should be notified. [smsConn
|
|
* will be NULL if this non-global save came from
|
|
* a non-XSMP client (e.g via a ToolTalk message).
|
|
*/
|
|
if (smsConn) {
|
|
SmsSaveYourself (smsConn, saveType, shutdown,
|
|
interactStyle, fast);
|
|
#ifdef DEBUG
|
|
(void) printf ("\tSent SaveYourself to %d\n", smsConn);
|
|
#endif /* DEBUG */
|
|
}
|
|
return;
|
|
}
|
|
|
|
smXSMP.saveState.inProgress = True;
|
|
smXSMP.saveState.shutdown = shutdown;
|
|
smXSMP.saveState.shutdownCanceled = False;
|
|
smXSMP.saveState.interactStyle = interactStyle;
|
|
smXSMP.saveState.global = global;
|
|
|
|
/*
|
|
* Before notifying the clients, setup a directory
|
|
* for them to save their state.
|
|
*/
|
|
if (smGD.homeSave || (smGD.sessionType == HOME_SESSION &&
|
|
smSettings.startState == DtSM_HOME_STATE)) {
|
|
if (smXSMP.saveState.shutdown)
|
|
/*
|
|
* Leave the old session dir in place. It
|
|
* will only be used by XSMP apps.
|
|
*/
|
|
notify = False;
|
|
else
|
|
SetupSaveState (True, DtSM_HOME_STATE);
|
|
|
|
} else {
|
|
if (smGD.sessionType == CURRENT_SESSION ||
|
|
smGD.sessionType == DEFAULT_SESSION)
|
|
SetupSaveState (False, DtSM_CURRENT_STATE);
|
|
else if (smGD.sessionType == HOME_SESSION &&
|
|
smSettings.startState == DtSM_CURRENT_STATE)
|
|
SetupSaveState (False, DtSM_HOME_STATE);
|
|
else
|
|
SetupSaveState (False, DtSM_HOME_STATE);
|
|
}
|
|
|
|
/*
|
|
* Before the XSMP clients are saved, the ICCC apps must be
|
|
* sent a WM_SAVE_YOURSELF message. This needs to be done because some
|
|
* apps do not update their geometry information until they
|
|
* get this message. If an ICCC app doesn't update their geometry,
|
|
* then an XSMP-based Window Manager will not have the appropriate
|
|
* geometry information and the app will not be restore in the
|
|
* appropriate location.
|
|
*/
|
|
if (notify) {
|
|
EnterWaitState();
|
|
NotifyProxyClients ();
|
|
LeaveWaitState();
|
|
}
|
|
|
|
for (pClientRec = connectedList; pClientRec != NULL;
|
|
pClientRec = pClientRec->next) {
|
|
|
|
if (pClientRec->active) {
|
|
SmsSaveYourself (pClientRec->smConn, saveType,
|
|
shutdown, interactStyle, fast);
|
|
#ifdef DEBUG
|
|
(void) printf ("\tSent saveyourself to %d\n",
|
|
pClientRec->smConn);
|
|
#endif /* DEBUG */
|
|
}
|
|
}
|
|
|
|
/*
|
|
* If all of the clients are P2 clients, then process
|
|
* the save now because these clients won't send a
|
|
* SaveYourselfDone msg until after they have processed
|
|
* a P2 message.
|
|
*/
|
|
tmpClient = NULL;
|
|
|
|
for (pClientRec = connectedList; pClientRec != NULL;
|
|
pClientRec = pClientRec->next) {
|
|
|
|
if (pClientRec->active) {
|
|
if (pClientRec->saveYourselfP2Requested)
|
|
tmpClient = pClientRec;
|
|
else
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (tmpClient) {
|
|
SmsSaveYourselfPhase2 (tmpClient->smConn);
|
|
#ifdef DEBUG
|
|
(void) printf ("\tSent SaveYourselfPhase2 to %d\n",
|
|
pClientRec->smConn);
|
|
#endif /* DEBUG */
|
|
}
|
|
}
|
|
|
|
|
|
/*ARGSUSED*/
|
|
void
|
|
SaveYourselfPhase2ReqProc (
|
|
SmsConn smsConn,
|
|
SmPointer managerData)
|
|
{
|
|
ClientRecPtr client = (ClientRecPtr) managerData;
|
|
|
|
#ifdef DEBUG
|
|
(void) printf ("Received SAVE YOURSELF PHASE 2 REQUEST [%d]\n",
|
|
smsConn);
|
|
#endif /* DEBUG */
|
|
|
|
client->saveYourselfP2Requested = True;
|
|
|
|
/*
|
|
* A client may have sent this message in response to
|
|
* the SM's start-up SaveYourself message. So if
|
|
* a session isn't currently being saved, return.
|
|
*/
|
|
if (!smXSMP.saveState.inProgress) {
|
|
/*
|
|
* The client is responding to the start-up SaveYourself
|
|
* message - this isn't a user-initiated save.
|
|
*/
|
|
|
|
SmsSaveComplete (smsConn);
|
|
return;
|
|
}
|
|
|
|
ProcessSaveYourselfResponses ();
|
|
}
|
|
|
|
|
|
/*ARGSUSED*/
|
|
void
|
|
SaveYourselfDoneProc (
|
|
SmsConn smsConn,
|
|
SmPointer managerData,
|
|
Bool success)
|
|
{
|
|
ClientRecPtr pClientRec = (ClientRec *) managerData;
|
|
|
|
#ifdef DEBUG
|
|
(void) printf ("Received SAVE YOURSELF DONE [%d] - Success = %s\n",
|
|
smsConn, success ? "True" : "False");
|
|
#endif /* DEBUG */
|
|
|
|
if (!smXSMP.saveState.inProgress) {
|
|
/*
|
|
* The client is responding to the start-up SaveYourself
|
|
* message - this isn't a user-initiated save.
|
|
*/
|
|
SmsSaveComplete (smsConn);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Cache success if it is a failure - it will be needed later
|
|
*/
|
|
if (success == False)
|
|
smXSMP.saveState.doneSuccess = False;
|
|
|
|
pClientRec->saveYourselfDone = True;
|
|
|
|
ProcessSaveYourselfResponses ();
|
|
}
|
|
|
|
|
|
static void
|
|
ProcessSaveYourselfResponses (void)
|
|
{
|
|
ClientRecPtr pClientRec;
|
|
Boolean done = False;
|
|
|
|
/*
|
|
* If all clients are marked as saveYourselfDone, complete
|
|
* the save.
|
|
*/
|
|
for (done = True, pClientRec = connectedList;
|
|
pClientRec != NULL; pClientRec = pClientRec->next) {
|
|
|
|
if (pClientRec->active &&
|
|
pClientRec->saveYourselfDone == False) {
|
|
done = False;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (done) {
|
|
if (smXSMP.saveState.shutdownCanceled)
|
|
CancelShutdown ();
|
|
else
|
|
CompleteXSMPSave ();
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* If any client is marked as not having sent a
|
|
* SaveYourselfDone message and it is has not been
|
|
* marked as having requested a SaveYourselfP2,
|
|
* then return.
|
|
*/
|
|
for (pClientRec = connectedList; pClientRec != NULL;
|
|
pClientRec = pClientRec->next) {
|
|
|
|
if (pClientRec->active &&
|
|
pClientRec->saveYourselfDone == False &&
|
|
pClientRec->saveYourselfP2Requested == False)
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Only clients which requested a SaveYourselfP2 have not
|
|
* responded with a SaveYourselfDone message.
|
|
*
|
|
* Tell the P2 clients to save themselves.
|
|
*/
|
|
for (pClientRec = connectedList; pClientRec != NULL;
|
|
pClientRec = pClientRec->next) {
|
|
|
|
if (pClientRec->active) {
|
|
if (pClientRec->saveYourselfP2Requested &&
|
|
!pClientRec->saveYourselfDone) {
|
|
#ifdef DEBUG
|
|
(void) printf ("\tSent SaveYourselfPhase2 to %d\n",
|
|
pClientRec->smConn);
|
|
#endif /* DEBUG */
|
|
SmsSaveYourselfPhase2 (pClientRec->smConn);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*ARGSUSED*/
|
|
void
|
|
CloseConnectionProc (
|
|
SmsConn smsConn,
|
|
SmPointer managerData,
|
|
int count,
|
|
char **reasonMsgs)
|
|
{
|
|
ClientRecPtr pClientRec = (ClientRec *) managerData;
|
|
ClientRecPtr tmp = pClientRec;
|
|
|
|
#ifdef DEBUG
|
|
int i;
|
|
|
|
(void) printf ("Received CONNECTION CLOSED [%d]\n", smsConn);
|
|
|
|
for (i = 0; i < count; i++)
|
|
(void) printf ("\tReason [%2d]: %s\n", i+1, reasonMsgs[i]);
|
|
#endif /* DEBUG */
|
|
|
|
if (count > 0) {
|
|
PostReasonsDialog (GetArrayPropertyValue (tmp, SmProgram), count, reasonMsgs, True);
|
|
SmFreeReasons (count, reasonMsgs);
|
|
}
|
|
|
|
CloseDownClient (pClientRec);
|
|
}
|
|
|
|
void
|
|
CompleteXSMPSave (void)
|
|
{
|
|
ClientRecPtr pClientRec;
|
|
|
|
/*
|
|
* Save the XSMP clients' state and the Proxy clients' state
|
|
* and save the rest of the settings, resources, etc.
|
|
*/
|
|
CompleteSave ();
|
|
|
|
/*
|
|
* If this isn't a shutdown, tell the clients that the save
|
|
* is complete.
|
|
*/
|
|
if (!smXSMP.saveState.shutdown) {
|
|
for (pClientRec = connectedList; pClientRec != NULL;
|
|
pClientRec = pClientRec->next) {
|
|
|
|
if (pClientRec->active) {
|
|
SmsSaveComplete (pClientRec->smConn);
|
|
#ifdef DEBUG
|
|
printf ("SENT SmsSaveComplete to: %d\n",
|
|
pClientRec->smConn);
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!smXSMP.saveState.shutdown) {
|
|
for (pClientRec = connectedList; pClientRec != NULL;
|
|
pClientRec = pClientRec->next) {
|
|
|
|
if (pClientRec->active) {
|
|
pClientRec->saveYourselfDone = False;
|
|
pClientRec->saveYourselfP2Requested = False;
|
|
pClientRec->interactRequested = False;
|
|
}
|
|
}
|
|
|
|
InitializeSaveState (False);
|
|
|
|
} else {
|
|
|
|
int restartHint;
|
|
|
|
for (pClientRec = connectedList; pClientRec != NULL;
|
|
pClientRec = pClientRec->next) {
|
|
|
|
if (pClientRec->active) {
|
|
SmsDie (pClientRec->smConn);
|
|
#ifdef DEBUG
|
|
printf ("SENT SmsDie to: %d\n",
|
|
pClientRec->smConn);
|
|
#endif
|
|
}
|
|
|
|
if (!GetCardPropertyValue (pClientRec,
|
|
SmRestartStyleHint,
|
|
&restartHint))
|
|
restartHint = pClientRec->restartHint;
|
|
|
|
if (restartHint == SmRestartAnyway)
|
|
ExecuteCommandProperty (SmShutdownCommand,
|
|
pClientRec);
|
|
}
|
|
/*
|
|
* Cannot exit until all of the clients go away.
|
|
*/
|
|
smXSMP.saveState.saveComplete = True;
|
|
return;
|
|
}
|
|
}
|
|
|
|
static
|
|
void FreeProps (
|
|
PropertyRecPtr pProp)
|
|
{
|
|
PropertyRecPtr tmp;
|
|
PropertyRecPtr trail;
|
|
int i;
|
|
|
|
for (tmp = pProp; tmp != NULL; ) {
|
|
|
|
for (i = 0; i < tmp->prop.num_vals; i++)
|
|
XtFree (tmp->prop.vals[i].value);
|
|
if (tmp->prop.num_vals > 0)
|
|
XtFree ((char *) tmp->prop.vals);
|
|
trail = tmp;
|
|
tmp = tmp->next;
|
|
XtFree ((char *) trail);
|
|
}
|
|
}
|
|
|
|
|
|
void CloseDownClient (
|
|
ClientRecPtr pClientRec )
|
|
{
|
|
int restartHint;
|
|
ClientRecPtr tmp, trail;
|
|
SmsConn oldConn;
|
|
|
|
SmsCleanUp (pClientRec->smConn);
|
|
IceSetShutdownNegotiation (pClientRec->iceConn, False);
|
|
IceCloseConnection (pClientRec->iceConn);
|
|
|
|
/* save connection information for later compare */
|
|
oldConn = pClientRec->smConn;
|
|
|
|
pClientRec->iceConn = NULL;
|
|
pClientRec->smConn = NULL;
|
|
pClientRec->active = False;
|
|
|
|
if (!GetCardPropertyValue (pClientRec, SmRestartStyleHint,
|
|
&restartHint))
|
|
restartHint = pClientRec->restartHint;
|
|
|
|
if (!smXSMP.saveState.inProgress && restartHint == SmRestartImmediately)
|
|
ExecuteCommandProperty (SmRestartCommand, pClientRec);
|
|
|
|
if (restartHint == SmRestartAnyway)
|
|
ExecuteCommandProperty (SmResignCommand, pClientRec);
|
|
|
|
if (restartHint == SmRestartNever) {
|
|
/*
|
|
* Remove the client from the list
|
|
*/
|
|
for (tmp = trail = connectedList; tmp != NULL;
|
|
trail = tmp, tmp = tmp->next) {
|
|
if (tmp->smConn == oldConn) {
|
|
FreeProps (pClientRec->props);
|
|
if (tmp == connectedList)
|
|
connectedList = tmp->next;
|
|
trail->next = tmp->next;
|
|
XtFree ((char *) tmp);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* If a shutdown is occurring and all of the clients
|
|
* are inactive, exit.
|
|
*/
|
|
if (smXSMP.saveState.shutdown) {
|
|
/*
|
|
* Return if any clients are still active
|
|
*/
|
|
for (tmp = connectedList; tmp != NULL; tmp = tmp->next) {
|
|
if (tmp->active) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* All clients are inactive - its time to exit
|
|
*/
|
|
_DtReleaseLock (smGD.display, SM_RUNNING_LOCK);
|
|
SM_EXIT (0);
|
|
}
|
|
}
|
|
|
|
|
|
/*ARGSUSED*/
|
|
static
|
|
Tt_callback_action GetWsmClientsHandler(
|
|
Tt_message message,
|
|
Tt_pattern pattern)
|
|
{
|
|
int lenClientIds;
|
|
int num_args = tt_message_args_count (message);
|
|
#ifdef DEBUG
|
|
char * pchar;
|
|
int i;
|
|
#endif
|
|
|
|
if (num_args != 3) {
|
|
smXSMP.saveState.numClientIds = 0;
|
|
smXSMP.saveState.clientIds = NULL;
|
|
smXSMP.saveState.workspaceNums = NULL;
|
|
ProcessInteract (smXSMP.saveState.interactClient, False);
|
|
return (TT_CALLBACK_PROCESSED);
|
|
}
|
|
|
|
/*
|
|
* Before extracting the new values from this message, free any
|
|
* old values.
|
|
*/
|
|
if (smXSMP.saveState.clientIds)
|
|
free (smXSMP.saveState.clientIds);
|
|
if (smXSMP.saveState.workspaceNums)
|
|
free (smXSMP.saveState.workspaceNums);
|
|
|
|
tt_message_arg_ival (message, 0,
|
|
&smXSMP.saveState.numClientIds);
|
|
tt_message_arg_bval (message, 1,
|
|
(unsigned char **) &smXSMP.saveState.clientIds,
|
|
&lenClientIds);
|
|
tt_message_arg_bval (message, 2,
|
|
(unsigned char **) &smXSMP.saveState.workspaceNums,
|
|
&lenClientIds);
|
|
tt_message_reply (message);
|
|
tt_message_destroy (message);
|
|
|
|
#ifdef DEBUG
|
|
(void) printf("GetWsmClientsHandler: num clients = %d\n",
|
|
smXSMP.saveState.numClientIds);
|
|
for (i = 0, pchar = smXSMP.saveState.clientIds;
|
|
i < smXSMP.saveState.numClientIds;
|
|
i++, pchar += strlen (pchar) + 1) {
|
|
(void) printf("\tclient [%2d]: workspace = %2d, id = %s\n",
|
|
i+1, smXSMP.saveState.workspaceNums[i], pchar);
|
|
}
|
|
#endif
|
|
|
|
ProcessInteract (smXSMP.saveState.interactClient, True);
|
|
|
|
return (TT_CALLBACK_PROCESSED);
|
|
}
|
|
|
|
|
|
static
|
|
Boolean SendGetWsmClientsMessage (void)
|
|
{
|
|
Tt_message message;
|
|
Tt_status status;
|
|
|
|
message = tt_message_create ();
|
|
status = tt_ptr_error (message);
|
|
if (status != TT_OK)
|
|
return (False);
|
|
|
|
tt_message_class_set (message, TT_REQUEST);
|
|
tt_message_scope_set (message, TT_SESSION);
|
|
tt_message_address_set (message, TT_PROCEDURE);
|
|
|
|
tt_message_session_set (message, tt_default_session());
|
|
tt_message_op_set (message, GET_CLIENT_WORKSPACE_MSG);
|
|
tt_message_callback_add (message, GetWsmClientsHandler);
|
|
|
|
/*
|
|
* Three arguments are expected in the reply so apparently
|
|
* they must be accounted for now.
|
|
*/
|
|
tt_message_iarg_add (message, TT_OUT, "integer", 0);
|
|
tt_message_barg_add (message, TT_OUT, "stringlist", 0, 0);
|
|
tt_message_barg_add (message, TT_OUT, "intlist", 0, 0);
|
|
|
|
status = tt_message_send (message);
|
|
if (status != TT_OK)
|
|
return (False);
|
|
|
|
return (True);
|
|
}
|
|
|
|
|
|
static
|
|
int GetCurrentWorkspaceNumber (void)
|
|
{
|
|
Atom currentWorkspace;
|
|
Atom *workspaceList;
|
|
Window root;
|
|
int rval;
|
|
int numWorkspaces;
|
|
int i;
|
|
|
|
root = XDefaultRootWindow (smGD.display);
|
|
|
|
rval = DtWsmGetCurrentWorkspace(smGD.display, root, ¤tWorkspace);
|
|
if (rval != Success)
|
|
return (-1);
|
|
|
|
rval = DtWsmGetWorkspaceList (smGD.display, root, &workspaceList,
|
|
(int *) &numWorkspaces);
|
|
if (rval != Success)
|
|
return (-1);
|
|
|
|
for (i = 0; i < numWorkspaces; i++) {
|
|
if (currentWorkspace == workspaceList[i])
|
|
return (currentWorkspace);
|
|
}
|
|
|
|
return (-1);
|
|
}
|
|
|
|
|
|
static
|
|
void CancelShutdown (void)
|
|
{
|
|
ClientRecPtr pClientRec;
|
|
char *pch;
|
|
|
|
for (pClientRec = connectedList; pClientRec != NULL;
|
|
pClientRec = pClientRec->next) {
|
|
|
|
if (pClientRec->active) {
|
|
|
|
ExecuteCommandProperty (SmDiscardCommand, pClientRec);
|
|
|
|
pClientRec->saveYourselfDone = False;
|
|
pClientRec->saveYourselfP2Requested = False;
|
|
pClientRec->interactRequested = False;
|
|
}
|
|
}
|
|
|
|
UndoSetSavePath ();
|
|
|
|
InitializeSaveState (False);
|
|
}
|
|
|
|
|
|
/*
|
|
* This function can be invoked via different paths:
|
|
*
|
|
* 1. From the InteractRequest callback
|
|
* 2. From the InteractDone callback
|
|
* 3. From the GetWsmClients message callback
|
|
*/
|
|
static
|
|
void ProcessInteract (
|
|
ClientRecPtr client,
|
|
Boolean getWsmClientOK)
|
|
{
|
|
int currentWorkspace;
|
|
int i;
|
|
ClientRecPtr pClientRec;
|
|
ClientRecPtr tmp = NULL;
|
|
char *pchar;
|
|
|
|
if (!getWsmClientOK) {
|
|
smXSMP.saveState.clientInteracting = True;
|
|
SmsInteract (client->smConn);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* If a client wants to interact and its workspace matches
|
|
* the current workspace, then let it interact.
|
|
*/
|
|
currentWorkspace = GetCurrentWorkspaceNumber ();
|
|
|
|
for (pClientRec = connectedList;
|
|
pClientRec != NULL;
|
|
pClientRec = pClientRec->next) {
|
|
|
|
if (pClientRec->interactRequested) {
|
|
tmp = pClientRec;
|
|
|
|
for (i = 0, pchar = smXSMP.saveState.clientIds;
|
|
i < smXSMP.saveState.numClientIds;
|
|
i++, pchar += strlen (pchar) + 1) {
|
|
|
|
if ((currentWorkspace ==
|
|
smXSMP.saveState.workspaceNums[i]) &&
|
|
(!strcmp (pchar, pClientRec->clientId))) {
|
|
|
|
smXSMP.saveState.clientInteracting =
|
|
True;
|
|
SmsInteract (pClientRec->smConn);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Tmp didn't meet all of the requirements but it does
|
|
* want to interact so let it.
|
|
*/
|
|
if (tmp) {
|
|
smXSMP.saveState.clientInteracting = True;
|
|
SmsInteract (tmp->smConn);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* List manipulation functions
|
|
*/
|
|
void AddClient (
|
|
ClientRecPtr newClient)
|
|
{
|
|
ClientRecPtr pClient;
|
|
|
|
if (!connectedList) {
|
|
connectedList = newClient;
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Find the end of the list
|
|
*/
|
|
for (pClient = connectedList; pClient->next != NULL;
|
|
pClient = pClient->next);
|
|
|
|
pClient->next = newClient;
|
|
}
|
|
|
|
|
|
/*
|
|
* The real way to handle IO errors is to check the return status
|
|
* of IceProcessMessages. dtsession properly does this.
|
|
*
|
|
* Unfortunately, a design flaw exists in the ICE library in which
|
|
* a default IO error handler is invoked if no IO error handler is
|
|
* installed. This default handler exits. We must avoid this.
|
|
*
|
|
* To get around this problem, we install an IO error handler that
|
|
* does a little magic. Since a previous IO handler might have been
|
|
* installed, when we install our IO error handler, we do a little
|
|
* trick to get both the previous IO error handler and the default
|
|
* IO error handler. When our IO error handler is called, if the
|
|
* previous handler is not the default handler, we call it. This
|
|
* way, everyone's IO error handler gets called except the stupid
|
|
* default one which does an exit!
|
|
*/
|
|
|
|
static IceIOErrorHandler prev_handler;
|
|
|
|
void
|
|
MyIoErrorHandler (
|
|
IceConn ice_conn)
|
|
{
|
|
if (prev_handler)
|
|
(*prev_handler) (ice_conn);
|
|
}
|
|
|
|
void
|
|
InstallIOErrorHandler (void)
|
|
{
|
|
IceIOErrorHandler default_handler;
|
|
|
|
prev_handler = IceSetIOErrorHandler (NULL);
|
|
default_handler = IceSetIOErrorHandler (MyIoErrorHandler);
|
|
if (prev_handler == default_handler)
|
|
prev_handler = NULL;
|
|
}
|
|
|
|
|
|
void XSMPExit (void)
|
|
{
|
|
char * pchar;
|
|
|
|
if (authenticationInitialized)
|
|
FreeAuthenticationData (smXSMP.numTransports,
|
|
smXSMP.authDataEntries);
|
|
|
|
/*
|
|
* If the local socket file exists, remove it.
|
|
*
|
|
* Assume the format of networkIds is:
|
|
*
|
|
* local/<host_name>:/<socket_file_name>,<other_stuff>
|
|
*/
|
|
if (!strncmp (networkIds, "local/", 6)) {
|
|
if (pchar = strchr (networkIds, ':')) {
|
|
pchar++;
|
|
if (pchar && *pchar != '\000') {
|
|
char * pchar2;
|
|
|
|
if (pchar2 = strchr (pchar, ',')) {
|
|
struct stat buf;
|
|
/*
|
|
* This modifies networkIds but
|
|
* that's OK because an exit is
|
|
* about to happen.
|
|
*/
|
|
*pchar2 = '\000';
|
|
if ((stat (pchar, &buf)) == 0) {
|
|
(void) unlink (pchar);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|