sm_client.c revision 3c15da26
1126a8a12Smrg/*
2126a8a12Smrg
3126a8a12SmrgCopyright 1993, 1998  The Open Group
4126a8a12Smrg
5126a8a12SmrgPermission to use, copy, modify, distribute, and sell this software and its
6126a8a12Smrgdocumentation for any purpose is hereby granted without fee, provided that
7126a8a12Smrgthe above copyright notice appear in all copies and that both that
8126a8a12Smrgcopyright notice and this permission notice appear in supporting
9126a8a12Smrgdocumentation.
10126a8a12Smrg
11126a8a12SmrgThe above copyright notice and this permission notice shall be included in
12126a8a12Smrgall copies or substantial portions of the Software.
13126a8a12Smrg
14126a8a12SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15126a8a12SmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16126a8a12SmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17126a8a12SmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18126a8a12SmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19126a8a12SmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20126a8a12Smrg
21126a8a12SmrgExcept as contained in this notice, the name of The Open Group shall not be
22126a8a12Smrgused in advertising or otherwise to promote the sale, use or other dealings
23126a8a12Smrgin this Software without prior written authorization from The Open Group.
24126a8a12Smrg
25126a8a12Smrg*/
26126a8a12Smrg
27126a8a12Smrg/*
28126a8a12Smrg * Author: Ralph Mor, X Consortium
29126a8a12Smrg */
30126a8a12Smrg
31126a8a12Smrg#ifdef HAVE_CONFIG_H
32126a8a12Smrg#include <config.h>
33126a8a12Smrg#endif
34126a8a12Smrg#include <X11/SM/SMlib.h>
35126a8a12Smrg#include "SMlibint.h"
36126a8a12Smrg
37d656433aSmrgint 	_SmcOpcode = 0;
38d656433aSmrgint 	_SmsOpcode = 0;
39d656433aSmrg
40d656433aSmrg#ifndef __UNIXOS2__
41d656433aSmrgSmsNewClientProc _SmsNewClientProc;
42d656433aSmrgSmPointer        _SmsNewClientData;
43d656433aSmrg#else
44d656433aSmrgSmsNewClientProc _SmsNewClientProc = 0;
45d656433aSmrgSmPointer        _SmsNewClientData = 0;
46d656433aSmrg#endif
47d656433aSmrg
48d656433aSmrgSmcErrorHandler _SmcErrorHandler = _SmcDefaultErrorHandler;
49d656433aSmrgSmsErrorHandler _SmsErrorHandler = _SmsDefaultErrorHandler;
50d656433aSmrg
51d656433aSmrg
52d656433aSmrgstatic void
53d656433aSmrgset_callbacks(SmcConn smcConn, unsigned long mask, SmcCallbacks *callbacks);
54126a8a12Smrg
55126a8a12Smrg
56126a8a12SmrgSmcConn
57d656433aSmrgSmcOpenConnection(char *networkIdsList, SmPointer context,
58d656433aSmrg		  int xsmpMajorRev, int xsmpMinorRev,
59d656433aSmrg		  unsigned long mask, SmcCallbacks *callbacks,
60d656433aSmrg		  char *previousId, char **clientIdRet,
61d656433aSmrg		  int errorLength, char *errorStringRet)
62126a8a12Smrg{
63126a8a12Smrg    SmcConn			smcConn;
64126a8a12Smrg    IceConn			iceConn;
65126a8a12Smrg    char 			*ids;
66126a8a12Smrg    IceProtocolSetupStatus	setupstat;
67126a8a12Smrg    int				majorVersion;
68126a8a12Smrg    int				minorVersion;
69126a8a12Smrg    char			*vendor = NULL;
70126a8a12Smrg    char			*release = NULL;
71126a8a12Smrg    smRegisterClientMsg 	*pMsg;
72126a8a12Smrg    char 			*pData;
73126a8a12Smrg    int				extra, len;
74126a8a12Smrg    IceReplyWaitInfo		replyWait;
75126a8a12Smrg    _SmcRegisterClientReply	reply;
76126a8a12Smrg    Bool			gotReply, ioErrorOccured;
77126a8a12Smrg
78126a8a12Smrg    const char *auth_names[] = {"MIT-MAGIC-COOKIE-1"};
79126a8a12Smrg    IcePoAuthProc auth_procs[] = {_IcePoMagicCookie1Proc};
80126a8a12Smrg    int auth_count = 1;
81126a8a12Smrg
82126a8a12Smrg    IcePoVersionRec versions[] = {
83126a8a12Smrg        {SmProtoMajor, SmProtoMinor, _SmcProcessMessage}
84126a8a12Smrg    };
85126a8a12Smrg    int version_count = 1;
86126a8a12Smrg
87126a8a12Smrg
88126a8a12Smrg    *clientIdRet = NULL;
89126a8a12Smrg
90126a8a12Smrg    if (errorStringRet && errorLength > 0)
91126a8a12Smrg	*errorStringRet = '\0';
92126a8a12Smrg
93126a8a12Smrg    if (!_SmcOpcode)
94126a8a12Smrg    {
95126a8a12Smrg	/*
96126a8a12Smrg	 * For now, there is only one version of XSMP, so we don't
97126a8a12Smrg	 * have to check {xsmpMajorRev, xsmpMinorRev}.  In the future,
98126a8a12Smrg	 * we will check against versions and generate the list
99126a8a12Smrg	 * of versions the application actually supports.
100126a8a12Smrg	 */
101126a8a12Smrg
102126a8a12Smrg	if ((_SmcOpcode = IceRegisterForProtocolSetup ("XSMP",
103126a8a12Smrg	    SmVendorString, SmReleaseString, version_count, versions,
104126a8a12Smrg            auth_count, auth_names, auth_procs, NULL)) < 0)
105126a8a12Smrg	{
106126a8a12Smrg	    if (errorStringRet && errorLength > 0) {
107126a8a12Smrg		strncpy (errorStringRet,
108126a8a12Smrg			 "Could not register XSMP protocol with ICE",
109126a8a12Smrg			 errorLength);
110126a8a12Smrg		errorStringRet[errorLength - 1] = '\0';
111126a8a12Smrg	    }
112126a8a12Smrg
113126a8a12Smrg	    return (NULL);
114126a8a12Smrg	}
115126a8a12Smrg    }
116126a8a12Smrg
117126a8a12Smrg    if (networkIdsList == NULL || *networkIdsList == '\0')
118126a8a12Smrg    {
119126a8a12Smrg	if ((ids = (char *) getenv ("SESSION_MANAGER")) == NULL)
120126a8a12Smrg	{
121126a8a12Smrg	    if (errorStringRet && errorLength > 0) {
122126a8a12Smrg		strncpy (errorStringRet,
123126a8a12Smrg			 "SESSION_MANAGER environment variable not defined",
124126a8a12Smrg			 errorLength);
125126a8a12Smrg		errorStringRet[errorLength - 1] = '\0';
126126a8a12Smrg	    }
127126a8a12Smrg	    return (NULL);
128126a8a12Smrg	}
129126a8a12Smrg    }
130126a8a12Smrg    else
131126a8a12Smrg    {
132126a8a12Smrg	ids = networkIdsList;
133126a8a12Smrg    }
134126a8a12Smrg
135126a8a12Smrg    if ((iceConn = IceOpenConnection (
136126a8a12Smrg	ids, context, 0, _SmcOpcode, errorLength, errorStringRet)) == NULL)
137126a8a12Smrg    {
138126a8a12Smrg	return (NULL);
139126a8a12Smrg    }
140126a8a12Smrg
1413c15da26Smrg    if ((smcConn = malloc (sizeof (struct _SmcConn))) == NULL)
142126a8a12Smrg    {
143126a8a12Smrg	if (errorStringRet && errorLength > 0) {
144126a8a12Smrg	    strncpy (errorStringRet, "Can't malloc", errorLength);
145126a8a12Smrg	    errorStringRet[errorLength - 1] = '\0';
146126a8a12Smrg	}
147126a8a12Smrg	IceCloseConnection (iceConn);
148126a8a12Smrg	return (NULL);
149126a8a12Smrg    }
150126a8a12Smrg
151126a8a12Smrg    setupstat = IceProtocolSetup (iceConn, _SmcOpcode,
152126a8a12Smrg	(IcePointer) smcConn,
153126a8a12Smrg	False /* mustAuthenticate */,
154126a8a12Smrg	&majorVersion, &minorVersion,
155126a8a12Smrg	&vendor, &release, errorLength, errorStringRet);
156126a8a12Smrg
157126a8a12Smrg    if (setupstat == IceProtocolSetupFailure ||
158126a8a12Smrg	setupstat == IceProtocolSetupIOError)
159126a8a12Smrg    {
160126a8a12Smrg	IceCloseConnection (iceConn);
1613c15da26Smrg	free (smcConn);
162126a8a12Smrg	return (NULL);
163126a8a12Smrg    }
164126a8a12Smrg    else if (setupstat == IceProtocolAlreadyActive)
165126a8a12Smrg    {
166126a8a12Smrg	/*
167126a8a12Smrg	 * This case should never happen, because when we called
168126a8a12Smrg	 * IceOpenConnection, we required that the ICE connection
169126a8a12Smrg	 * may not already have XSMP active on it.
170126a8a12Smrg	 */
171126a8a12Smrg
1723c15da26Smrg	free (smcConn);
173126a8a12Smrg	if (errorStringRet && errorLength > 0) {
174126a8a12Smrg	    strncpy (errorStringRet, "Internal error in IceOpenConnection",
175126a8a12Smrg		     errorLength);
176126a8a12Smrg	    errorStringRet[errorLength - 1] = '\0';
177126a8a12Smrg	}
178126a8a12Smrg	return (NULL);
179126a8a12Smrg    }
180126a8a12Smrg
181126a8a12Smrg    smcConn->iceConn = iceConn;
182126a8a12Smrg    smcConn->proto_major_version = majorVersion;
183126a8a12Smrg    smcConn->proto_minor_version = minorVersion;
184126a8a12Smrg    smcConn->vendor = vendor;
185126a8a12Smrg    smcConn->release = release;
186126a8a12Smrg    smcConn->client_id = NULL;
187126a8a12Smrg
188126a8a12Smrg    bzero ((char *) &smcConn->callbacks, sizeof (SmcCallbacks));
189126a8a12Smrg    set_callbacks (smcConn, mask, callbacks);
190126a8a12Smrg
191126a8a12Smrg    smcConn->interact_waits = NULL;
192126a8a12Smrg    smcConn->phase2_wait = NULL;
193126a8a12Smrg    smcConn->prop_reply_waits = NULL;
194126a8a12Smrg
195126a8a12Smrg    smcConn->save_yourself_in_progress = False;
196126a8a12Smrg    smcConn->shutdown_in_progress = False;
197126a8a12Smrg
198126a8a12Smrg
199126a8a12Smrg    /*
200126a8a12Smrg     * Now register the client
201126a8a12Smrg     */
202126a8a12Smrg
203d656433aSmrg    if (!previousId)
204d656433aSmrg	previousId = "";
205d656433aSmrg    len = strlen (previousId);
206126a8a12Smrg    extra = ARRAY8_BYTES (len);
207126a8a12Smrg
208126a8a12Smrg    IceGetHeaderExtra (iceConn, _SmcOpcode, SM_RegisterClient,
209126a8a12Smrg	SIZEOF (smRegisterClientMsg), WORD64COUNT (extra),
210126a8a12Smrg	smRegisterClientMsg, pMsg, pData);
211126a8a12Smrg
212126a8a12Smrg    STORE_ARRAY8 (pData, len, previousId);
213126a8a12Smrg
214126a8a12Smrg    IceFlush (iceConn);
215126a8a12Smrg
216126a8a12Smrg    replyWait.sequence_of_request = IceLastSentSequenceNumber (iceConn);
217126a8a12Smrg    replyWait.major_opcode_of_request = _SmcOpcode;
218126a8a12Smrg    replyWait.minor_opcode_of_request = SM_RegisterClient;
219126a8a12Smrg    replyWait.reply = (IcePointer) &reply;
220126a8a12Smrg
221126a8a12Smrg    gotReply = False;
222126a8a12Smrg    ioErrorOccured = False;
223126a8a12Smrg
224126a8a12Smrg    while (!gotReply && !ioErrorOccured)
225126a8a12Smrg    {
226126a8a12Smrg	ioErrorOccured = (IceProcessMessages (
227126a8a12Smrg	    iceConn, &replyWait, &gotReply) == IceProcessMessagesIOError);
228126a8a12Smrg
229126a8a12Smrg	if (ioErrorOccured)
230126a8a12Smrg	{
231126a8a12Smrg	    if (errorStringRet && errorLength > 0) {
232126a8a12Smrg		strncpy (errorStringRet, "IO error occured opening connection",
233126a8a12Smrg			 errorLength);
234126a8a12Smrg		errorStringRet[errorLength - 1] = '\0';
235126a8a12Smrg	    }
236126a8a12Smrg	    free (smcConn->vendor);
237126a8a12Smrg	    free (smcConn->release);
2383c15da26Smrg	    free (smcConn);
239126a8a12Smrg
240126a8a12Smrg	    return (NULL);
241126a8a12Smrg	}
242126a8a12Smrg	else if (gotReply)
243126a8a12Smrg	{
244126a8a12Smrg	    if (reply.status == 1)
245126a8a12Smrg	    {
246126a8a12Smrg		/*
247126a8a12Smrg		 * The client successfully registered.
248126a8a12Smrg		 */
249126a8a12Smrg
250126a8a12Smrg		*clientIdRet = reply.client_id;
251126a8a12Smrg
2523c15da26Smrg		smcConn->client_id = strdup (*clientIdRet);
253126a8a12Smrg	    }
254126a8a12Smrg	    else
255126a8a12Smrg	    {
256126a8a12Smrg		/*
257126a8a12Smrg		 * Could not register the client because the previous ID
258126a8a12Smrg		 * was bad.  So now we register the client with the
259126a8a12Smrg		 * previous ID set to NULL.
260126a8a12Smrg		 */
261126a8a12Smrg
262126a8a12Smrg		extra = ARRAY8_BYTES (0);
263126a8a12Smrg
264126a8a12Smrg		IceGetHeaderExtra (iceConn, _SmcOpcode, SM_RegisterClient,
265126a8a12Smrg		    SIZEOF (smRegisterClientMsg), WORD64COUNT (extra),
266126a8a12Smrg		    smRegisterClientMsg, pMsg, pData);
267126a8a12Smrg
268d656433aSmrg		STORE_ARRAY8 (pData, 0, "");
269126a8a12Smrg
270126a8a12Smrg		IceFlush (iceConn);
271126a8a12Smrg
272126a8a12Smrg		replyWait.sequence_of_request =
273126a8a12Smrg		    IceLastSentSequenceNumber (iceConn);
274126a8a12Smrg
275126a8a12Smrg		gotReply = False;
276126a8a12Smrg	    }
277126a8a12Smrg	}
278126a8a12Smrg    }
279126a8a12Smrg
280126a8a12Smrg    return (smcConn);
281126a8a12Smrg}
282126a8a12Smrg
283126a8a12Smrg
284126a8a12Smrg
285126a8a12SmrgSmcCloseStatus
286d656433aSmrgSmcCloseConnection(SmcConn smcConn, int count, char **reasonMsgs)
287126a8a12Smrg{
288126a8a12Smrg    IceConn			iceConn = smcConn->iceConn;
289126a8a12Smrg    smCloseConnectionMsg 	*pMsg;
290126a8a12Smrg    char 			*pData;
291126a8a12Smrg    int				extra, i;
292126a8a12Smrg    IceCloseStatus	        closeStatus;
293126a8a12Smrg    SmcCloseStatus		statusRet;
294126a8a12Smrg
295126a8a12Smrg    extra = 8;
296126a8a12Smrg
297126a8a12Smrg    for (i = 0; i < count; i++)
298126a8a12Smrg	extra += ARRAY8_BYTES (strlen (reasonMsgs[i]));
299126a8a12Smrg
300126a8a12Smrg    IceGetHeaderExtra (iceConn, _SmcOpcode, SM_CloseConnection,
301126a8a12Smrg	SIZEOF (smCloseConnectionMsg), WORD64COUNT (extra),
302126a8a12Smrg	smCloseConnectionMsg, pMsg, pData);
303126a8a12Smrg
304126a8a12Smrg    STORE_CARD32 (pData, count);
305126a8a12Smrg    pData += 4;
306126a8a12Smrg
307126a8a12Smrg    for (i = 0; i < count; i++)
3083c15da26Smrg	STORE_ARRAY8 (pData, strlen (reasonMsgs[i]), reasonMsgs[i]);
309126a8a12Smrg
310126a8a12Smrg    IceFlush (iceConn);
311126a8a12Smrg
312126a8a12Smrg    IceProtocolShutdown (iceConn, _SmcOpcode);
313126a8a12Smrg    IceSetShutdownNegotiation (iceConn, False);
314126a8a12Smrg    closeStatus = IceCloseConnection (iceConn);
315126a8a12Smrg
316126a8a12Smrg    if (smcConn->vendor)
317126a8a12Smrg	free (smcConn->vendor);
318126a8a12Smrg
319126a8a12Smrg    if (smcConn->release)
320126a8a12Smrg	free (smcConn->release);
321126a8a12Smrg
322126a8a12Smrg    if (smcConn->client_id)
323126a8a12Smrg	free (smcConn->client_id);
324126a8a12Smrg
325126a8a12Smrg    if (smcConn->prop_reply_waits)
326126a8a12Smrg    {
327126a8a12Smrg	_SmcPropReplyWait *ptr = smcConn->prop_reply_waits;
328126a8a12Smrg	_SmcPropReplyWait *next;
329126a8a12Smrg
330126a8a12Smrg	while (ptr)
331126a8a12Smrg	{
332126a8a12Smrg	    next = ptr->next;
3333c15da26Smrg	    free (ptr);
334126a8a12Smrg	    ptr = next;
335126a8a12Smrg	}
3363c15da26Smrg
337126a8a12Smrg    }
338126a8a12Smrg
3393c15da26Smrg    free (smcConn);
340126a8a12Smrg
341126a8a12Smrg    if (closeStatus == IceClosedNow)
342126a8a12Smrg	statusRet = SmcClosedNow;
343126a8a12Smrg    else if (closeStatus == IceClosedASAP)
344126a8a12Smrg	statusRet = SmcClosedASAP;
345126a8a12Smrg    else
346126a8a12Smrg	statusRet = SmcConnectionInUse;
347126a8a12Smrg
348126a8a12Smrg    return (statusRet);
349126a8a12Smrg}
350126a8a12Smrg
351126a8a12Smrg
352126a8a12Smrg
353126a8a12Smrgvoid
354d656433aSmrgSmcModifyCallbacks(SmcConn smcConn, unsigned long mask, SmcCallbacks *callbacks)
355126a8a12Smrg{
356126a8a12Smrg    set_callbacks (smcConn, mask, callbacks);
357126a8a12Smrg}
358126a8a12Smrg
359126a8a12Smrg
360126a8a12Smrg
361126a8a12Smrgvoid
362d656433aSmrgSmcSetProperties(SmcConn smcConn, int numProps, SmProp **props)
363126a8a12Smrg{
364126a8a12Smrg    IceConn		iceConn = smcConn->iceConn;
365126a8a12Smrg    smSetPropertiesMsg	*pMsg;
366126a8a12Smrg    char		*pBuf;
367126a8a12Smrg    char		*pStart;
368126a8a12Smrg    int			bytes;
369126a8a12Smrg
370126a8a12Smrg    IceGetHeader (iceConn, _SmcOpcode, SM_SetProperties,
371126a8a12Smrg	SIZEOF (smSetPropertiesMsg), smSetPropertiesMsg, pMsg);
372126a8a12Smrg
373126a8a12Smrg    LISTOF_PROP_BYTES (numProps, props, bytes);
374126a8a12Smrg    pMsg->length += WORD64COUNT (bytes);
375126a8a12Smrg
376126a8a12Smrg    pBuf = pStart = IceAllocScratch (iceConn, bytes);
377d656433aSmrg    memset(pStart, 0, bytes);
378126a8a12Smrg
379126a8a12Smrg    STORE_LISTOF_PROPERTY (pBuf, numProps, props);
380126a8a12Smrg
381126a8a12Smrg    IceWriteData (iceConn, bytes, pStart);
382126a8a12Smrg    IceFlush (iceConn);
383126a8a12Smrg}
384126a8a12Smrg
385126a8a12Smrg
386126a8a12Smrg
387126a8a12Smrgvoid
388d656433aSmrgSmcDeleteProperties(SmcConn smcConn, int numProps, char **propNames)
389126a8a12Smrg{
390126a8a12Smrg    IceConn			iceConn = smcConn->iceConn;
391126a8a12Smrg    smDeletePropertiesMsg 	*pMsg;
392126a8a12Smrg    char 			*pData;
393126a8a12Smrg    int				extra, i;
394126a8a12Smrg
395126a8a12Smrg    extra = 8;
396126a8a12Smrg
397126a8a12Smrg    for (i = 0; i < numProps; i++)
398126a8a12Smrg	extra += ARRAY8_BYTES (strlen (propNames[i]));
399126a8a12Smrg
400126a8a12Smrg    IceGetHeaderExtra (iceConn, _SmcOpcode, SM_DeleteProperties,
401126a8a12Smrg	SIZEOF (smDeletePropertiesMsg), WORD64COUNT (extra),
402126a8a12Smrg	smDeletePropertiesMsg, pMsg, pData);
403126a8a12Smrg
404126a8a12Smrg    STORE_CARD32 (pData, numProps);
405126a8a12Smrg    pData += 4;
406126a8a12Smrg
407126a8a12Smrg    for (i = 0; i < numProps; i++)
4083c15da26Smrg	STORE_ARRAY8 (pData, strlen (propNames[i]), propNames[i]);
409126a8a12Smrg
410126a8a12Smrg    IceFlush (iceConn);
411126a8a12Smrg}
412126a8a12Smrg
413126a8a12Smrg
414126a8a12Smrg
415126a8a12SmrgStatus
416d656433aSmrgSmcGetProperties(SmcConn smcConn, SmcPropReplyProc propReplyProc,
417d656433aSmrg		 SmPointer clientData)
418126a8a12Smrg{
419126a8a12Smrg    IceConn		iceConn = smcConn->iceConn;
420126a8a12Smrg    _SmcPropReplyWait 	*wait, *ptr;
421126a8a12Smrg
4223c15da26Smrg    if ((wait = malloc (sizeof (_SmcPropReplyWait))) == NULL)
423126a8a12Smrg    {
424126a8a12Smrg	return (0);
425126a8a12Smrg    }
426126a8a12Smrg
427126a8a12Smrg    wait->prop_reply_proc = propReplyProc;
428126a8a12Smrg    wait->client_data = clientData;
429126a8a12Smrg    wait->next = NULL;
430126a8a12Smrg
431126a8a12Smrg    ptr = smcConn->prop_reply_waits;
432126a8a12Smrg    while (ptr && ptr->next)
433126a8a12Smrg	ptr = ptr->next;
434126a8a12Smrg
435126a8a12Smrg    if (ptr == NULL)
436126a8a12Smrg	smcConn->prop_reply_waits = wait;
437126a8a12Smrg    else
438126a8a12Smrg	ptr->next = wait;
439126a8a12Smrg
440126a8a12Smrg    IceSimpleMessage (iceConn, _SmcOpcode, SM_GetProperties);
441126a8a12Smrg    IceFlush (iceConn);
442126a8a12Smrg
443126a8a12Smrg    return (1);
444126a8a12Smrg}
445126a8a12Smrg
446126a8a12Smrg
447126a8a12Smrg
448126a8a12SmrgStatus
449d656433aSmrgSmcInteractRequest(SmcConn smcConn, int dialogType,
450d656433aSmrg		   SmcInteractProc interactProc, SmPointer clientData)
451126a8a12Smrg{
452126a8a12Smrg    IceConn			iceConn = smcConn->iceConn;
453126a8a12Smrg    smInteractRequestMsg	*pMsg;
454126a8a12Smrg    _SmcInteractWait 		*wait, *ptr;
455126a8a12Smrg
4563c15da26Smrg    if ((wait = malloc (sizeof (_SmcInteractWait))) == NULL)
457126a8a12Smrg    {
458126a8a12Smrg	return (0);
459126a8a12Smrg    }
460126a8a12Smrg
461126a8a12Smrg    wait->interact_proc = interactProc;
462126a8a12Smrg    wait->client_data = clientData;
463126a8a12Smrg    wait->next = NULL;
464126a8a12Smrg
465126a8a12Smrg    ptr = smcConn->interact_waits;
466126a8a12Smrg    while (ptr && ptr->next)
467126a8a12Smrg	ptr = ptr->next;
468126a8a12Smrg
469126a8a12Smrg    if (ptr == NULL)
470126a8a12Smrg	smcConn->interact_waits = wait;
471126a8a12Smrg    else
472126a8a12Smrg	ptr->next = wait;
473126a8a12Smrg
474126a8a12Smrg    IceGetHeader (iceConn, _SmcOpcode, SM_InteractRequest,
475126a8a12Smrg	SIZEOF (smInteractRequestMsg), smInteractRequestMsg, pMsg);
476126a8a12Smrg
477126a8a12Smrg    pMsg->dialogType = dialogType;
478126a8a12Smrg
479126a8a12Smrg    IceFlush (iceConn);
480126a8a12Smrg
481126a8a12Smrg    return (1);
482126a8a12Smrg}
483126a8a12Smrg
484126a8a12Smrg
485126a8a12Smrg
486126a8a12Smrgvoid
487d656433aSmrgSmcInteractDone(SmcConn smcConn, Bool cancelShutdown)
488126a8a12Smrg{
489126a8a12Smrg    IceConn		iceConn = smcConn->iceConn;
490126a8a12Smrg    smInteractDoneMsg	*pMsg;
491126a8a12Smrg
492126a8a12Smrg    IceGetHeader (iceConn, _SmcOpcode, SM_InteractDone,
493126a8a12Smrg	SIZEOF (smInteractDoneMsg), smInteractDoneMsg, pMsg);
494126a8a12Smrg
495126a8a12Smrg    pMsg->cancelShutdown = cancelShutdown;
496126a8a12Smrg
497126a8a12Smrg    IceFlush (iceConn);
498126a8a12Smrg}
499126a8a12Smrg
500126a8a12Smrg
501126a8a12Smrg
502126a8a12Smrgvoid
503d656433aSmrgSmcRequestSaveYourself(SmcConn smcConn, int saveType, Bool shutdown,
504d656433aSmrg		       int interactStyle, Bool fast, Bool global)
505126a8a12Smrg{
506126a8a12Smrg    IceConn			iceConn = smcConn->iceConn;
507126a8a12Smrg    smSaveYourselfRequestMsg	*pMsg;
508126a8a12Smrg
509126a8a12Smrg    IceGetHeader (iceConn, _SmcOpcode, SM_SaveYourselfRequest,
510126a8a12Smrg	SIZEOF (smSaveYourselfRequestMsg), smSaveYourselfRequestMsg, pMsg);
511126a8a12Smrg
512126a8a12Smrg    pMsg->saveType = saveType;
513126a8a12Smrg    pMsg->shutdown = shutdown;
514126a8a12Smrg    pMsg->interactStyle = interactStyle;
515126a8a12Smrg    pMsg->fast = fast;
516126a8a12Smrg    pMsg->global = global;
517126a8a12Smrg
518126a8a12Smrg    IceFlush (iceConn);
519126a8a12Smrg}
520126a8a12Smrg
521126a8a12Smrg
522126a8a12Smrg
523126a8a12SmrgStatus
524d656433aSmrgSmcRequestSaveYourselfPhase2(SmcConn smcConn,
525d656433aSmrg			     SmcSaveYourselfPhase2Proc saveYourselfPhase2Proc,
526d656433aSmrg			     SmPointer clientData)
527126a8a12Smrg{
528126a8a12Smrg    IceConn		iceConn = smcConn->iceConn;
529126a8a12Smrg    _SmcPhase2Wait 	*wait;
530126a8a12Smrg
531126a8a12Smrg    if (smcConn->phase2_wait)
532126a8a12Smrg	wait = smcConn->phase2_wait;
533126a8a12Smrg    else
534126a8a12Smrg    {
5353c15da26Smrg	if ((wait = malloc (sizeof (_SmcPhase2Wait))) == NULL)
536126a8a12Smrg	{
537126a8a12Smrg	    return (0);
538126a8a12Smrg	}
539126a8a12Smrg    }
540126a8a12Smrg
541126a8a12Smrg    wait->phase2_proc = saveYourselfPhase2Proc;
542126a8a12Smrg    wait->client_data = clientData;
543126a8a12Smrg
544126a8a12Smrg    smcConn->phase2_wait = wait;
545126a8a12Smrg
546126a8a12Smrg    IceSimpleMessage (iceConn, _SmcOpcode, SM_SaveYourselfPhase2Request);
547126a8a12Smrg    IceFlush (iceConn);
548126a8a12Smrg
549126a8a12Smrg    return (1);
550126a8a12Smrg}
551126a8a12Smrg
552126a8a12Smrg
553126a8a12Smrg
554126a8a12Smrgvoid
555d656433aSmrgSmcSaveYourselfDone(SmcConn smcConn, Bool success)
556126a8a12Smrg{
557126a8a12Smrg    IceConn			iceConn = smcConn->iceConn;
558126a8a12Smrg    smSaveYourselfDoneMsg	*pMsg;
559126a8a12Smrg
560126a8a12Smrg    IceGetHeader (iceConn, _SmcOpcode, SM_SaveYourselfDone,
561126a8a12Smrg	SIZEOF (smSaveYourselfDoneMsg), smSaveYourselfDoneMsg, pMsg);
562126a8a12Smrg
563126a8a12Smrg    pMsg->success = success;
564126a8a12Smrg
565126a8a12Smrg    IceFlush (iceConn);
566126a8a12Smrg}
567126a8a12Smrg
568126a8a12Smrg
569126a8a12Smrg
570126a8a12Smrgstatic void
571d656433aSmrgset_callbacks(SmcConn smcConn, unsigned long mask, SmcCallbacks *callbacks)
572126a8a12Smrg{
573126a8a12Smrg    if (mask & SmcSaveYourselfProcMask)
574126a8a12Smrg    {
575126a8a12Smrg	smcConn->callbacks.save_yourself.callback =
576126a8a12Smrg	    callbacks->save_yourself.callback;
577126a8a12Smrg	smcConn->callbacks.save_yourself.client_data =
578126a8a12Smrg	    callbacks->save_yourself.client_data;
579126a8a12Smrg    }
580126a8a12Smrg
581126a8a12Smrg    if (mask & SmcDieProcMask)
582126a8a12Smrg    {
583126a8a12Smrg	smcConn->callbacks.die.callback = callbacks->die.callback;
584126a8a12Smrg	smcConn->callbacks.die.client_data = callbacks->die.client_data;
585126a8a12Smrg    }
586126a8a12Smrg
587126a8a12Smrg    if (mask & SmcSaveCompleteProcMask)
588126a8a12Smrg    {
589126a8a12Smrg	smcConn->callbacks.save_complete.callback =
590126a8a12Smrg	    callbacks->save_complete.callback;
591126a8a12Smrg	smcConn->callbacks.save_complete.client_data =
592126a8a12Smrg	    callbacks->save_complete.client_data;
593126a8a12Smrg    }
594126a8a12Smrg
595126a8a12Smrg    if (mask & SmcShutdownCancelledProcMask)
596126a8a12Smrg    {
597126a8a12Smrg	smcConn->callbacks.shutdown_cancelled.callback =
598126a8a12Smrg	    callbacks->shutdown_cancelled.callback;
599126a8a12Smrg	smcConn->callbacks.shutdown_cancelled.client_data =
600126a8a12Smrg	    callbacks->shutdown_cancelled.client_data;
601126a8a12Smrg    }
602126a8a12Smrg}
603