upload tizen2.0 source
[framework/uifw/xorg/lib/libsm.git] / src / sm_client.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 int     _SmcOpcode = 0;
38 int     _SmsOpcode = 0;
39
40 #ifndef __UNIXOS2__
41 SmsNewClientProc _SmsNewClientProc;
42 SmPointer        _SmsNewClientData;
43 #else
44 SmsNewClientProc _SmsNewClientProc = 0;
45 SmPointer        _SmsNewClientData = 0;
46 #endif
47
48 SmcErrorHandler _SmcErrorHandler = _SmcDefaultErrorHandler;
49 SmsErrorHandler _SmsErrorHandler = _SmsDefaultErrorHandler;
50
51
52 static void
53 set_callbacks(SmcConn smcConn, unsigned long mask, SmcCallbacks *callbacks);
54
55 \f
56 SmcConn
57 SmcOpenConnection(char *networkIdsList, SmPointer context,
58                   int xsmpMajorRev, int xsmpMinorRev,
59                   unsigned long mask, SmcCallbacks *callbacks,
60                   char *previousId, char **clientIdRet,
61                   int errorLength, char *errorStringRet)
62 {
63     SmcConn                     smcConn;
64     IceConn                     iceConn;
65     char                        *ids;
66     IceProtocolSetupStatus      setupstat;
67     int                         majorVersion;
68     int                         minorVersion;
69     char                        *vendor = NULL;
70     char                        *release = NULL;
71     smRegisterClientMsg         *pMsg;
72     char                        *pData;
73     int                         extra, len;
74     IceReplyWaitInfo            replyWait;
75     _SmcRegisterClientReply     reply;
76     Bool                        gotReply, ioErrorOccured;
77
78     const char *auth_names[] = {"MIT-MAGIC-COOKIE-1"};
79     IcePoAuthProc auth_procs[] = {_IcePoMagicCookie1Proc};
80     int auth_count = 1;
81
82     IcePoVersionRec versions[] = {
83         {SmProtoMajor, SmProtoMinor, _SmcProcessMessage}
84     };
85     int version_count = 1;
86
87
88     *clientIdRet = NULL;
89
90     if (errorStringRet && errorLength > 0)
91         *errorStringRet = '\0';
92
93     if (!_SmcOpcode)
94     {
95         /*
96          * For now, there is only one version of XSMP, so we don't
97          * have to check {xsmpMajorRev, xsmpMinorRev}.  In the future,
98          * we will check against versions and generate the list
99          * of versions the application actually supports.
100          */
101
102         if ((_SmcOpcode = IceRegisterForProtocolSetup ("XSMP",
103             SmVendorString, SmReleaseString, version_count, versions,
104             auth_count, auth_names, auth_procs, NULL)) < 0)
105         {
106             if (errorStringRet && errorLength > 0) {
107                 strncpy (errorStringRet,
108                          "Could not register XSMP protocol with ICE",
109                          errorLength);
110                 errorStringRet[errorLength - 1] = '\0';
111             }
112
113             return (NULL);
114         }
115     }
116
117     if (networkIdsList == NULL || *networkIdsList == '\0')
118     {
119         if ((ids = (char *) getenv ("SESSION_MANAGER")) == NULL)
120         {
121             if (errorStringRet && errorLength > 0) {
122                 strncpy (errorStringRet,
123                          "SESSION_MANAGER environment variable not defined",
124                          errorLength);
125                 errorStringRet[errorLength - 1] = '\0';
126             }
127             return (NULL);
128         }
129     }
130     else
131     {
132         ids = networkIdsList;
133     }
134
135     if ((iceConn = IceOpenConnection (
136         ids, context, 0, _SmcOpcode, errorLength, errorStringRet)) == NULL)
137     {
138         return (NULL);
139     }
140
141     if ((smcConn = malloc (sizeof (struct _SmcConn))) == NULL)
142     {
143         if (errorStringRet && errorLength > 0) {
144             strncpy (errorStringRet, "Can't malloc", errorLength);
145             errorStringRet[errorLength - 1] = '\0';
146         }
147         IceCloseConnection (iceConn);
148         return (NULL);
149     }
150
151     setupstat = IceProtocolSetup (iceConn, _SmcOpcode,
152         (IcePointer) smcConn,
153         False /* mustAuthenticate */,
154         &majorVersion, &minorVersion,
155         &vendor, &release, errorLength, errorStringRet);
156
157     if (setupstat == IceProtocolSetupFailure ||
158         setupstat == IceProtocolSetupIOError)
159     {
160         IceCloseConnection (iceConn);
161         free (smcConn);
162         return (NULL);
163     }
164     else if (setupstat == IceProtocolAlreadyActive)
165     {
166         /*
167          * This case should never happen, because when we called
168          * IceOpenConnection, we required that the ICE connection
169          * may not already have XSMP active on it.
170          */
171
172         free (smcConn);
173         if (errorStringRet && errorLength > 0) {
174             strncpy (errorStringRet, "Internal error in IceOpenConnection",
175                      errorLength);
176             errorStringRet[errorLength - 1] = '\0';
177         }
178         return (NULL);
179     }
180
181     smcConn->iceConn = iceConn;
182     smcConn->proto_major_version = majorVersion;
183     smcConn->proto_minor_version = minorVersion;
184     smcConn->vendor = vendor;
185     smcConn->release = release;
186     smcConn->client_id = NULL;
187
188     bzero ((char *) &smcConn->callbacks, sizeof (SmcCallbacks));
189     set_callbacks (smcConn, mask, callbacks);
190
191     smcConn->interact_waits = NULL;
192     smcConn->phase2_wait = NULL;
193     smcConn->prop_reply_waits = NULL;
194
195     smcConn->save_yourself_in_progress = False;
196     smcConn->shutdown_in_progress = False;
197
198
199     /*
200      * Now register the client
201      */
202
203     if (!previousId)
204         previousId = "";
205     len = strlen (previousId);
206     extra = ARRAY8_BYTES (len);
207
208     IceGetHeaderExtra (iceConn, _SmcOpcode, SM_RegisterClient,
209         SIZEOF (smRegisterClientMsg), WORD64COUNT (extra),
210         smRegisterClientMsg, pMsg, pData);
211
212     STORE_ARRAY8 (pData, len, previousId);
213
214     IceFlush (iceConn);
215
216     replyWait.sequence_of_request = IceLastSentSequenceNumber (iceConn);
217     replyWait.major_opcode_of_request = _SmcOpcode;
218     replyWait.minor_opcode_of_request = SM_RegisterClient;
219     replyWait.reply = (IcePointer) &reply;
220
221     gotReply = False;
222     ioErrorOccured = False;
223
224     while (!gotReply && !ioErrorOccured)
225     {
226         ioErrorOccured = (IceProcessMessages (
227             iceConn, &replyWait, &gotReply) == IceProcessMessagesIOError);
228
229         if (ioErrorOccured)
230         {
231             if (errorStringRet && errorLength > 0) {
232                 strncpy (errorStringRet, "IO error occured opening connection",
233                          errorLength);
234                 errorStringRet[errorLength - 1] = '\0';
235             }
236             free (smcConn->vendor);
237             free (smcConn->release);
238             free (smcConn);
239
240             return (NULL);
241         }
242         else if (gotReply)
243         {
244             if (reply.status == 1)
245             {
246                 /*
247                  * The client successfully registered.
248                  */
249
250                 *clientIdRet = reply.client_id;
251
252                 smcConn->client_id = strdup (*clientIdRet);
253             }
254             else
255             {
256                 /*
257                  * Could not register the client because the previous ID
258                  * was bad.  So now we register the client with the
259                  * previous ID set to NULL.
260                  */
261
262                 extra = ARRAY8_BYTES (0);
263
264                 IceGetHeaderExtra (iceConn, _SmcOpcode, SM_RegisterClient,
265                     SIZEOF (smRegisterClientMsg), WORD64COUNT (extra),
266                     smRegisterClientMsg, pMsg, pData);
267
268                 STORE_ARRAY8 (pData, 0, "");
269
270                 IceFlush (iceConn);
271
272                 replyWait.sequence_of_request =
273                     IceLastSentSequenceNumber (iceConn);
274
275                 gotReply = False;
276             }
277         }
278     }
279
280     return (smcConn);
281 }
282
283
284 \f
285 SmcCloseStatus
286 SmcCloseConnection(SmcConn smcConn, int count, char **reasonMsgs)
287 {
288     IceConn                     iceConn = smcConn->iceConn;
289     smCloseConnectionMsg        *pMsg;
290     char                        *pData;
291     int                         extra, i;
292     IceCloseStatus              closeStatus;
293     SmcCloseStatus              statusRet;
294
295     extra = 8;
296
297     for (i = 0; i < count; i++)
298         extra += ARRAY8_BYTES (strlen (reasonMsgs[i]));
299
300     IceGetHeaderExtra (iceConn, _SmcOpcode, SM_CloseConnection,
301         SIZEOF (smCloseConnectionMsg), WORD64COUNT (extra),
302         smCloseConnectionMsg, pMsg, pData);
303
304     STORE_CARD32 (pData, count);
305     pData += 4;
306
307     for (i = 0; i < count; i++)
308         STORE_ARRAY8 (pData, strlen (reasonMsgs[i]), reasonMsgs[i]);
309
310     IceFlush (iceConn);
311
312     IceProtocolShutdown (iceConn, _SmcOpcode);
313     IceSetShutdownNegotiation (iceConn, False);
314     closeStatus = IceCloseConnection (iceConn);
315
316     if (smcConn->vendor)
317         free (smcConn->vendor);
318
319     if (smcConn->release)
320         free (smcConn->release);
321
322     if (smcConn->client_id)
323         free (smcConn->client_id);
324
325     if (smcConn->prop_reply_waits)
326     {
327         _SmcPropReplyWait *ptr = smcConn->prop_reply_waits;
328         _SmcPropReplyWait *next;
329
330         while (ptr)
331         {
332             next = ptr->next;
333             free (ptr);
334             ptr = next;
335         }
336
337     }
338
339     free (smcConn);
340
341     if (closeStatus == IceClosedNow)
342         statusRet = SmcClosedNow;
343     else if (closeStatus == IceClosedASAP)
344         statusRet = SmcClosedASAP;
345     else
346         statusRet = SmcConnectionInUse;
347
348     return (statusRet);
349 }
350
351
352 \f
353 void
354 SmcModifyCallbacks(SmcConn smcConn, unsigned long mask, SmcCallbacks *callbacks)
355 {
356     set_callbacks (smcConn, mask, callbacks);
357 }
358
359
360 \f
361 void
362 SmcSetProperties(SmcConn smcConn, int numProps, SmProp **props)
363 {
364     IceConn             iceConn = smcConn->iceConn;
365     smSetPropertiesMsg  *pMsg;
366     char                *pBuf;
367     char                *pStart;
368     int                 bytes;
369
370     IceGetHeader (iceConn, _SmcOpcode, SM_SetProperties,
371         SIZEOF (smSetPropertiesMsg), smSetPropertiesMsg, pMsg);
372
373     LISTOF_PROP_BYTES (numProps, props, bytes);
374     pMsg->length += WORD64COUNT (bytes);
375
376     pBuf = pStart = IceAllocScratch (iceConn, bytes);
377     memset(pStart, 0, bytes);
378
379     STORE_LISTOF_PROPERTY (pBuf, numProps, props);
380
381     IceWriteData (iceConn, bytes, pStart);
382     IceFlush (iceConn);
383 }
384
385
386 \f
387 void
388 SmcDeleteProperties(SmcConn smcConn, int numProps, char **propNames)
389 {
390     IceConn                     iceConn = smcConn->iceConn;
391     smDeletePropertiesMsg       *pMsg;
392     char                        *pData;
393     int                         extra, i;
394
395     extra = 8;
396
397     for (i = 0; i < numProps; i++)
398         extra += ARRAY8_BYTES (strlen (propNames[i]));
399
400     IceGetHeaderExtra (iceConn, _SmcOpcode, SM_DeleteProperties,
401         SIZEOF (smDeletePropertiesMsg), WORD64COUNT (extra),
402         smDeletePropertiesMsg, pMsg, pData);
403
404     STORE_CARD32 (pData, numProps);
405     pData += 4;
406
407     for (i = 0; i < numProps; i++)
408         STORE_ARRAY8 (pData, strlen (propNames[i]), propNames[i]);
409
410     IceFlush (iceConn);
411 }
412
413
414 \f
415 Status
416 SmcGetProperties(SmcConn smcConn, SmcPropReplyProc propReplyProc,
417                  SmPointer clientData)
418 {
419     IceConn             iceConn = smcConn->iceConn;
420     _SmcPropReplyWait   *wait, *ptr;
421
422     if ((wait = malloc (sizeof (_SmcPropReplyWait))) == NULL)
423     {
424         return (0);
425     }
426
427     wait->prop_reply_proc = propReplyProc;
428     wait->client_data = clientData;
429     wait->next = NULL;
430
431     ptr = smcConn->prop_reply_waits;
432     while (ptr && ptr->next)
433         ptr = ptr->next;
434
435     if (ptr == NULL)
436         smcConn->prop_reply_waits = wait;
437     else
438         ptr->next = wait;
439
440     IceSimpleMessage (iceConn, _SmcOpcode, SM_GetProperties);
441     IceFlush (iceConn);
442
443     return (1);
444 }
445
446
447 \f
448 Status
449 SmcInteractRequest(SmcConn smcConn, int dialogType,
450                    SmcInteractProc interactProc, SmPointer clientData)
451 {
452     IceConn                     iceConn = smcConn->iceConn;
453     smInteractRequestMsg        *pMsg;
454     _SmcInteractWait            *wait, *ptr;
455
456     if ((wait = malloc (sizeof (_SmcInteractWait))) == NULL)
457     {
458         return (0);
459     }
460
461     wait->interact_proc = interactProc;
462     wait->client_data = clientData;
463     wait->next = NULL;
464
465     ptr = smcConn->interact_waits;
466     while (ptr && ptr->next)
467         ptr = ptr->next;
468
469     if (ptr == NULL)
470         smcConn->interact_waits = wait;
471     else
472         ptr->next = wait;
473
474     IceGetHeader (iceConn, _SmcOpcode, SM_InteractRequest,
475         SIZEOF (smInteractRequestMsg), smInteractRequestMsg, pMsg);
476
477     pMsg->dialogType = dialogType;
478
479     IceFlush (iceConn);
480
481     return (1);
482 }
483
484
485 \f
486 void
487 SmcInteractDone(SmcConn smcConn, Bool cancelShutdown)
488 {
489     IceConn             iceConn = smcConn->iceConn;
490     smInteractDoneMsg   *pMsg;
491
492     IceGetHeader (iceConn, _SmcOpcode, SM_InteractDone,
493         SIZEOF (smInteractDoneMsg), smInteractDoneMsg, pMsg);
494
495     pMsg->cancelShutdown = cancelShutdown;
496
497     IceFlush (iceConn);
498 }
499
500
501 \f
502 void
503 SmcRequestSaveYourself(SmcConn smcConn, int saveType, Bool shutdown,
504                        int interactStyle, Bool fast, Bool global)
505 {
506     IceConn                     iceConn = smcConn->iceConn;
507     smSaveYourselfRequestMsg    *pMsg;
508
509     IceGetHeader (iceConn, _SmcOpcode, SM_SaveYourselfRequest,
510         SIZEOF (smSaveYourselfRequestMsg), smSaveYourselfRequestMsg, pMsg);
511
512     pMsg->saveType = saveType;
513     pMsg->shutdown = shutdown;
514     pMsg->interactStyle = interactStyle;
515     pMsg->fast = fast;
516     pMsg->global = global;
517
518     IceFlush (iceConn);
519 }
520
521
522 \f
523 Status
524 SmcRequestSaveYourselfPhase2(SmcConn smcConn,
525                              SmcSaveYourselfPhase2Proc saveYourselfPhase2Proc,
526                              SmPointer clientData)
527 {
528     IceConn             iceConn = smcConn->iceConn;
529     _SmcPhase2Wait      *wait;
530
531     if (smcConn->phase2_wait)
532         wait = smcConn->phase2_wait;
533     else
534     {
535         if ((wait = malloc (sizeof (_SmcPhase2Wait))) == NULL)
536         {
537             return (0);
538         }
539     }
540
541     wait->phase2_proc = saveYourselfPhase2Proc;
542     wait->client_data = clientData;
543
544     smcConn->phase2_wait = wait;
545
546     IceSimpleMessage (iceConn, _SmcOpcode, SM_SaveYourselfPhase2Request);
547     IceFlush (iceConn);
548
549     return (1);
550 }
551
552
553 \f
554 void
555 SmcSaveYourselfDone(SmcConn smcConn, Bool success)
556 {
557     IceConn                     iceConn = smcConn->iceConn;
558     smSaveYourselfDoneMsg       *pMsg;
559
560     IceGetHeader (iceConn, _SmcOpcode, SM_SaveYourselfDone,
561         SIZEOF (smSaveYourselfDoneMsg), smSaveYourselfDoneMsg, pMsg);
562
563     pMsg->success = success;
564
565     IceFlush (iceConn);
566 }
567
568
569 \f
570 static void
571 set_callbacks(SmcConn smcConn, unsigned long mask, SmcCallbacks *callbacks)
572 {
573     if (mask & SmcSaveYourselfProcMask)
574     {
575         smcConn->callbacks.save_yourself.callback =
576             callbacks->save_yourself.callback;
577         smcConn->callbacks.save_yourself.client_data =
578             callbacks->save_yourself.client_data;
579     }
580
581     if (mask & SmcDieProcMask)
582     {
583         smcConn->callbacks.die.callback = callbacks->die.callback;
584         smcConn->callbacks.die.client_data = callbacks->die.client_data;
585     }
586
587     if (mask & SmcSaveCompleteProcMask)
588     {
589         smcConn->callbacks.save_complete.callback =
590             callbacks->save_complete.callback;
591         smcConn->callbacks.save_complete.client_data =
592             callbacks->save_complete.client_data;
593     }
594
595     if (mask & SmcShutdownCancelledProcMask)
596     {
597         smcConn->callbacks.shutdown_cancelled.callback =
598             callbacks->shutdown_cancelled.callback;
599         smcConn->callbacks.shutdown_cancelled.client_data =
600             callbacks->shutdown_cancelled.client_data;
601     }
602 }