c7c7abe98f477e1749b3b136f7c01289641f5c1a
[framework/uifw/xorg/lib/libsm.git] / src / sm_process.c
1 /*
2
3 Copyright 1993, 1998  The Open Group
4
5 Permission to use, copy, modify, distribute, and sell this software and its
6 documentation for any purpose is hereby granted without fee, provided that
7 the above copyright notice appear in all copies and that both that
8 copyright notice and this permission notice appear in supporting
9 documentation.
10
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
21 Except as contained in this notice, the name of The Open Group shall not be
22 used in advertising or otherwise to promote the sale, use or other dealings
23 in 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 (((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 \f
67 void
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 ((char *) 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 ((char *) 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 ((char *) 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 \f
414 void
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 = (char **) 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 = (char **) 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 }