sm_process.c revision 0a6b08f8
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
37
38/*
39 * Check for bad length
40 */
41
42#define CHECK_SIZE_MATCH(_iceConn, _majorOp, _minorOp, _expected_len, _actual_len, _severity) \
43    if ((((_actual_len) - SIZEOF (iceMsg)) >> 3) != _expected_len) \
44    { \
45       _IceErrorBadLength (_iceConn, _majorOp, _minorOp, _severity); \
46       return; \
47    }
48
49#define CHECK_AT_LEAST_SIZE(_iceConn, _majorOp, _minorOp, _expected_len, _actual_len, _severity) \
50    if ((((_actual_len) - SIZEOF (iceMsg)) >> 3) > _expected_len) \
51    { \
52       _IceErrorBadLength (_iceConn, _majorOp, _minorOp, _severity); \
53       return; \
54    }
55
56#define CHECK_COMPLETE_SIZE(_iceConn, _majorOp, _minorOp, _expected_len, _actual_len, _pStart, _severity) \
57    if (((unsigned long)(PADDED_BYTES64((_actual_len)) - SIZEOF (iceMsg)) >> 3)	\
58        != _expected_len) \
59    { \
60       _IceErrorBadLength (_iceConn, _majorOp, _minorOp, _severity); \
61       IceDisposeCompleteMessage (iceConn, _pStart); \
62       return; \
63    }
64
65
66
67void
68_SmcProcessMessage(IceConn iceConn, IcePointer clientData, int opcode,
69		   unsigned long length, Bool swap,
70		   IceReplyWaitInfo *replyWait, Bool *replyReadyRet)
71{
72    SmcConn	smcConn = (SmcConn) clientData;
73
74    if (replyWait)
75	*replyReadyRet = False;
76
77    if (!smcConn->client_id &&
78        opcode != SM_RegisterClientReply && opcode != SM_Error)
79    {
80	_IceReadSkip (iceConn, length << 3);
81
82	_IceErrorBadState (iceConn, _SmcOpcode, opcode, IceFatalToProtocol);
83	return;
84    }
85
86    switch (opcode)
87    {
88    case SM_Error:
89    {
90	iceErrorMsg 	*pMsg;
91	char	    	*pData;
92
93	CHECK_AT_LEAST_SIZE (iceConn, _SmcOpcode, opcode,
94	    length, SIZEOF (iceErrorMsg), IceFatalToProtocol);
95
96	IceReadCompleteMessage (iceConn, SIZEOF (iceErrorMsg),
97	    iceErrorMsg, pMsg, pData);
98
99	if (!IceValidIO (iceConn))
100	{
101	    IceDisposeCompleteMessage (iceConn, pData);
102	    return;
103	}
104
105	if (swap)
106	{
107	    pMsg->errorClass = lswaps (pMsg->errorClass);
108	    pMsg->offendingSequenceNum = lswapl (pMsg->offendingSequenceNum);
109	}
110
111	if (replyWait &&
112	    replyWait->minor_opcode_of_request == SM_RegisterClient &&
113            pMsg->errorClass == IceBadValue &&
114	    pMsg->offendingMinorOpcode == SM_RegisterClient &&
115	    pMsg->offendingSequenceNum == replyWait->sequence_of_request)
116	{
117	    /*
118	     * For Register Client, the previous ID was bad.
119	     */
120
121	    _SmcRegisterClientReply *reply =
122		(_SmcRegisterClientReply *) (replyWait->reply);
123
124	    reply->status = 0;
125
126	    *replyReadyRet = True;
127	}
128	else
129	{
130	    (*_SmcErrorHandler) (smcConn, swap,
131		pMsg->offendingMinorOpcode,
132	        pMsg->offendingSequenceNum,
133		pMsg->errorClass, pMsg->severity,
134		(SmPointer) pData);
135	}
136
137	IceDisposeCompleteMessage (iceConn, pData);
138	break;
139    }
140
141    case SM_RegisterClientReply:
142
143	if (!replyWait ||
144	    replyWait->minor_opcode_of_request != SM_RegisterClient)
145	{
146	    _IceReadSkip (iceConn, length << 3);
147
148	    _IceErrorBadState (iceConn, _SmcOpcode,
149		SM_RegisterClientReply, IceFatalToProtocol);
150	}
151        else
152	{
153	    smRegisterClientReplyMsg 	*pMsg;
154	    char			*pData, *pStart;
155	    _SmcRegisterClientReply 	*reply =
156	        (_SmcRegisterClientReply *) (replyWait->reply);
157
158#if 0 /* No-op */
159	    CHECK_AT_LEAST_SIZE (iceConn, _SmcOpcode, opcode,
160		length, SIZEOF (smRegisterClientReplyMsg), IceFatalToProtocol);
161#endif
162
163	    IceReadCompleteMessage (iceConn, SIZEOF (smRegisterClientReplyMsg),
164		smRegisterClientReplyMsg, pMsg, pStart);
165
166	    if (!IceValidIO (iceConn))
167	    {
168		IceDisposeCompleteMessage (iceConn, pStart);
169		return;
170	    }
171
172	    pData = pStart;
173
174	    SKIP_ARRAY8 (pData, swap);		/* client id */
175
176	    CHECK_COMPLETE_SIZE (iceConn, _SmcOpcode, opcode,
177		length, pData - pStart + SIZEOF (smRegisterClientReplyMsg),
178		pStart, IceFatalToProtocol);
179
180	    pData = pStart;
181
182	    EXTRACT_ARRAY8_AS_STRING (pData, swap, reply->client_id);
183
184	    reply->status = 1;
185	    *replyReadyRet = True;
186
187	    IceDisposeCompleteMessage (iceConn, pStart);
188	}
189	break;
190
191    case SM_SaveYourself:
192    {
193	smSaveYourselfMsg 	*pMsg;
194	unsigned char		errVal;
195	int			errOffset = -1;
196
197	CHECK_SIZE_MATCH (iceConn, _SmcOpcode, opcode,
198	    length, SIZEOF (smSaveYourselfMsg),
199	    IceFatalToProtocol);
200
201	IceReadMessageHeader (iceConn, SIZEOF (smSaveYourselfMsg),
202	    smSaveYourselfMsg, pMsg);
203
204	if (!IceValidIO (iceConn))
205	{
206	    return;
207	}
208
209	if (pMsg->saveType != SmSaveGlobal &&
210	    pMsg->saveType != SmSaveLocal &&
211	    pMsg->saveType != SmSaveBoth)
212	{
213	    errVal = pMsg->saveType;
214	    errOffset = 8;
215	}
216	else if (pMsg->shutdown != 1 && pMsg->shutdown != 0)
217	{
218	    errVal = pMsg->shutdown;
219	    errOffset = 9;
220	}
221	else if (pMsg->interactStyle != SmInteractStyleNone &&
222	    pMsg->interactStyle != SmInteractStyleErrors &&
223	    pMsg->interactStyle != SmInteractStyleAny)
224	{
225	    errVal = pMsg->interactStyle;
226	    errOffset = 10;
227	}
228	else if (pMsg->fast != 1 && pMsg->fast != 0)
229	{
230	    errVal = pMsg->fast;
231	    errOffset = 11;
232	}
233
234	if (errOffset >= 0)
235	{
236	    _IceErrorBadValue (iceConn, _SmcOpcode,
237	        SM_SaveYourself, errOffset, 1, (IcePointer) &errVal);
238	}
239	else
240	{
241	    (*smcConn->callbacks.save_yourself.callback) (smcConn,
242	        smcConn->callbacks.save_yourself.client_data,
243                pMsg->saveType, pMsg->shutdown,
244		pMsg->interactStyle, pMsg->fast);
245
246	    smcConn->save_yourself_in_progress = True;
247
248	    if (pMsg->shutdown)
249		smcConn->shutdown_in_progress = True;
250	}
251	break;
252    }
253
254    case SM_SaveYourselfPhase2:
255
256	if (!smcConn->phase2_wait)
257	{
258	    _IceErrorBadState (iceConn, _SmcOpcode,
259		SM_SaveYourselfPhase2, IceCanContinue);
260	}
261        else
262	{
263	    CHECK_SIZE_MATCH (iceConn, _SmcOpcode, opcode,
264	        length, SIZEOF (smSaveYourselfPhase2Msg),
265	        IceFatalToProtocol);
266
267	    (*smcConn->phase2_wait->phase2_proc) (smcConn,
268		smcConn->phase2_wait->client_data);
269
270	    free (smcConn->phase2_wait);
271	    smcConn->phase2_wait  = NULL;
272	}
273	break;
274
275    case SM_Interact:
276
277        if (!smcConn->interact_waits)
278	{
279	    _IceErrorBadState (iceConn, _SmcOpcode,
280		SM_Interact, IceCanContinue);
281	}
282        else
283	{
284	    _SmcInteractWait *next = smcConn->interact_waits->next;
285
286	    CHECK_SIZE_MATCH (iceConn, _SmcOpcode, opcode,
287	        length, SIZEOF (smInteractMsg),
288	        IceFatalToProtocol);
289
290	    (*smcConn->interact_waits->interact_proc) (smcConn,
291		smcConn->interact_waits->client_data);
292
293	    free (smcConn->interact_waits);
294	    smcConn->interact_waits = next;
295	}
296	break;
297
298    case SM_SaveComplete:
299
300	if (!smcConn->save_yourself_in_progress)
301	{
302	    _IceErrorBadState (iceConn, _SmcOpcode,
303		SM_SaveComplete, IceCanContinue);
304	}
305	else
306	{
307	    CHECK_SIZE_MATCH (iceConn, _SmcOpcode, opcode,
308	        length, SIZEOF (smSaveCompleteMsg),
309	        IceFatalToProtocol);
310
311	    smcConn->save_yourself_in_progress = False;
312
313	    (*smcConn->callbacks.save_complete.callback) (smcConn,
314	        smcConn->callbacks.save_complete.client_data);
315	}
316	break;
317
318    case SM_Die:
319
320	CHECK_SIZE_MATCH (iceConn, _SmcOpcode, opcode,
321	    length, SIZEOF (smDieMsg),
322	    IceFatalToProtocol);
323
324	(*smcConn->callbacks.die.callback) (smcConn,
325	    smcConn->callbacks.die.client_data);
326	break;
327
328    case SM_ShutdownCancelled:
329
330	if (!smcConn->shutdown_in_progress)
331	{
332	    _IceErrorBadState (iceConn, _SmcOpcode,
333		SM_ShutdownCancelled, IceCanContinue);
334	}
335	else
336	{
337	    CHECK_SIZE_MATCH (iceConn, _SmcOpcode, opcode,
338	        length, SIZEOF (smShutdownCancelledMsg),
339	        IceFatalToProtocol);
340
341	    smcConn->shutdown_in_progress = False;
342
343	    (*smcConn->callbacks.shutdown_cancelled.callback) (smcConn,
344	        smcConn->callbacks.shutdown_cancelled.client_data);
345	}
346	break;
347
348    case SM_PropertiesReply:
349
350        if (!smcConn->prop_reply_waits)
351	{
352	    _IceReadSkip (iceConn, length << 3);
353
354	    _IceErrorBadState (iceConn, _SmcOpcode,
355		SM_PropertiesReply, IceCanContinue);
356	}
357        else
358	{
359	    smPropertiesReplyMsg 	*pMsg;
360	    char 			*pData, *pStart;
361	    int				numProps;
362	    SmProp			**props = NULL;
363	    _SmcPropReplyWait 		*next;
364
365#if 0 /* No-op */
366	    CHECK_AT_LEAST_SIZE (iceConn, _SmcOpcode, opcode,
367		length, SIZEOF (smPropertiesReplyMsg), IceFatalToProtocol);
368#endif
369
370	    IceReadCompleteMessage (iceConn, SIZEOF (smPropertiesReplyMsg),
371		smPropertiesReplyMsg, pMsg, pStart);
372
373	    if (!IceValidIO (iceConn))
374	    {
375		IceDisposeCompleteMessage (iceConn, pStart);
376		return;
377	    }
378
379	    pData = pStart;
380
381	    SKIP_LISTOF_PROPERTY (pData, swap);
382
383	    CHECK_COMPLETE_SIZE (iceConn, _SmcOpcode, opcode,
384	        length, pData - pStart + SIZEOF (smPropertiesReplyMsg),
385	        pStart, IceFatalToProtocol);
386
387	    pData = pStart;
388
389	    EXTRACT_LISTOF_PROPERTY (pData, swap, numProps, props);
390
391	    next = smcConn->prop_reply_waits->next;
392
393	    (*smcConn->prop_reply_waits->prop_reply_proc) (smcConn,
394		smcConn->prop_reply_waits->client_data, numProps, props);
395
396	    free (smcConn->prop_reply_waits);
397	    smcConn->prop_reply_waits = next;
398
399	    IceDisposeCompleteMessage (iceConn, pStart);
400	}
401	break;
402
403    default:
404    {
405	_IceErrorBadMinor (iceConn, _SmcOpcode, opcode, IceCanContinue);
406	_IceReadSkip (iceConn, length << 3);
407	break;
408    }
409    }
410}
411
412
413
414void
415_SmsProcessMessage(IceConn iceConn, IcePointer clientData, int opcode,
416		   unsigned long length, Bool swap)
417{
418    SmsConn	smsConn = (SmsConn) clientData;
419
420    if (!smsConn->client_id &&
421        opcode != SM_RegisterClient && opcode != SM_Error)
422    {
423	_IceReadSkip (iceConn, length << 3);
424
425	_IceErrorBadState (iceConn, _SmsOpcode, opcode, IceFatalToProtocol);
426
427	return;
428    }
429
430    switch (opcode)
431    {
432    case SM_Error:
433    {
434	iceErrorMsg 	*pMsg;
435	char	    	*pData;
436
437	CHECK_AT_LEAST_SIZE (iceConn, _SmsOpcode, opcode,
438	    length, SIZEOF (iceErrorMsg), IceFatalToProtocol);
439
440	IceReadCompleteMessage (iceConn, SIZEOF (iceErrorMsg),
441	    iceErrorMsg, pMsg, pData);
442
443	if (!IceValidIO (iceConn))
444	{
445	    IceDisposeCompleteMessage (iceConn, pData);
446	    return;
447	}
448
449	if (swap)
450	{
451	    pMsg->errorClass = lswaps (pMsg->errorClass);
452	    pMsg->offendingSequenceNum = lswapl (pMsg->offendingSequenceNum);
453	}
454
455	(*_SmsErrorHandler) (smsConn, swap,
456	    pMsg->offendingMinorOpcode,
457	    pMsg->offendingSequenceNum,
458	    pMsg->errorClass, pMsg->severity,
459            (SmPointer) pData);
460
461	IceDisposeCompleteMessage (iceConn, pData);
462	break;
463    }
464
465    case SM_RegisterClient:
466    {
467	smRegisterClientMsg 	*pMsg;
468	char 			*pData, *pStart;
469	char 			*previousId;
470	int                      idLen;
471
472#if 0 /* No-op */
473	CHECK_AT_LEAST_SIZE (iceConn, _SmsOpcode, opcode,
474	    length, SIZEOF (smRegisterClientMsg), IceFatalToProtocol);
475#endif
476
477	IceReadCompleteMessage (iceConn, SIZEOF (smRegisterClientMsg),
478	    smRegisterClientMsg, pMsg, pStart);
479
480	if (!IceValidIO (iceConn))
481	{
482	    IceDisposeCompleteMessage (iceConn, pStart);
483	    return;
484	}
485
486	pData = pStart;
487
488	SKIP_ARRAY8 (pData, swap);	/* previous id */
489
490	CHECK_COMPLETE_SIZE (iceConn, _SmsOpcode, opcode,
491	   length, pData - pStart + SIZEOF (smRegisterClientMsg),
492	   pStart, IceFatalToProtocol);
493
494	pData = pStart;
495
496	EXTRACT_ARRAY8 (pData, swap, idLen, previousId);
497
498	if (*previousId == '\0')
499	{
500	    free (previousId);
501	    previousId = NULL;
502	}
503
504	if (!(*smsConn->callbacks.register_client.callback) (smsConn,
505            smsConn->callbacks.register_client.manager_data, previousId))
506	{
507	    /*
508	     * The previoudId was bad.  Generate BadValue error.
509	     */
510
511	    _IceErrorBadValue (smsConn->iceConn, _SmsOpcode, SM_RegisterClient,
512		8, ARRAY8_BYTES (idLen), (IcePointer) pStart);
513	}
514
515	IceDisposeCompleteMessage (iceConn, pStart);
516	break;
517    }
518
519    case SM_InteractRequest:
520
521        if (!smsConn->save_yourself_in_progress ||
522	    smsConn->interaction_allowed == SmInteractStyleNone)
523	{
524	    _IceErrorBadState (iceConn, _SmsOpcode,
525		SM_InteractRequest, IceCanContinue);
526	}
527        else
528	{
529	    smInteractRequestMsg 	*pMsg;
530
531	    CHECK_SIZE_MATCH (iceConn, _SmsOpcode, opcode,
532	        length, SIZEOF (smInteractRequestMsg),
533	        IceFatalToProtocol);
534
535	    IceReadSimpleMessage (iceConn, smInteractRequestMsg, pMsg);
536
537	    if (pMsg->dialogType != SmDialogNormal &&
538		pMsg->dialogType != SmDialogError)
539	    {
540		unsigned char errVal = pMsg->dialogType;
541
542		_IceErrorBadValue (iceConn, _SmsOpcode,
543	            SM_InteractRequest, 2, 1, (IcePointer) &errVal);
544	    }
545	    else if (pMsg->dialogType == SmDialogNormal &&
546		smsConn->interaction_allowed != SmInteractStyleAny)
547	    {
548		_IceErrorBadState (iceConn, _SmsOpcode,
549		    SM_InteractRequest, IceCanContinue);
550	    }
551	    else
552	    {
553		(*smsConn->callbacks.interact_request.callback) (smsConn,
554	            smsConn->callbacks.interact_request.manager_data,
555		    pMsg->dialogType);
556	    }
557	}
558	break;
559
560    case SM_InteractDone:
561
562        if (!smsConn->interact_in_progress)
563	{
564	    _IceErrorBadState (iceConn, _SmsOpcode,
565		SM_InteractDone, IceCanContinue);
566	}
567        else
568	{
569	    smInteractDoneMsg 	*pMsg;
570
571	    CHECK_SIZE_MATCH (iceConn, _SmsOpcode, opcode,
572	        length, SIZEOF (smInteractDoneMsg),
573	        IceFatalToProtocol);
574
575	    IceReadSimpleMessage (iceConn, smInteractDoneMsg, pMsg);
576
577	    if (pMsg->cancelShutdown != 1 &&
578		pMsg->cancelShutdown != 0)
579	    {
580		unsigned char errVal = pMsg->cancelShutdown;
581
582		_IceErrorBadValue (iceConn, _SmsOpcode,
583	            SM_InteractDone, 2, 1, (IcePointer) &errVal);
584	    }
585	    else if (pMsg->cancelShutdown && !smsConn->can_cancel_shutdown)
586	    {
587		_IceErrorBadState (iceConn, _SmsOpcode,
588		    SM_InteractDone, IceCanContinue);
589	    }
590	    else
591	    {
592		smsConn->interact_in_progress = False;
593
594		(*smsConn->callbacks.interact_done.callback) (smsConn,
595	            smsConn->callbacks.interact_done.manager_data,
596	            pMsg->cancelShutdown);
597	    }
598	}
599	break;
600
601    case SM_SaveYourselfRequest:
602    {
603	smSaveYourselfRequestMsg 	*pMsg;
604	unsigned char			errVal;
605	int				errOffset = -1;
606
607	CHECK_SIZE_MATCH (iceConn, _SmsOpcode, opcode,
608	    length, SIZEOF (smSaveYourselfRequestMsg),
609	    IceFatalToProtocol);
610
611	IceReadMessageHeader (iceConn, SIZEOF (smSaveYourselfRequestMsg),
612	    smSaveYourselfRequestMsg, pMsg);
613
614	if (!IceValidIO (iceConn))
615	{
616	    IceDisposeCompleteMessage (iceConn, pMsg);
617	    return;
618	}
619
620	if (pMsg->saveType != SmSaveGlobal &&
621	    pMsg->saveType != SmSaveLocal &&
622	    pMsg->saveType != SmSaveBoth)
623	{
624	    errVal = pMsg->saveType;
625	    errOffset = 8;
626	}
627	else if (pMsg->shutdown != 1 && pMsg->shutdown != 0)
628	{
629	    errVal = pMsg->shutdown;
630	    errOffset = 9;
631	}
632	else if (pMsg->interactStyle != SmInteractStyleNone &&
633	    pMsg->interactStyle != SmInteractStyleErrors &&
634	    pMsg->interactStyle != SmInteractStyleAny)
635	{
636	    errVal = pMsg->interactStyle;
637	    errOffset = 10;
638	}
639	else if (pMsg->fast != 1 && pMsg->fast != 0)
640	{
641	    errVal = pMsg->fast;
642	    errOffset = 11;
643	}
644	else if (pMsg->global != 1 && pMsg->global != 0)
645	{
646	    errVal = pMsg->fast;
647	    errOffset = 11;
648	}
649
650	if (errOffset >= 0)
651	{
652	    _IceErrorBadValue (iceConn, _SmsOpcode,
653	        SM_SaveYourselfRequest, errOffset, 1, (IcePointer) &errVal);
654	}
655	else
656	{
657	    (*smsConn->callbacks.save_yourself_request.callback) (smsConn,
658	        smsConn->callbacks.save_yourself_request.manager_data,
659                pMsg->saveType, pMsg->shutdown, pMsg->interactStyle,
660	        pMsg->fast, pMsg->global);
661	}
662	break;
663    }
664
665    case SM_SaveYourselfPhase2Request:
666
667        if (!smsConn->save_yourself_in_progress)
668	{
669	    _IceErrorBadState (iceConn, _SmsOpcode,
670		SM_SaveYourselfPhase2Request, IceCanContinue);
671	}
672        else
673	{
674	    CHECK_SIZE_MATCH (iceConn, _SmsOpcode, opcode,
675	        length, SIZEOF (smSaveYourselfPhase2RequestMsg),
676	        IceFatalToProtocol);
677
678	    (*smsConn->callbacks.save_yourself_phase2_request.callback) (
679		smsConn, smsConn->callbacks.
680		save_yourself_phase2_request.manager_data);
681	}
682	break;
683
684    case SM_SaveYourselfDone:
685
686        if (!smsConn->save_yourself_in_progress)
687	{
688	    _IceErrorBadState (iceConn, _SmsOpcode,
689		SM_SaveYourselfDone, IceCanContinue);
690	}
691        else
692	{
693	    smSaveYourselfDoneMsg 	*pMsg;
694
695	    CHECK_SIZE_MATCH (iceConn, _SmsOpcode, opcode,
696	        length, SIZEOF (smSaveYourselfDoneMsg),
697	        IceFatalToProtocol);
698
699	    IceReadSimpleMessage (iceConn, smSaveYourselfDoneMsg, pMsg);
700
701	    if (pMsg->success != 1 && pMsg->success != 0)
702	    {
703		unsigned char errVal = pMsg->success;
704
705		_IceErrorBadValue (iceConn, _SmsOpcode,
706	            SM_SaveYourselfDone, 2, 1, (IcePointer) &errVal);
707	    }
708	    else
709	    {
710		smsConn->save_yourself_in_progress = False;
711		smsConn->interaction_allowed = SmInteractStyleNone;
712
713		(*smsConn->callbacks.save_yourself_done.callback) (smsConn,
714	            smsConn->callbacks.save_yourself_done.manager_data,
715		    pMsg->success);
716	    }
717	}
718	break;
719
720    case SM_CloseConnection:
721    {
722	smCloseConnectionMsg 	*pMsg;
723	char 			*pData, *pStart;
724	int 			count, i;
725	char 			**reasonMsgs = NULL;
726
727#if 0 /* No-op */
728	CHECK_AT_LEAST_SIZE (iceConn, _SmsOpcode, opcode,
729	    length, SIZEOF (smCloseConnectionMsg), IceFatalToProtocol);
730#endif
731
732	IceReadCompleteMessage (iceConn, SIZEOF (smCloseConnectionMsg),
733	    smCloseConnectionMsg, pMsg, pStart);
734
735	if (!IceValidIO (iceConn))
736	{
737	    IceDisposeCompleteMessage (iceConn, pStart);
738	    return;
739	}
740
741	pData = pStart;
742
743	EXTRACT_CARD32 (pData, swap, count);
744	pData += 4;
745
746	for (i = 0; i < count; i++)
747	    SKIP_ARRAY8 (pData, swap);
748
749	CHECK_COMPLETE_SIZE (iceConn, _SmsOpcode, opcode,
750	   length, pData - pStart + SIZEOF (smCloseConnectionMsg),
751	   pStart, IceFatalToProtocol);
752
753	pData = pStart + 8;
754
755	reasonMsgs = malloc (count * sizeof (char *));
756	for (i = 0; i < count; i++)
757	    EXTRACT_ARRAY8_AS_STRING (pData, swap, reasonMsgs[i]);
758
759	IceDisposeCompleteMessage (iceConn, pStart);
760
761	(*smsConn->callbacks.close_connection.callback) (smsConn,
762	    smsConn->callbacks.close_connection.manager_data,
763	    count, reasonMsgs);
764	break;
765    }
766
767    case SM_SetProperties:
768    {
769	smSetPropertiesMsg 	*pMsg;
770	char 			*pData, *pStart;
771	SmProp			**props = NULL;
772	int 			numProps;
773
774#if 0 /* No-op */
775	CHECK_AT_LEAST_SIZE (iceConn, _SmsOpcode, opcode,
776	    length, SIZEOF (smSetPropertiesMsg), IceFatalToProtocol);
777#endif
778
779	IceReadCompleteMessage (iceConn, SIZEOF (smSetPropertiesMsg),
780	    smSetPropertiesMsg, pMsg, pStart);
781
782	if (!IceValidIO (iceConn))
783	{
784	    IceDisposeCompleteMessage (iceConn, pStart);
785	    return;
786	}
787
788	pData = pStart;
789
790	SKIP_LISTOF_PROPERTY (pData, swap);
791
792	CHECK_COMPLETE_SIZE (iceConn, _SmsOpcode, opcode,
793	   length, pData - pStart + SIZEOF (smSetPropertiesMsg),
794	   pStart, IceFatalToProtocol);
795
796	pData = pStart;
797
798	EXTRACT_LISTOF_PROPERTY (pData, swap, numProps, props);
799
800	(*smsConn->callbacks.set_properties.callback) (smsConn,
801	    smsConn->callbacks.set_properties.manager_data, numProps, props);
802
803	IceDisposeCompleteMessage (iceConn, pStart);
804	break;
805    }
806
807    case SM_DeleteProperties:
808    {
809	smDeletePropertiesMsg 	*pMsg;
810	char 			*pData, *pStart;
811	int 			count, i;
812	char 			**propNames = NULL;
813
814#if 0 /* No-op */
815	CHECK_AT_LEAST_SIZE (iceConn, _SmsOpcode, opcode,
816	    length, SIZEOF (smDeletePropertiesMsg), IceFatalToProtocol);
817#endif
818
819	IceReadCompleteMessage (iceConn, SIZEOF (smDeletePropertiesMsg),
820	    smDeletePropertiesMsg, pMsg, pStart);
821
822	if (!IceValidIO (iceConn))
823	{
824	    IceDisposeCompleteMessage (iceConn, pStart);
825	    return;
826	}
827
828	pData = pStart;
829
830	EXTRACT_CARD32 (pData, swap, count);
831	pData += 4;
832
833	for (i = 0; i < count; i++)
834	    SKIP_ARRAY8 (pData, swap);	/* prop names */
835
836	CHECK_COMPLETE_SIZE (iceConn, _SmsOpcode, opcode,
837	   length, pData - pStart + SIZEOF (smDeletePropertiesMsg),
838	   pStart, IceFatalToProtocol);
839
840	pData = pStart + 8;
841
842	propNames = malloc (count * sizeof (char *));
843	for (i = 0; i < count; i++)
844	    EXTRACT_ARRAY8_AS_STRING (pData, swap, propNames[i]);
845
846	IceDisposeCompleteMessage (iceConn, pStart);
847
848	(*smsConn->callbacks.delete_properties.callback) (smsConn,
849	    smsConn->callbacks.delete_properties.manager_data,
850	    count, propNames);
851
852	break;
853    }
854
855    case SM_GetProperties:
856
857	CHECK_SIZE_MATCH (iceConn, _SmsOpcode, opcode,
858	    length, SIZEOF (smGetPropertiesMsg),
859	    IceFatalToProtocol);
860
861	(*smsConn->callbacks.get_properties.callback) (smsConn,
862	    smsConn->callbacks.get_properties.manager_data);
863	break;
864
865    default:
866    {
867	_IceErrorBadMinor (iceConn, _SmsOpcode, opcode, IceCanContinue);
868	_IceReadSkip (iceConn, length << 3);
869	break;
870    }
871    }
872}
873