641 lines
14 KiB
C
641 lines
14 KiB
C
/* $XFree86: xc/lib/SM/sm_client.c,v 1.4 2004/12/31 02:56:03 tsi Exp $ */
|
||
/* $Xorg: sm_client.c,v 1.4 2001/02/09 02:03:30 xorgcvs Exp $ */
|
||
|
||
/*
|
||
|
||
Copyright 1993, 1998 The Open Group
|
||
|
||
Permission to use, copy, modify, distribute, and sell this software and its
|
||
documentation for any purpose is hereby granted without fee, provided that
|
||
the above copyright notice appear in all copies and that both that
|
||
copyright notice and this permission notice appear in supporting
|
||
documentation.
|
||
|
||
The above copyright notice and this permission notice shall be included in
|
||
all copies or substantial portions of the Software.
|
||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||
OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||
|
||
Except as contained in this notice, the name of The Open Group shall not be
|
||
used in advertising or otherwise to promote the sale, use or other dealings
|
||
in this Software without prior written authorization from The Open Group.
|
||
|
||
*/
|
||
|
||
/*
|
||
* Author: Ralph Mor, X Consortium
|
||
*/
|
||
|
||
#include <X11/SM/SMlib.h>
|
||
#include "SMlibint.h"
|
||
#include "globals.h"
|
||
|
||
static void set_callbacks();
|
||
|
||
|
||
SmcConn
|
||
SmcOpenConnection (networkIdsList, context,
|
||
xsmpMajorRev, xsmpMinorRev, mask, callbacks,
|
||
previousId, clientIdRet, errorLength, errorStringRet)
|
||
|
||
char *networkIdsList;
|
||
SmPointer context;
|
||
int xsmpMajorRev;
|
||
int xsmpMinorRev;
|
||
unsigned long mask;
|
||
SmcCallbacks *callbacks;
|
||
char *previousId;
|
||
char **clientIdRet;
|
||
int errorLength;
|
||
char *errorStringRet;
|
||
|
||
{
|
||
SmcConn smcConn;
|
||
IceConn iceConn;
|
||
char *ids;
|
||
IceProtocolSetupStatus setupstat;
|
||
int majorVersion;
|
||
int minorVersion;
|
||
char *vendor = NULL;
|
||
char *release = NULL;
|
||
smRegisterClientMsg *pMsg;
|
||
char *pData;
|
||
int extra, len;
|
||
IceReplyWaitInfo replyWait;
|
||
_SmcRegisterClientReply reply;
|
||
Bool gotReply, ioErrorOccured;
|
||
|
||
*clientIdRet = NULL;
|
||
|
||
if (errorStringRet && errorLength > 0)
|
||
*errorStringRet = '\0';
|
||
|
||
if (!_SmcOpcode)
|
||
{
|
||
/*
|
||
* For now, there is only one version of XSMP, so we don't
|
||
* have to check {xsmpMajorRev, xsmpMinorRev}. In the future,
|
||
* we will check against _SmcVersions and generate the list
|
||
* of versions the application actually supports.
|
||
*/
|
||
|
||
if ((_SmcOpcode = IceRegisterForProtocolSetup ("XSMP",
|
||
SmVendorString, SmReleaseString, _SmVersionCount, _SmcVersions,
|
||
_SmAuthCount, _SmAuthNames, _SmcAuthProcs, NULL)) < 0)
|
||
{
|
||
strncpy (errorStringRet,
|
||
"Could not register XSMP protocol with ICE", errorLength);
|
||
|
||
return (NULL);
|
||
}
|
||
}
|
||
|
||
if (networkIdsList == NULL || *networkIdsList == '\0')
|
||
{
|
||
if ((ids = (char *) getenv ("SESSION_MANAGER")) == NULL)
|
||
{
|
||
strncpy (errorStringRet,
|
||
"SESSION_MANAGER environment variable not defined",
|
||
errorLength);
|
||
|
||
return (NULL);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
ids = networkIdsList;
|
||
}
|
||
|
||
if ((iceConn = IceOpenConnection (
|
||
ids, context, 0, _SmcOpcode, errorLength, errorStringRet)) == NULL)
|
||
{
|
||
return (NULL);
|
||
}
|
||
|
||
if ((smcConn = (SmcConn) malloc (sizeof (struct _SmcConn))) == NULL)
|
||
{
|
||
strncpy (errorStringRet, "Can't malloc", errorLength);
|
||
IceCloseConnection (iceConn);
|
||
return (NULL);
|
||
}
|
||
|
||
setupstat = IceProtocolSetup (iceConn, _SmcOpcode,
|
||
(IcePointer) smcConn,
|
||
False /* mustAuthenticate */,
|
||
&majorVersion, &minorVersion,
|
||
&vendor, &release, errorLength, errorStringRet);
|
||
|
||
if (setupstat == IceProtocolSetupFailure ||
|
||
setupstat == IceProtocolSetupIOError)
|
||
{
|
||
IceCloseConnection (iceConn);
|
||
free ((char *) smcConn);
|
||
return (NULL);
|
||
}
|
||
else if (setupstat == IceProtocolAlreadyActive)
|
||
{
|
||
/*
|
||
* This case should never happen, because when we called
|
||
* IceOpenConnection, we required that the ICE connection
|
||
* may not already have XSMP active on it.
|
||
*/
|
||
|
||
free ((char *) smcConn);
|
||
strncpy (errorStringRet, "Internal error in IceOpenConnection",
|
||
errorLength);
|
||
return (NULL);
|
||
}
|
||
|
||
smcConn->iceConn = iceConn;
|
||
smcConn->proto_major_version = majorVersion;
|
||
smcConn->proto_minor_version = minorVersion;
|
||
smcConn->vendor = vendor;
|
||
smcConn->release = release;
|
||
smcConn->client_id = NULL;
|
||
|
||
bzero ((char *) &smcConn->callbacks, sizeof (SmcCallbacks));
|
||
set_callbacks (smcConn, mask, callbacks);
|
||
|
||
smcConn->interact_waits = NULL;
|
||
smcConn->phase2_wait = NULL;
|
||
smcConn->prop_reply_waits = NULL;
|
||
|
||
smcConn->save_yourself_in_progress = False;
|
||
smcConn->shutdown_in_progress = False;
|
||
|
||
|
||
/*
|
||
* Now register the client
|
||
*/
|
||
|
||
len = previousId ? strlen (previousId) : 0;
|
||
extra = ARRAY8_BYTES (len);
|
||
|
||
IceGetHeaderExtra (iceConn, _SmcOpcode, SM_RegisterClient,
|
||
SIZEOF (smRegisterClientMsg), WORD64COUNT (extra),
|
||
smRegisterClientMsg, pMsg, pData);
|
||
|
||
if (pData == NULL)
|
||
{
|
||
strncpy (errorStringRet, "Malformed previous session ID", errorLength);
|
||
|
||
free (smcConn->vendor);
|
||
free (smcConn->release);
|
||
free ((char *) smcConn);
|
||
|
||
return (NULL);
|
||
}
|
||
|
||
STORE_ARRAY8 (pData, len, previousId);
|
||
|
||
IceFlush (iceConn);
|
||
|
||
replyWait.sequence_of_request = IceLastSentSequenceNumber (iceConn);
|
||
replyWait.major_opcode_of_request = _SmcOpcode;
|
||
replyWait.minor_opcode_of_request = SM_RegisterClient;
|
||
replyWait.reply = (IcePointer) &reply;
|
||
|
||
gotReply = False;
|
||
ioErrorOccured = False;
|
||
|
||
while (!gotReply && !ioErrorOccured)
|
||
{
|
||
ioErrorOccured = (IceProcessMessages (
|
||
iceConn, &replyWait, &gotReply) == IceProcessMessagesIOError);
|
||
|
||
if (ioErrorOccured)
|
||
{
|
||
strncpy (errorStringRet, "IO error occured opening connection",
|
||
errorLength);
|
||
|
||
free (smcConn->vendor);
|
||
free (smcConn->release);
|
||
free ((char *) smcConn);
|
||
|
||
return (NULL);
|
||
}
|
||
else if (gotReply)
|
||
{
|
||
if (reply.status == 1)
|
||
{
|
||
/*
|
||
* The client successfully registered.
|
||
*/
|
||
|
||
*clientIdRet = reply.client_id;
|
||
|
||
smcConn->client_id = (char *) malloc (
|
||
strlen (*clientIdRet) + 1);
|
||
|
||
strcpy (smcConn->client_id, *clientIdRet);
|
||
}
|
||
else
|
||
{
|
||
/*
|
||
* Could not register the client because the previous ID
|
||
* was bad. So now we register the client with the
|
||
* previous ID set to NULL.
|
||
*/
|
||
|
||
extra = ARRAY8_BYTES (0);
|
||
|
||
IceGetHeaderExtra (iceConn, _SmcOpcode, SM_RegisterClient,
|
||
SIZEOF (smRegisterClientMsg), WORD64COUNT (extra),
|
||
smRegisterClientMsg, pMsg, pData);
|
||
|
||
STORE_NULL (pData);
|
||
|
||
IceFlush (iceConn);
|
||
|
||
replyWait.sequence_of_request =
|
||
IceLastSentSequenceNumber (iceConn);
|
||
|
||
gotReply = False;
|
||
}
|
||
}
|
||
}
|
||
|
||
return (smcConn);
|
||
}
|
||
|
||
|
||
|
||
SmcCloseStatus
|
||
SmcCloseConnection (smcConn, count, reasonMsgs)
|
||
|
||
SmcConn smcConn;
|
||
int count;
|
||
char **reasonMsgs;
|
||
|
||
{
|
||
IceConn iceConn = smcConn->iceConn;
|
||
smCloseConnectionMsg *pMsg;
|
||
char *pData;
|
||
int extra, i;
|
||
IceCloseStatus closeStatus;
|
||
SmcCloseStatus statusRet;
|
||
|
||
extra = 8;
|
||
|
||
for (i = 0; i < count; i++)
|
||
extra += ARRAY8_BYTES (strlen (reasonMsgs[i]));
|
||
|
||
IceGetHeaderExtra (iceConn, _SmcOpcode, SM_CloseConnection,
|
||
SIZEOF (smCloseConnectionMsg), WORD64COUNT (extra),
|
||
smCloseConnectionMsg, pMsg, pData);
|
||
|
||
STORE_CARD32 (pData, count);
|
||
pData += 4;
|
||
|
||
for (i = 0; i < count; i++)
|
||
STORE_ARRAY8 (pData, strlen (reasonMsgs[i]), reasonMsgs[i]);
|
||
|
||
IceFlush (iceConn);
|
||
|
||
IceProtocolShutdown (iceConn, _SmcOpcode);
|
||
IceSetShutdownNegotiation (iceConn, False);
|
||
closeStatus = IceCloseConnection (iceConn);
|
||
|
||
if (smcConn->vendor)
|
||
free (smcConn->vendor);
|
||
|
||
if (smcConn->release)
|
||
free (smcConn->release);
|
||
|
||
if (smcConn->client_id)
|
||
free (smcConn->client_id);
|
||
|
||
if (smcConn->prop_reply_waits)
|
||
{
|
||
_SmcPropReplyWait *ptr = smcConn->prop_reply_waits;
|
||
_SmcPropReplyWait *next;
|
||
|
||
while (ptr)
|
||
{
|
||
next = ptr->next;
|
||
free ((char *) ptr);
|
||
ptr = next;
|
||
}
|
||
|
||
}
|
||
|
||
free ((char *) smcConn);
|
||
|
||
if (closeStatus == IceClosedNow)
|
||
statusRet = SmcClosedNow;
|
||
else if (closeStatus == IceClosedASAP)
|
||
statusRet = SmcClosedASAP;
|
||
else
|
||
statusRet = SmcConnectionInUse;
|
||
|
||
return (statusRet);
|
||
}
|
||
|
||
|
||
|
||
void
|
||
SmcModifyCallbacks (smcConn, mask, callbacks)
|
||
|
||
SmcConn smcConn;
|
||
unsigned long mask;
|
||
SmcCallbacks *callbacks;
|
||
|
||
{
|
||
set_callbacks (smcConn, mask, callbacks);
|
||
}
|
||
|
||
|
||
|
||
void
|
||
SmcSetProperties (smcConn, numProps, props)
|
||
|
||
SmcConn smcConn;
|
||
int numProps;
|
||
SmProp **props;
|
||
|
||
{
|
||
IceConn iceConn = smcConn->iceConn;
|
||
smSetPropertiesMsg *pMsg;
|
||
char *pBuf;
|
||
char *pStart;
|
||
int bytes;
|
||
|
||
IceGetHeader (iceConn, _SmcOpcode, SM_SetProperties,
|
||
SIZEOF (smSetPropertiesMsg), smSetPropertiesMsg, pMsg);
|
||
|
||
LISTOF_PROP_BYTES (numProps, props, bytes);
|
||
pMsg->length += WORD64COUNT (bytes);
|
||
|
||
pBuf = pStart = IceAllocScratch (iceConn, bytes);
|
||
|
||
STORE_LISTOF_PROPERTY (pBuf, numProps, props);
|
||
|
||
IceWriteData (iceConn, bytes, pStart);
|
||
IceFlush (iceConn);
|
||
}
|
||
|
||
|
||
|
||
void
|
||
SmcDeleteProperties (smcConn, numProps, propNames)
|
||
|
||
SmcConn smcConn;
|
||
int numProps;
|
||
char **propNames;
|
||
|
||
{
|
||
IceConn iceConn = smcConn->iceConn;
|
||
smDeletePropertiesMsg *pMsg;
|
||
char *pData;
|
||
int extra, i;
|
||
|
||
extra = 8;
|
||
|
||
for (i = 0; i < numProps; i++)
|
||
extra += ARRAY8_BYTES (strlen (propNames[i]));
|
||
|
||
IceGetHeaderExtra (iceConn, _SmcOpcode, SM_DeleteProperties,
|
||
SIZEOF (smDeletePropertiesMsg), WORD64COUNT (extra),
|
||
smDeletePropertiesMsg, pMsg, pData);
|
||
|
||
STORE_CARD32 (pData, numProps);
|
||
pData += 4;
|
||
|
||
for (i = 0; i < numProps; i++)
|
||
STORE_ARRAY8 (pData, strlen (propNames[i]), propNames[i]);
|
||
|
||
IceFlush (iceConn);
|
||
}
|
||
|
||
|
||
|
||
Status
|
||
SmcGetProperties (smcConn, propReplyProc, clientData)
|
||
|
||
SmcConn smcConn;
|
||
SmcPropReplyProc propReplyProc;
|
||
SmPointer clientData;
|
||
|
||
{
|
||
IceConn iceConn = smcConn->iceConn;
|
||
_SmcPropReplyWait *wait, *ptr;
|
||
|
||
if ((wait = (_SmcPropReplyWait *) malloc (
|
||
sizeof (_SmcPropReplyWait))) == NULL)
|
||
{
|
||
return (0);
|
||
}
|
||
|
||
wait->prop_reply_proc = propReplyProc;
|
||
wait->client_data = clientData;
|
||
wait->next = NULL;
|
||
|
||
ptr = smcConn->prop_reply_waits;
|
||
while (ptr && ptr->next)
|
||
ptr = ptr->next;
|
||
|
||
if (ptr == NULL)
|
||
smcConn->prop_reply_waits = wait;
|
||
else
|
||
ptr->next = wait;
|
||
|
||
IceSimpleMessage (iceConn, _SmcOpcode, SM_GetProperties);
|
||
IceFlush (iceConn);
|
||
|
||
return (1);
|
||
}
|
||
|
||
|
||
|
||
Status
|
||
SmcInteractRequest (smcConn, dialogType, interactProc, clientData)
|
||
|
||
SmcConn smcConn;
|
||
int dialogType;
|
||
SmcInteractProc interactProc;
|
||
SmPointer clientData;
|
||
|
||
{
|
||
IceConn iceConn = smcConn->iceConn;
|
||
smInteractRequestMsg *pMsg;
|
||
_SmcInteractWait *wait, *ptr;
|
||
|
||
if ((wait = (_SmcInteractWait *) malloc (
|
||
sizeof (_SmcInteractWait))) == NULL)
|
||
{
|
||
return (0);
|
||
}
|
||
|
||
wait->interact_proc = interactProc;
|
||
wait->client_data = clientData;
|
||
wait->next = NULL;
|
||
|
||
ptr = smcConn->interact_waits;
|
||
while (ptr && ptr->next)
|
||
ptr = ptr->next;
|
||
|
||
if (ptr == NULL)
|
||
smcConn->interact_waits = wait;
|
||
else
|
||
ptr->next = wait;
|
||
|
||
IceGetHeader (iceConn, _SmcOpcode, SM_InteractRequest,
|
||
SIZEOF (smInteractRequestMsg), smInteractRequestMsg, pMsg);
|
||
|
||
pMsg->dialogType = dialogType;
|
||
|
||
IceFlush (iceConn);
|
||
|
||
return (1);
|
||
}
|
||
|
||
|
||
|
||
void
|
||
SmcInteractDone (smcConn, cancelShutdown)
|
||
|
||
SmcConn smcConn;
|
||
Bool cancelShutdown;
|
||
|
||
{
|
||
IceConn iceConn = smcConn->iceConn;
|
||
smInteractDoneMsg *pMsg;
|
||
|
||
IceGetHeader (iceConn, _SmcOpcode, SM_InteractDone,
|
||
SIZEOF (smInteractDoneMsg), smInteractDoneMsg, pMsg);
|
||
|
||
pMsg->cancelShutdown = cancelShutdown;
|
||
|
||
IceFlush (iceConn);
|
||
}
|
||
|
||
|
||
|
||
void
|
||
SmcRequestSaveYourself (smcConn, saveType, shutdown, interactStyle,
|
||
fast, global)
|
||
|
||
SmcConn smcConn;
|
||
int saveType;
|
||
Bool shutdown;
|
||
int interactStyle;
|
||
Bool fast;
|
||
Bool global;
|
||
|
||
{
|
||
IceConn iceConn = smcConn->iceConn;
|
||
smSaveYourselfRequestMsg *pMsg;
|
||
|
||
IceGetHeader (iceConn, _SmcOpcode, SM_SaveYourselfRequest,
|
||
SIZEOF (smSaveYourselfRequestMsg), smSaveYourselfRequestMsg, pMsg);
|
||
|
||
pMsg->saveType = saveType;
|
||
pMsg->shutdown = shutdown;
|
||
pMsg->interactStyle = interactStyle;
|
||
pMsg->fast = fast;
|
||
pMsg->global = global;
|
||
|
||
IceFlush (iceConn);
|
||
}
|
||
|
||
|
||
|
||
Status
|
||
SmcRequestSaveYourselfPhase2 (smcConn, saveYourselfPhase2Proc, clientData)
|
||
|
||
SmcConn smcConn;
|
||
SmcSaveYourselfPhase2Proc saveYourselfPhase2Proc;
|
||
SmPointer clientData;
|
||
|
||
{
|
||
IceConn iceConn = smcConn->iceConn;
|
||
_SmcPhase2Wait *wait;
|
||
|
||
if (smcConn->phase2_wait)
|
||
wait = smcConn->phase2_wait;
|
||
else
|
||
{
|
||
if ((wait = (_SmcPhase2Wait *) malloc (
|
||
sizeof (_SmcPhase2Wait))) == NULL)
|
||
{
|
||
return (0);
|
||
}
|
||
}
|
||
|
||
wait->phase2_proc = saveYourselfPhase2Proc;
|
||
wait->client_data = clientData;
|
||
|
||
smcConn->phase2_wait = wait;
|
||
|
||
IceSimpleMessage (iceConn, _SmcOpcode, SM_SaveYourselfPhase2Request);
|
||
IceFlush (iceConn);
|
||
|
||
return (1);
|
||
}
|
||
|
||
|
||
|
||
void
|
||
SmcSaveYourselfDone (smcConn, success)
|
||
|
||
SmcConn smcConn;
|
||
Bool success;
|
||
|
||
{
|
||
IceConn iceConn = smcConn->iceConn;
|
||
smSaveYourselfDoneMsg *pMsg;
|
||
|
||
IceGetHeader (iceConn, _SmcOpcode, SM_SaveYourselfDone,
|
||
SIZEOF (smSaveYourselfDoneMsg), smSaveYourselfDoneMsg, pMsg);
|
||
|
||
pMsg->success = success;
|
||
|
||
IceFlush (iceConn);
|
||
}
|
||
|
||
|
||
|
||
static void
|
||
set_callbacks (smcConn, mask, callbacks)
|
||
|
||
SmcConn smcConn;
|
||
unsigned long mask;
|
||
SmcCallbacks *callbacks;
|
||
|
||
{
|
||
if (mask & SmcSaveYourselfProcMask)
|
||
{
|
||
smcConn->callbacks.save_yourself.callback =
|
||
callbacks->save_yourself.callback;
|
||
smcConn->callbacks.save_yourself.client_data =
|
||
callbacks->save_yourself.client_data;
|
||
}
|
||
|
||
if (mask & SmcDieProcMask)
|
||
{
|
||
smcConn->callbacks.die.callback = callbacks->die.callback;
|
||
smcConn->callbacks.die.client_data = callbacks->die.client_data;
|
||
}
|
||
|
||
if (mask & SmcSaveCompleteProcMask)
|
||
{
|
||
smcConn->callbacks.save_complete.callback =
|
||
callbacks->save_complete.callback;
|
||
smcConn->callbacks.save_complete.client_data =
|
||
callbacks->save_complete.client_data;
|
||
}
|
||
|
||
if (mask & SmcShutdownCancelledProcMask)
|
||
{
|
||
smcConn->callbacks.shutdown_cancelled.callback =
|
||
callbacks->shutdown_cancelled.callback;
|
||
smcConn->callbacks.shutdown_cancelled.client_data =
|
||
callbacks->shutdown_cancelled.client_data;
|
||
}
|
||
}
|