1/*
2
3Copyright 1993, 1998  The Open Group
4
5Permission to use, copy, modify, distribute, and sell this software and its
6documentation for any purpose is hereby granted without fee, provided that
7the above copyright notice appear in all copies and that both that
8copyright notice and this permission notice appear in supporting
9documentation.
10
11The above copyright notice and this permission notice shall be included in
12all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
21Except as contained in this notice, the name of The Open Group shall not be
22used in advertising or otherwise to promote the sale, use or other dealings
23in this Software without prior written authorization from The Open Group.
24
25*/
26
27/*
28 * Author: Ralph Mor, X Consortium
29 */
30
31#ifdef HAVE_CONFIG_H
32#include <config.h>
33#endif
34#include <X11/SM/SMlib.h>
35#include "SMlibint.h"
36#include <X11/Xtrans/Xtrans.h>
37
38static Status
39_SmsProtocolSetupProc (IceConn    iceConn,
40		       int majorVersion,
41		       int minorVersion,
42		       char *vendor,
43		       char *release,
44		       IcePointer *clientDataRet,
45		       char **failureReasonRet)
46{
47    SmsConn  		smsConn;
48    unsigned long 	mask;
49    Status		status;
50
51    /*
52     * vendor/release are undefined for ProtocolSetup in XSMP.
53     */
54
55    if (vendor)
56	free (vendor);
57    if (release)
58	free (release);
59
60
61    /*
62     * Allocate new SmsConn.
63     */
64
65    if ((smsConn = malloc (sizeof (struct _SmsConn))) == NULL)
66    {
67	const char *str = "Memory allocation failed";
68
69	*failureReasonRet = strdup (str);
70
71	return (0);
72    }
73
74    smsConn->iceConn = iceConn;
75    smsConn->proto_major_version = majorVersion;
76    smsConn->proto_minor_version = minorVersion;
77    smsConn->client_id = NULL;
78
79    smsConn->save_yourself_in_progress = False;
80    smsConn->interaction_allowed = SmInteractStyleNone;
81    smsConn->can_cancel_shutdown = False;
82    smsConn->interact_in_progress = False;
83
84    *clientDataRet = (IcePointer) smsConn;
85
86
87    /*
88     * Now give the session manager the new smsConn and get back the
89     * callbacks to invoke when messages arrive from the client.
90     *
91     * In the future, we can use the mask return value to check
92     * if the SM is expecting an older rev of SMlib.
93     */
94
95    bzero ((char *) &smsConn->callbacks, sizeof (SmsCallbacks));
96
97    status = (*_SmsNewClientProc) (smsConn, _SmsNewClientData,
98	&mask, &smsConn->callbacks, failureReasonRet);
99
100    return (status);
101}
102
103
104
105
106Status
107SmsInitialize(const char *vendor, const char *release,
108	      SmsNewClientProc newClientProc,
109	      SmPointer managerData, IceHostBasedAuthProc hostBasedAuthProc,
110	      int errorLength, char *errorStringRet)
111{
112    const char *auth_names[] = {"MIT-MAGIC-COOKIE-1"};
113    IcePaAuthProc auth_procs[] = {_IcePaMagicCookie1Proc};
114    int auth_count = 1;
115
116    IcePaVersionRec versions[] = {
117        {SmProtoMajor, SmProtoMinor, _SmsProcessMessage}
118    };
119    int version_count = 1;
120
121    if (errorStringRet && errorLength > 0)
122	*errorStringRet = '\0';
123
124    if (!newClientProc)
125    {
126	if (errorStringRet && errorLength > 0) {
127	    strncpy (errorStringRet,
128		     "The SmsNewClientProc callback can't be NULL",
129		     errorLength);
130	    errorStringRet[errorLength - 1] = '\0';
131	}
132
133	return (0);
134    }
135
136    if (!_SmsOpcode)
137    {
138
139	if ((_SmsOpcode = IceRegisterForProtocolReply ("XSMP",
140	    vendor, release, version_count, versions,
141	    auth_count, auth_names, auth_procs, hostBasedAuthProc,
142	    _SmsProtocolSetupProc,
143	    NULL,	/* IceProtocolActivateProc - we don't care about
144			   when the Protocol Reply is sent, because the
145			   session manager can not immediately send a
146			   message - it must wait for RegisterClient. */
147	    NULL	/* IceIOErrorProc */
148            )) < 0)
149	{
150	    if (errorStringRet && errorLength > 0) {
151		strncpy (errorStringRet,
152			 "Could not register XSMP protocol with ICE",
153			 errorLength);
154		errorStringRet[errorLength - 1] = '\0';
155	    }
156	    return (0);
157	}
158    }
159
160    _SmsNewClientProc = newClientProc;
161    _SmsNewClientData = managerData;
162
163    return (1);
164}
165
166
167
168char *
169SmsClientHostName(SmsConn smsConn)
170{
171    return (IceGetPeerName (smsConn->iceConn));
172}
173
174
175
176Status
177SmsRegisterClientReply(SmsConn smsConn, char *clientId)
178{
179    IceConn			iceConn = smsConn->iceConn;
180    size_t			extra;
181    smRegisterClientReplyMsg 	*pMsg;
182    char 			*pData;
183
184    if ((smsConn->client_id = strdup (clientId)) == NULL)
185    {
186	return (0);
187    }
188
189    extra = ARRAY8_BYTES (strlen (clientId));
190
191    IceGetHeaderExtra (iceConn, _SmsOpcode, SM_RegisterClientReply,
192	SIZEOF (smRegisterClientReplyMsg), WORD64COUNT (extra),
193	smRegisterClientReplyMsg, pMsg, pData);
194
195    if (pData != NULL) {
196        STORE_ARRAY8 (pData, strlen (clientId), clientId);
197        IceFlush (iceConn);
198    }
199    else {
200        SEND_ARRAY8 (iceConn, strlen (clientId), clientId);
201    }
202
203    return (1);
204}
205
206
207
208void
209SmsSaveYourself(SmsConn smsConn, int saveType, Bool shutdown,
210		int interactStyle, Bool fast)
211{
212    IceConn		iceConn = smsConn->iceConn;
213    smSaveYourselfMsg	*pMsg;
214
215    IceGetHeader (iceConn, _SmsOpcode, SM_SaveYourself,
216	SIZEOF (smSaveYourselfMsg), smSaveYourselfMsg, pMsg);
217
218    pMsg->saveType = saveType;
219    pMsg->shutdown = shutdown;
220    pMsg->interactStyle = interactStyle;
221    pMsg->fast = fast;
222
223    IceFlush (iceConn);
224
225    smsConn->save_yourself_in_progress = True;
226
227    if (interactStyle == SmInteractStyleNone ||
228	interactStyle == SmInteractStyleErrors ||
229	interactStyle == SmInteractStyleAny)
230    {
231	smsConn->interaction_allowed = interactStyle;
232    }
233    else
234    {
235	smsConn->interaction_allowed = SmInteractStyleNone;
236    }
237
238    smsConn->can_cancel_shutdown = shutdown &&
239	(interactStyle == SmInteractStyleAny ||
240	interactStyle == SmInteractStyleErrors);
241}
242
243
244
245void
246SmsSaveYourselfPhase2(SmsConn smsConn)
247{
248    IceConn	iceConn = smsConn->iceConn;
249
250    IceSimpleMessage (iceConn, _SmsOpcode, SM_SaveYourselfPhase2);
251    IceFlush (iceConn);
252}
253
254
255
256void
257SmsInteract(SmsConn smsConn)
258{
259    IceConn	iceConn = smsConn->iceConn;
260
261    IceSimpleMessage (iceConn, _SmsOpcode, SM_Interact);
262    IceFlush (iceConn);
263
264    smsConn->interact_in_progress = True;
265}
266
267
268
269void
270SmsDie(SmsConn smsConn)
271{
272    IceConn	iceConn = smsConn->iceConn;
273
274    IceSimpleMessage (iceConn, _SmsOpcode, SM_Die);
275    IceFlush (iceConn);
276}
277
278
279
280void
281SmsSaveComplete(SmsConn smsConn)
282{
283    IceConn	iceConn = smsConn->iceConn;
284
285    IceSimpleMessage (iceConn, _SmsOpcode, SM_SaveComplete);
286    IceFlush (iceConn);
287}
288
289
290
291void
292SmsShutdownCancelled(SmsConn smsConn)
293{
294    IceConn	iceConn = smsConn->iceConn;
295
296    IceSimpleMessage (iceConn, _SmsOpcode, SM_ShutdownCancelled);
297    IceFlush (iceConn);
298
299    smsConn->can_cancel_shutdown = False;
300}
301
302
303
304void
305SmsReturnProperties(SmsConn smsConn, int numProps, SmProp **props)
306{
307    IceConn			iceConn = smsConn->iceConn;
308    unsigned int		bytes;
309    smPropertiesReplyMsg	*pMsg;
310    char 			*pBuf;
311    char			*pStart;
312
313    IceGetHeader (iceConn, _SmsOpcode, SM_PropertiesReply,
314	SIZEOF (smPropertiesReplyMsg), smPropertiesReplyMsg, pMsg);
315
316    LISTOF_PROP_BYTES (numProps, props, bytes);
317    pMsg->length += WORD64COUNT (bytes);
318
319    pBuf = pStart = IceAllocScratch (iceConn, bytes);
320
321    STORE_LISTOF_PROPERTY (pBuf, numProps, props);
322
323    IceWriteData (iceConn, bytes, pStart);
324    IceFlush (iceConn);
325}
326
327
328
329void
330SmsCleanUp(SmsConn smsConn)
331{
332    IceProtocolShutdown (smsConn->iceConn, _SmsOpcode);
333
334    if (smsConn->client_id)
335	free (smsConn->client_id);
336
337    free (smsConn);
338}
339