sm_client.c revision 0a6b08f8
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
40d656433aSmrgSmsNewClientProc _SmsNewClientProc;
41d656433aSmrgSmPointer        _SmsNewClientData;
42d656433aSmrg
43d656433aSmrgSmcErrorHandler _SmcErrorHandler = _SmcDefaultErrorHandler;
44d656433aSmrgSmsErrorHandler _SmsErrorHandler = _SmsDefaultErrorHandler;
45d656433aSmrg
46d656433aSmrg
47d656433aSmrgstatic void
48d656433aSmrgset_callbacks(SmcConn smcConn, unsigned long mask, SmcCallbacks *callbacks);
49126a8a12Smrg
50126a8a12Smrg
51126a8a12SmrgSmcConn
52d656433aSmrgSmcOpenConnection(char *networkIdsList, SmPointer context,
53d656433aSmrg		  int xsmpMajorRev, int xsmpMinorRev,
54d656433aSmrg		  unsigned long mask, SmcCallbacks *callbacks,
550a6b08f8Smrg		  const char *previousId, char **clientIdRet,
56d656433aSmrg		  int errorLength, char *errorStringRet)
57126a8a12Smrg{
58126a8a12Smrg    SmcConn			smcConn;
59126a8a12Smrg    IceConn			iceConn;
60126a8a12Smrg    char 			*ids;
61126a8a12Smrg    IceProtocolSetupStatus	setupstat;
62126a8a12Smrg    int				majorVersion;
63126a8a12Smrg    int				minorVersion;
64126a8a12Smrg    char			*vendor = NULL;
65126a8a12Smrg    char			*release = NULL;
66126a8a12Smrg    smRegisterClientMsg 	*pMsg;
67126a8a12Smrg    char 			*pData;
680a6b08f8Smrg    unsigned int		extra, len;
69126a8a12Smrg    IceReplyWaitInfo		replyWait;
70126a8a12Smrg    _SmcRegisterClientReply	reply;
71126a8a12Smrg    Bool			gotReply, ioErrorOccured;
72126a8a12Smrg
73126a8a12Smrg    const char *auth_names[] = {"MIT-MAGIC-COOKIE-1"};
74126a8a12Smrg    IcePoAuthProc auth_procs[] = {_IcePoMagicCookie1Proc};
75126a8a12Smrg    int auth_count = 1;
76126a8a12Smrg
77126a8a12Smrg    IcePoVersionRec versions[] = {
78126a8a12Smrg        {SmProtoMajor, SmProtoMinor, _SmcProcessMessage}
79126a8a12Smrg    };
80126a8a12Smrg    int version_count = 1;
81126a8a12Smrg
82126a8a12Smrg
83126a8a12Smrg    *clientIdRet = NULL;
84126a8a12Smrg
85126a8a12Smrg    if (errorStringRet && errorLength > 0)
86126a8a12Smrg	*errorStringRet = '\0';
87126a8a12Smrg
88126a8a12Smrg    if (!_SmcOpcode)
89126a8a12Smrg    {
90126a8a12Smrg	/*
91126a8a12Smrg	 * For now, there is only one version of XSMP, so we don't
92126a8a12Smrg	 * have to check {xsmpMajorRev, xsmpMinorRev}.  In the future,
93126a8a12Smrg	 * we will check against versions and generate the list
94126a8a12Smrg	 * of versions the application actually supports.
95126a8a12Smrg	 */
96126a8a12Smrg
97126a8a12Smrg	if ((_SmcOpcode = IceRegisterForProtocolSetup ("XSMP",
98126a8a12Smrg	    SmVendorString, SmReleaseString, version_count, versions,
99126a8a12Smrg            auth_count, auth_names, auth_procs, NULL)) < 0)
100126a8a12Smrg	{
101126a8a12Smrg	    if (errorStringRet && errorLength > 0) {
102126a8a12Smrg		strncpy (errorStringRet,
103126a8a12Smrg			 "Could not register XSMP protocol with ICE",
104126a8a12Smrg			 errorLength);
105126a8a12Smrg		errorStringRet[errorLength - 1] = '\0';
106126a8a12Smrg	    }
107126a8a12Smrg
108126a8a12Smrg	    return (NULL);
109126a8a12Smrg	}
110126a8a12Smrg    }
111126a8a12Smrg
112126a8a12Smrg    if (networkIdsList == NULL || *networkIdsList == '\0')
113126a8a12Smrg    {
114126a8a12Smrg	if ((ids = (char *) getenv ("SESSION_MANAGER")) == NULL)
115126a8a12Smrg	{
116126a8a12Smrg	    if (errorStringRet && errorLength > 0) {
117126a8a12Smrg		strncpy (errorStringRet,
118126a8a12Smrg			 "SESSION_MANAGER environment variable not defined",
119126a8a12Smrg			 errorLength);
120126a8a12Smrg		errorStringRet[errorLength - 1] = '\0';
121126a8a12Smrg	    }
122126a8a12Smrg	    return (NULL);
123126a8a12Smrg	}
124126a8a12Smrg    }
125126a8a12Smrg    else
126126a8a12Smrg    {
127126a8a12Smrg	ids = networkIdsList;
128126a8a12Smrg    }
129126a8a12Smrg
130126a8a12Smrg    if ((iceConn = IceOpenConnection (
131126a8a12Smrg	ids, context, 0, _SmcOpcode, errorLength, errorStringRet)) == NULL)
132126a8a12Smrg    {
133126a8a12Smrg	return (NULL);
134126a8a12Smrg    }
135126a8a12Smrg
1363c15da26Smrg    if ((smcConn = malloc (sizeof (struct _SmcConn))) == NULL)
137126a8a12Smrg    {
138126a8a12Smrg	if (errorStringRet && errorLength > 0) {
139126a8a12Smrg	    strncpy (errorStringRet, "Can't malloc", errorLength);
140126a8a12Smrg	    errorStringRet[errorLength - 1] = '\0';
141126a8a12Smrg	}
142126a8a12Smrg	IceCloseConnection (iceConn);
143126a8a12Smrg	return (NULL);
144126a8a12Smrg    }
145126a8a12Smrg
146126a8a12Smrg    setupstat = IceProtocolSetup (iceConn, _SmcOpcode,
147126a8a12Smrg	(IcePointer) smcConn,
148126a8a12Smrg	False /* mustAuthenticate */,
149126a8a12Smrg	&majorVersion, &minorVersion,
150126a8a12Smrg	&vendor, &release, errorLength, errorStringRet);
151126a8a12Smrg
152126a8a12Smrg    if (setupstat == IceProtocolSetupFailure ||
153126a8a12Smrg	setupstat == IceProtocolSetupIOError)
154126a8a12Smrg    {
155126a8a12Smrg	IceCloseConnection (iceConn);
1563c15da26Smrg	free (smcConn);
157126a8a12Smrg	return (NULL);
158126a8a12Smrg    }
159126a8a12Smrg    else if (setupstat == IceProtocolAlreadyActive)
160126a8a12Smrg    {
161126a8a12Smrg	/*
162126a8a12Smrg	 * This case should never happen, because when we called
163126a8a12Smrg	 * IceOpenConnection, we required that the ICE connection
164126a8a12Smrg	 * may not already have XSMP active on it.
165126a8a12Smrg	 */
166126a8a12Smrg
1673c15da26Smrg	free (smcConn);
168126a8a12Smrg	if (errorStringRet && errorLength > 0) {
169126a8a12Smrg	    strncpy (errorStringRet, "Internal error in IceOpenConnection",
170126a8a12Smrg		     errorLength);
171126a8a12Smrg	    errorStringRet[errorLength - 1] = '\0';
172126a8a12Smrg	}
173126a8a12Smrg	return (NULL);
174126a8a12Smrg    }
175126a8a12Smrg
176126a8a12Smrg    smcConn->iceConn = iceConn;
177126a8a12Smrg    smcConn->proto_major_version = majorVersion;
178126a8a12Smrg    smcConn->proto_minor_version = minorVersion;
179126a8a12Smrg    smcConn->vendor = vendor;
180126a8a12Smrg    smcConn->release = release;
181126a8a12Smrg    smcConn->client_id = NULL;
182126a8a12Smrg
183126a8a12Smrg    bzero ((char *) &smcConn->callbacks, sizeof (SmcCallbacks));
184126a8a12Smrg    set_callbacks (smcConn, mask, callbacks);
185126a8a12Smrg
186126a8a12Smrg    smcConn->interact_waits = NULL;
187126a8a12Smrg    smcConn->phase2_wait = NULL;
188126a8a12Smrg    smcConn->prop_reply_waits = NULL;
189126a8a12Smrg
190126a8a12Smrg    smcConn->save_yourself_in_progress = False;
191126a8a12Smrg    smcConn->shutdown_in_progress = False;
192126a8a12Smrg
193126a8a12Smrg
194126a8a12Smrg    /*
195126a8a12Smrg     * Now register the client
196126a8a12Smrg     */
197126a8a12Smrg
198d656433aSmrg    if (!previousId)
199d656433aSmrg	previousId = "";
200d656433aSmrg    len = strlen (previousId);
201126a8a12Smrg    extra = ARRAY8_BYTES (len);
202126a8a12Smrg
203126a8a12Smrg    IceGetHeaderExtra (iceConn, _SmcOpcode, SM_RegisterClient,
204126a8a12Smrg	SIZEOF (smRegisterClientMsg), WORD64COUNT (extra),
205126a8a12Smrg	smRegisterClientMsg, pMsg, pData);
206126a8a12Smrg
207126a8a12Smrg    STORE_ARRAY8 (pData, len, previousId);
208126a8a12Smrg
209126a8a12Smrg    IceFlush (iceConn);
210126a8a12Smrg
211126a8a12Smrg    replyWait.sequence_of_request = IceLastSentSequenceNumber (iceConn);
212126a8a12Smrg    replyWait.major_opcode_of_request = _SmcOpcode;
213126a8a12Smrg    replyWait.minor_opcode_of_request = SM_RegisterClient;
214126a8a12Smrg    replyWait.reply = (IcePointer) &reply;
215126a8a12Smrg
216126a8a12Smrg    gotReply = False;
217126a8a12Smrg    ioErrorOccured = False;
218126a8a12Smrg
219126a8a12Smrg    while (!gotReply && !ioErrorOccured)
220126a8a12Smrg    {
221126a8a12Smrg	ioErrorOccured = (IceProcessMessages (
222126a8a12Smrg	    iceConn, &replyWait, &gotReply) == IceProcessMessagesIOError);
223126a8a12Smrg
224126a8a12Smrg	if (ioErrorOccured)
225126a8a12Smrg	{
226126a8a12Smrg	    if (errorStringRet && errorLength > 0) {
227126a8a12Smrg		strncpy (errorStringRet, "IO error occured opening connection",
228126a8a12Smrg			 errorLength);
229126a8a12Smrg		errorStringRet[errorLength - 1] = '\0';
230126a8a12Smrg	    }
231126a8a12Smrg	    free (smcConn->vendor);
232126a8a12Smrg	    free (smcConn->release);
2333c15da26Smrg	    free (smcConn);
234126a8a12Smrg
235126a8a12Smrg	    return (NULL);
236126a8a12Smrg	}
237126a8a12Smrg	else if (gotReply)
238126a8a12Smrg	{
239126a8a12Smrg	    if (reply.status == 1)
240126a8a12Smrg	    {
241126a8a12Smrg		/*
242126a8a12Smrg		 * The client successfully registered.
243126a8a12Smrg		 */
244126a8a12Smrg
245126a8a12Smrg		*clientIdRet = reply.client_id;
246126a8a12Smrg
2473c15da26Smrg		smcConn->client_id = strdup (*clientIdRet);
248126a8a12Smrg	    }
249126a8a12Smrg	    else
250126a8a12Smrg	    {
251126a8a12Smrg		/*
252126a8a12Smrg		 * Could not register the client because the previous ID
253126a8a12Smrg		 * was bad.  So now we register the client with the
254126a8a12Smrg		 * previous ID set to NULL.
255126a8a12Smrg		 */
256126a8a12Smrg
257126a8a12Smrg		extra = ARRAY8_BYTES (0);
258126a8a12Smrg
259126a8a12Smrg		IceGetHeaderExtra (iceConn, _SmcOpcode, SM_RegisterClient,
260126a8a12Smrg		    SIZEOF (smRegisterClientMsg), WORD64COUNT (extra),
261126a8a12Smrg		    smRegisterClientMsg, pMsg, pData);
262126a8a12Smrg
263d656433aSmrg		STORE_ARRAY8 (pData, 0, "");
264126a8a12Smrg
265126a8a12Smrg		IceFlush (iceConn);
266126a8a12Smrg
267126a8a12Smrg		replyWait.sequence_of_request =
268126a8a12Smrg		    IceLastSentSequenceNumber (iceConn);
269126a8a12Smrg
270126a8a12Smrg		gotReply = False;
271126a8a12Smrg	    }
272126a8a12Smrg	}
273126a8a12Smrg    }
274126a8a12Smrg
275126a8a12Smrg    return (smcConn);
276126a8a12Smrg}
277126a8a12Smrg
278126a8a12Smrg
279126a8a12Smrg
280126a8a12SmrgSmcCloseStatus
281d656433aSmrgSmcCloseConnection(SmcConn smcConn, int count, char **reasonMsgs)
282126a8a12Smrg{
283126a8a12Smrg    IceConn			iceConn = smcConn->iceConn;
284126a8a12Smrg    smCloseConnectionMsg 	*pMsg;
285126a8a12Smrg    char 			*pData;
286126a8a12Smrg    int				extra, i;
287126a8a12Smrg    IceCloseStatus	        closeStatus;
288126a8a12Smrg    SmcCloseStatus		statusRet;
289126a8a12Smrg
290126a8a12Smrg    extra = 8;
291126a8a12Smrg
292126a8a12Smrg    for (i = 0; i < count; i++)
293126a8a12Smrg	extra += ARRAY8_BYTES (strlen (reasonMsgs[i]));
294126a8a12Smrg
295126a8a12Smrg    IceGetHeaderExtra (iceConn, _SmcOpcode, SM_CloseConnection,
296126a8a12Smrg	SIZEOF (smCloseConnectionMsg), WORD64COUNT (extra),
297126a8a12Smrg	smCloseConnectionMsg, pMsg, pData);
298126a8a12Smrg
2990a6b08f8Smrg    STORE_CARD32 (pData, (CARD32) count);
300126a8a12Smrg    pData += 4;
301126a8a12Smrg
302126a8a12Smrg    for (i = 0; i < count; i++)
3033c15da26Smrg	STORE_ARRAY8 (pData, strlen (reasonMsgs[i]), reasonMsgs[i]);
304126a8a12Smrg
305126a8a12Smrg    IceFlush (iceConn);
306126a8a12Smrg
307126a8a12Smrg    IceProtocolShutdown (iceConn, _SmcOpcode);
308126a8a12Smrg    IceSetShutdownNegotiation (iceConn, False);
309126a8a12Smrg    closeStatus = IceCloseConnection (iceConn);
310126a8a12Smrg
311126a8a12Smrg    if (smcConn->vendor)
312126a8a12Smrg	free (smcConn->vendor);
313126a8a12Smrg
314126a8a12Smrg    if (smcConn->release)
315126a8a12Smrg	free (smcConn->release);
316126a8a12Smrg
317126a8a12Smrg    if (smcConn->client_id)
318126a8a12Smrg	free (smcConn->client_id);
319126a8a12Smrg
320126a8a12Smrg    if (smcConn->prop_reply_waits)
321126a8a12Smrg    {
322126a8a12Smrg	_SmcPropReplyWait *ptr = smcConn->prop_reply_waits;
323126a8a12Smrg	_SmcPropReplyWait *next;
324126a8a12Smrg
325126a8a12Smrg	while (ptr)
326126a8a12Smrg	{
327126a8a12Smrg	    next = ptr->next;
3283c15da26Smrg	    free (ptr);
329126a8a12Smrg	    ptr = next;
330126a8a12Smrg	}
3313c15da26Smrg
332126a8a12Smrg    }
333126a8a12Smrg
3343c15da26Smrg    free (smcConn);
335126a8a12Smrg
336126a8a12Smrg    if (closeStatus == IceClosedNow)
337126a8a12Smrg	statusRet = SmcClosedNow;
338126a8a12Smrg    else if (closeStatus == IceClosedASAP)
339126a8a12Smrg	statusRet = SmcClosedASAP;
340126a8a12Smrg    else
341126a8a12Smrg	statusRet = SmcConnectionInUse;
342126a8a12Smrg
343126a8a12Smrg    return (statusRet);
344126a8a12Smrg}
345126a8a12Smrg
346126a8a12Smrg
347126a8a12Smrg
348126a8a12Smrgvoid
349d656433aSmrgSmcModifyCallbacks(SmcConn smcConn, unsigned long mask, SmcCallbacks *callbacks)
350126a8a12Smrg{
351126a8a12Smrg    set_callbacks (smcConn, mask, callbacks);
352126a8a12Smrg}
353126a8a12Smrg
354126a8a12Smrg
355126a8a12Smrg
356126a8a12Smrgvoid
357d656433aSmrgSmcSetProperties(SmcConn smcConn, int numProps, SmProp **props)
358126a8a12Smrg{
359126a8a12Smrg    IceConn		iceConn = smcConn->iceConn;
360126a8a12Smrg    smSetPropertiesMsg	*pMsg;
361126a8a12Smrg    char		*pBuf;
362126a8a12Smrg    char		*pStart;
3630a6b08f8Smrg    unsigned int	bytes;
364126a8a12Smrg
365126a8a12Smrg    IceGetHeader (iceConn, _SmcOpcode, SM_SetProperties,
366126a8a12Smrg	SIZEOF (smSetPropertiesMsg), smSetPropertiesMsg, pMsg);
367126a8a12Smrg
368126a8a12Smrg    LISTOF_PROP_BYTES (numProps, props, bytes);
369126a8a12Smrg    pMsg->length += WORD64COUNT (bytes);
370126a8a12Smrg
371126a8a12Smrg    pBuf = pStart = IceAllocScratch (iceConn, bytes);
372d656433aSmrg    memset(pStart, 0, bytes);
373126a8a12Smrg
374126a8a12Smrg    STORE_LISTOF_PROPERTY (pBuf, numProps, props);
375126a8a12Smrg
376126a8a12Smrg    IceWriteData (iceConn, bytes, pStart);
377126a8a12Smrg    IceFlush (iceConn);
378126a8a12Smrg}
379126a8a12Smrg
380126a8a12Smrg
381126a8a12Smrg
382126a8a12Smrgvoid
383d656433aSmrgSmcDeleteProperties(SmcConn smcConn, int numProps, char **propNames)
384126a8a12Smrg{
385126a8a12Smrg    IceConn			iceConn = smcConn->iceConn;
386126a8a12Smrg    smDeletePropertiesMsg 	*pMsg;
387126a8a12Smrg    char 			*pData;
388126a8a12Smrg    int				extra, i;
389126a8a12Smrg
390126a8a12Smrg    extra = 8;
391126a8a12Smrg
392126a8a12Smrg    for (i = 0; i < numProps; i++)
393126a8a12Smrg	extra += ARRAY8_BYTES (strlen (propNames[i]));
394126a8a12Smrg
395126a8a12Smrg    IceGetHeaderExtra (iceConn, _SmcOpcode, SM_DeleteProperties,
396126a8a12Smrg	SIZEOF (smDeletePropertiesMsg), WORD64COUNT (extra),
397126a8a12Smrg	smDeletePropertiesMsg, pMsg, pData);
398126a8a12Smrg
399126a8a12Smrg    STORE_CARD32 (pData, numProps);
400126a8a12Smrg    pData += 4;
401126a8a12Smrg
402126a8a12Smrg    for (i = 0; i < numProps; i++)
4033c15da26Smrg	STORE_ARRAY8 (pData, strlen (propNames[i]), propNames[i]);
404126a8a12Smrg
405126a8a12Smrg    IceFlush (iceConn);
406126a8a12Smrg}
407126a8a12Smrg
408126a8a12Smrg
409126a8a12Smrg
410126a8a12SmrgStatus
411d656433aSmrgSmcGetProperties(SmcConn smcConn, SmcPropReplyProc propReplyProc,
412d656433aSmrg		 SmPointer clientData)
413126a8a12Smrg{
414126a8a12Smrg    IceConn		iceConn = smcConn->iceConn;
415126a8a12Smrg    _SmcPropReplyWait 	*wait, *ptr;
416126a8a12Smrg
4173c15da26Smrg    if ((wait = malloc (sizeof (_SmcPropReplyWait))) == NULL)
418126a8a12Smrg    {
419126a8a12Smrg	return (0);
420126a8a12Smrg    }
421126a8a12Smrg
422126a8a12Smrg    wait->prop_reply_proc = propReplyProc;
423126a8a12Smrg    wait->client_data = clientData;
424126a8a12Smrg    wait->next = NULL;
425126a8a12Smrg
426126a8a12Smrg    ptr = smcConn->prop_reply_waits;
427126a8a12Smrg    while (ptr && ptr->next)
428126a8a12Smrg	ptr = ptr->next;
429126a8a12Smrg
430126a8a12Smrg    if (ptr == NULL)
431126a8a12Smrg	smcConn->prop_reply_waits = wait;
432126a8a12Smrg    else
433126a8a12Smrg	ptr->next = wait;
434126a8a12Smrg
435126a8a12Smrg    IceSimpleMessage (iceConn, _SmcOpcode, SM_GetProperties);
436126a8a12Smrg    IceFlush (iceConn);
437126a8a12Smrg
438126a8a12Smrg    return (1);
439126a8a12Smrg}
440126a8a12Smrg
441126a8a12Smrg
442126a8a12Smrg
443126a8a12SmrgStatus
444d656433aSmrgSmcInteractRequest(SmcConn smcConn, int dialogType,
445d656433aSmrg		   SmcInteractProc interactProc, SmPointer clientData)
446126a8a12Smrg{
447126a8a12Smrg    IceConn			iceConn = smcConn->iceConn;
448126a8a12Smrg    smInteractRequestMsg	*pMsg;
449126a8a12Smrg    _SmcInteractWait 		*wait, *ptr;
450126a8a12Smrg
4513c15da26Smrg    if ((wait = malloc (sizeof (_SmcInteractWait))) == NULL)
452126a8a12Smrg    {
453126a8a12Smrg	return (0);
454126a8a12Smrg    }
455126a8a12Smrg
456126a8a12Smrg    wait->interact_proc = interactProc;
457126a8a12Smrg    wait->client_data = clientData;
458126a8a12Smrg    wait->next = NULL;
459126a8a12Smrg
460126a8a12Smrg    ptr = smcConn->interact_waits;
461126a8a12Smrg    while (ptr && ptr->next)
462126a8a12Smrg	ptr = ptr->next;
463126a8a12Smrg
464126a8a12Smrg    if (ptr == NULL)
465126a8a12Smrg	smcConn->interact_waits = wait;
466126a8a12Smrg    else
467126a8a12Smrg	ptr->next = wait;
468126a8a12Smrg
469126a8a12Smrg    IceGetHeader (iceConn, _SmcOpcode, SM_InteractRequest,
470126a8a12Smrg	SIZEOF (smInteractRequestMsg), smInteractRequestMsg, pMsg);
471126a8a12Smrg
472126a8a12Smrg    pMsg->dialogType = dialogType;
473126a8a12Smrg
474126a8a12Smrg    IceFlush (iceConn);
475126a8a12Smrg
476126a8a12Smrg    return (1);
477126a8a12Smrg}
478126a8a12Smrg
479126a8a12Smrg
480126a8a12Smrg
481126a8a12Smrgvoid
482d656433aSmrgSmcInteractDone(SmcConn smcConn, Bool cancelShutdown)
483126a8a12Smrg{
484126a8a12Smrg    IceConn		iceConn = smcConn->iceConn;
485126a8a12Smrg    smInteractDoneMsg	*pMsg;
486126a8a12Smrg
487126a8a12Smrg    IceGetHeader (iceConn, _SmcOpcode, SM_InteractDone,
488126a8a12Smrg	SIZEOF (smInteractDoneMsg), smInteractDoneMsg, pMsg);
489126a8a12Smrg
490126a8a12Smrg    pMsg->cancelShutdown = cancelShutdown;
491126a8a12Smrg
492126a8a12Smrg    IceFlush (iceConn);
493126a8a12Smrg}
494126a8a12Smrg
495126a8a12Smrg
496126a8a12Smrg
497126a8a12Smrgvoid
498d656433aSmrgSmcRequestSaveYourself(SmcConn smcConn, int saveType, Bool shutdown,
499d656433aSmrg		       int interactStyle, Bool fast, Bool global)
500126a8a12Smrg{
501126a8a12Smrg    IceConn			iceConn = smcConn->iceConn;
502126a8a12Smrg    smSaveYourselfRequestMsg	*pMsg;
503126a8a12Smrg
504126a8a12Smrg    IceGetHeader (iceConn, _SmcOpcode, SM_SaveYourselfRequest,
505126a8a12Smrg	SIZEOF (smSaveYourselfRequestMsg), smSaveYourselfRequestMsg, pMsg);
506126a8a12Smrg
507126a8a12Smrg    pMsg->saveType = saveType;
508126a8a12Smrg    pMsg->shutdown = shutdown;
509126a8a12Smrg    pMsg->interactStyle = interactStyle;
510126a8a12Smrg    pMsg->fast = fast;
511126a8a12Smrg    pMsg->global = global;
512126a8a12Smrg
513126a8a12Smrg    IceFlush (iceConn);
514126a8a12Smrg}
515126a8a12Smrg
516126a8a12Smrg
517126a8a12Smrg
518126a8a12SmrgStatus
519d656433aSmrgSmcRequestSaveYourselfPhase2(SmcConn smcConn,
520d656433aSmrg			     SmcSaveYourselfPhase2Proc saveYourselfPhase2Proc,
521d656433aSmrg			     SmPointer clientData)
522126a8a12Smrg{
523126a8a12Smrg    IceConn		iceConn = smcConn->iceConn;
524126a8a12Smrg    _SmcPhase2Wait 	*wait;
525126a8a12Smrg
526126a8a12Smrg    if (smcConn->phase2_wait)
527126a8a12Smrg	wait = smcConn->phase2_wait;
528126a8a12Smrg    else
529126a8a12Smrg    {
5303c15da26Smrg	if ((wait = malloc (sizeof (_SmcPhase2Wait))) == NULL)
531126a8a12Smrg	{
532126a8a12Smrg	    return (0);
533126a8a12Smrg	}
534126a8a12Smrg    }
535126a8a12Smrg
536126a8a12Smrg    wait->phase2_proc = saveYourselfPhase2Proc;
537126a8a12Smrg    wait->client_data = clientData;
538126a8a12Smrg
539126a8a12Smrg    smcConn->phase2_wait = wait;
540126a8a12Smrg
541126a8a12Smrg    IceSimpleMessage (iceConn, _SmcOpcode, SM_SaveYourselfPhase2Request);
542126a8a12Smrg    IceFlush (iceConn);
543126a8a12Smrg
544126a8a12Smrg    return (1);
545126a8a12Smrg}
546126a8a12Smrg
547126a8a12Smrg
548126a8a12Smrg
549126a8a12Smrgvoid
550d656433aSmrgSmcSaveYourselfDone(SmcConn smcConn, Bool success)
551126a8a12Smrg{
552126a8a12Smrg    IceConn			iceConn = smcConn->iceConn;
553126a8a12Smrg    smSaveYourselfDoneMsg	*pMsg;
554126a8a12Smrg
555126a8a12Smrg    IceGetHeader (iceConn, _SmcOpcode, SM_SaveYourselfDone,
556126a8a12Smrg	SIZEOF (smSaveYourselfDoneMsg), smSaveYourselfDoneMsg, pMsg);
557126a8a12Smrg
558126a8a12Smrg    pMsg->success = success;
559126a8a12Smrg
560126a8a12Smrg    IceFlush (iceConn);
561126a8a12Smrg}
562126a8a12Smrg
563126a8a12Smrg
564126a8a12Smrg
565126a8a12Smrgstatic void
566d656433aSmrgset_callbacks(SmcConn smcConn, unsigned long mask, SmcCallbacks *callbacks)
567126a8a12Smrg{
568126a8a12Smrg    if (mask & SmcSaveYourselfProcMask)
569126a8a12Smrg    {
570126a8a12Smrg	smcConn->callbacks.save_yourself.callback =
571126a8a12Smrg	    callbacks->save_yourself.callback;
572126a8a12Smrg	smcConn->callbacks.save_yourself.client_data =
573126a8a12Smrg	    callbacks->save_yourself.client_data;
574126a8a12Smrg    }
575126a8a12Smrg
576126a8a12Smrg    if (mask & SmcDieProcMask)
577126a8a12Smrg    {
578126a8a12Smrg	smcConn->callbacks.die.callback = callbacks->die.callback;
579126a8a12Smrg	smcConn->callbacks.die.client_data = callbacks->die.client_data;
580126a8a12Smrg    }
581126a8a12Smrg
582126a8a12Smrg    if (mask & SmcSaveCompleteProcMask)
583126a8a12Smrg    {
584126a8a12Smrg	smcConn->callbacks.save_complete.callback =
585126a8a12Smrg	    callbacks->save_complete.callback;
586126a8a12Smrg	smcConn->callbacks.save_complete.client_data =
587126a8a12Smrg	    callbacks->save_complete.client_data;
588126a8a12Smrg    }
589126a8a12Smrg
590126a8a12Smrg    if (mask & SmcShutdownCancelledProcMask)
591126a8a12Smrg    {
592126a8a12Smrg	smcConn->callbacks.shutdown_cancelled.callback =
593126a8a12Smrg	    callbacks->shutdown_cancelled.callback;
594126a8a12Smrg	smcConn->callbacks.shutdown_cancelled.client_data =
595126a8a12Smrg	    callbacks->shutdown_cancelled.client_data;
596126a8a12Smrg    }
597126a8a12Smrg}
598