Git init
[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 = (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 ((char *) 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 ((char *) 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 ((char *) 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 = (char *) malloc (
253                     strlen (*clientIdRet) + 1);
254
255                 strcpy (smcConn->client_id, *clientIdRet);
256             }
257             else
258             {
259                 /*
260                  * Could not register the client because the previous ID
261                  * was bad.  So now we register the client with the
262                  * previous ID set to NULL.
263                  */
264
265                 extra = ARRAY8_BYTES (0);
266
267                 IceGetHeaderExtra (iceConn, _SmcOpcode, SM_RegisterClient,
268                     SIZEOF (smRegisterClientMsg), WORD64COUNT (extra),
269                     smRegisterClientMsg, pMsg, pData);
270
271                 STORE_ARRAY8 (pData, 0, "");
272
273                 IceFlush (iceConn);
274
275                 replyWait.sequence_of_request =
276                     IceLastSentSequenceNumber (iceConn);
277
278                 gotReply = False;
279             }
280         }
281     }
282
283     return (smcConn);
284 }
285
286
287 \f
288 SmcCloseStatus
289 SmcCloseConnection(SmcConn smcConn, int count, char **reasonMsgs)
290 {
291     IceConn                     iceConn = smcConn->iceConn;
292     smCloseConnectionMsg        *pMsg;
293     char                        *pData;
294     int                         extra, i;
295     IceCloseStatus              closeStatus;
296     SmcCloseStatus              statusRet;
297
298     extra = 8;
299
300     for (i = 0; i < count; i++)
301         extra += ARRAY8_BYTES (strlen (reasonMsgs[i]));
302
303     IceGetHeaderExtra (iceConn, _SmcOpcode, SM_CloseConnection,
304         SIZEOF (smCloseConnectionMsg), WORD64COUNT (extra),
305         smCloseConnectionMsg, pMsg, pData);
306
307     STORE_CARD32 (pData, count);
308     pData += 4;
309
310     for (i = 0; i < count; i++)
311         STORE_ARRAY8 (pData, strlen (reasonMsgs[i]), reasonMsgs[i]); 
312
313     IceFlush (iceConn);
314
315     IceProtocolShutdown (iceConn, _SmcOpcode);
316     IceSetShutdownNegotiation (iceConn, False);
317     closeStatus = IceCloseConnection (iceConn);
318
319     if (smcConn->vendor)
320         free (smcConn->vendor);
321
322     if (smcConn->release)
323         free (smcConn->release);
324
325     if (smcConn->client_id)
326         free (smcConn->client_id);
327
328     if (smcConn->prop_reply_waits)
329     {
330         _SmcPropReplyWait *ptr = smcConn->prop_reply_waits;
331         _SmcPropReplyWait *next;
332
333         while (ptr)
334         {
335             next = ptr->next;
336             free ((char *) ptr);
337             ptr = next;
338         }
339         
340     }
341
342     free ((char *) smcConn);
343
344     if (closeStatus == IceClosedNow)
345         statusRet = SmcClosedNow;
346     else if (closeStatus == IceClosedASAP)
347         statusRet = SmcClosedASAP;
348     else
349         statusRet = SmcConnectionInUse;
350
351     return (statusRet);
352 }
353
354
355 \f
356 void
357 SmcModifyCallbacks(SmcConn smcConn, unsigned long mask, SmcCallbacks *callbacks)
358 {
359     set_callbacks (smcConn, mask, callbacks);
360 }
361
362
363 \f
364 void
365 SmcSetProperties(SmcConn smcConn, int numProps, SmProp **props)
366 {
367     IceConn             iceConn = smcConn->iceConn;
368     smSetPropertiesMsg  *pMsg;
369     char                *pBuf;
370     char                *pStart;
371     int                 bytes;
372
373     IceGetHeader (iceConn, _SmcOpcode, SM_SetProperties,
374         SIZEOF (smSetPropertiesMsg), smSetPropertiesMsg, pMsg);
375
376     LISTOF_PROP_BYTES (numProps, props, bytes);
377     pMsg->length += WORD64COUNT (bytes);
378
379     pBuf = pStart = IceAllocScratch (iceConn, bytes);
380     memset(pStart, 0, bytes);
381
382     STORE_LISTOF_PROPERTY (pBuf, numProps, props);
383
384     IceWriteData (iceConn, bytes, pStart);
385     IceFlush (iceConn);
386 }
387
388
389 \f
390 void
391 SmcDeleteProperties(SmcConn smcConn, int numProps, char **propNames)
392 {
393     IceConn                     iceConn = smcConn->iceConn;
394     smDeletePropertiesMsg       *pMsg;
395     char                        *pData;
396     int                         extra, i;
397
398     extra = 8;
399
400     for (i = 0; i < numProps; i++)
401         extra += ARRAY8_BYTES (strlen (propNames[i]));
402
403     IceGetHeaderExtra (iceConn, _SmcOpcode, SM_DeleteProperties,
404         SIZEOF (smDeletePropertiesMsg), WORD64COUNT (extra),
405         smDeletePropertiesMsg, pMsg, pData);
406
407     STORE_CARD32 (pData, numProps);
408     pData += 4;
409
410     for (i = 0; i < numProps; i++)
411         STORE_ARRAY8 (pData, strlen (propNames[i]), propNames[i]); 
412
413     IceFlush (iceConn);
414 }
415
416
417 \f
418 Status
419 SmcGetProperties(SmcConn smcConn, SmcPropReplyProc propReplyProc,
420                  SmPointer clientData)
421 {
422     IceConn             iceConn = smcConn->iceConn;
423     _SmcPropReplyWait   *wait, *ptr;
424
425     if ((wait = (_SmcPropReplyWait *) malloc (
426         sizeof (_SmcPropReplyWait))) == NULL)
427     {
428         return (0);
429     }
430
431     wait->prop_reply_proc = propReplyProc;
432     wait->client_data = clientData;
433     wait->next = NULL;
434
435     ptr = smcConn->prop_reply_waits;
436     while (ptr && ptr->next)
437         ptr = ptr->next;
438
439     if (ptr == NULL)
440         smcConn->prop_reply_waits = wait;
441     else
442         ptr->next = wait;
443
444     IceSimpleMessage (iceConn, _SmcOpcode, SM_GetProperties);
445     IceFlush (iceConn);
446
447     return (1);
448 }
449
450
451 \f
452 Status
453 SmcInteractRequest(SmcConn smcConn, int dialogType,
454                    SmcInteractProc interactProc, SmPointer clientData)
455 {
456     IceConn                     iceConn = smcConn->iceConn;
457     smInteractRequestMsg        *pMsg;
458     _SmcInteractWait            *wait, *ptr;
459
460     if ((wait = (_SmcInteractWait *) malloc (
461         sizeof (_SmcInteractWait))) == NULL)
462     {
463         return (0);
464     }
465
466     wait->interact_proc = interactProc;
467     wait->client_data = clientData;
468     wait->next = NULL;
469
470     ptr = smcConn->interact_waits;
471     while (ptr && ptr->next)
472         ptr = ptr->next;
473
474     if (ptr == NULL)
475         smcConn->interact_waits = wait;
476     else
477         ptr->next = wait;
478
479     IceGetHeader (iceConn, _SmcOpcode, SM_InteractRequest,
480         SIZEOF (smInteractRequestMsg), smInteractRequestMsg, pMsg);
481
482     pMsg->dialogType = dialogType;
483
484     IceFlush (iceConn);
485
486     return (1);
487 }
488
489
490 \f
491 void
492 SmcInteractDone(SmcConn smcConn, Bool cancelShutdown)
493 {
494     IceConn             iceConn = smcConn->iceConn;
495     smInteractDoneMsg   *pMsg;
496
497     IceGetHeader (iceConn, _SmcOpcode, SM_InteractDone,
498         SIZEOF (smInteractDoneMsg), smInteractDoneMsg, pMsg);
499
500     pMsg->cancelShutdown = cancelShutdown;
501
502     IceFlush (iceConn);
503 }
504
505
506 \f
507 void
508 SmcRequestSaveYourself(SmcConn smcConn, int saveType, Bool shutdown,
509                        int interactStyle, Bool fast, Bool global)
510 {
511     IceConn                     iceConn = smcConn->iceConn;
512     smSaveYourselfRequestMsg    *pMsg;
513
514     IceGetHeader (iceConn, _SmcOpcode, SM_SaveYourselfRequest,
515         SIZEOF (smSaveYourselfRequestMsg), smSaveYourselfRequestMsg, pMsg);
516
517     pMsg->saveType = saveType;
518     pMsg->shutdown = shutdown;
519     pMsg->interactStyle = interactStyle;
520     pMsg->fast = fast;
521     pMsg->global = global;
522
523     IceFlush (iceConn);
524 }
525
526
527 \f
528 Status
529 SmcRequestSaveYourselfPhase2(SmcConn smcConn,
530                              SmcSaveYourselfPhase2Proc saveYourselfPhase2Proc,
531                              SmPointer clientData)
532 {
533     IceConn             iceConn = smcConn->iceConn;
534     _SmcPhase2Wait      *wait;
535
536     if (smcConn->phase2_wait)
537         wait = smcConn->phase2_wait;
538     else
539     {
540         if ((wait = (_SmcPhase2Wait *) malloc (
541             sizeof (_SmcPhase2Wait))) == NULL)
542         {
543             return (0);
544         }
545     }
546
547     wait->phase2_proc = saveYourselfPhase2Proc;
548     wait->client_data = clientData;
549
550     smcConn->phase2_wait = wait;
551
552     IceSimpleMessage (iceConn, _SmcOpcode, SM_SaveYourselfPhase2Request);
553     IceFlush (iceConn);
554
555     return (1);
556 }
557
558
559 \f
560 void
561 SmcSaveYourselfDone(SmcConn smcConn, Bool success)
562 {
563     IceConn                     iceConn = smcConn->iceConn;
564     smSaveYourselfDoneMsg       *pMsg;
565
566     IceGetHeader (iceConn, _SmcOpcode, SM_SaveYourselfDone,
567         SIZEOF (smSaveYourselfDoneMsg), smSaveYourselfDoneMsg, pMsg);
568
569     pMsg->success = success;
570
571     IceFlush (iceConn);
572 }
573
574
575 \f
576 static void
577 set_callbacks(SmcConn smcConn, unsigned long mask, SmcCallbacks *callbacks)
578 {
579     if (mask & SmcSaveYourselfProcMask)
580     {
581         smcConn->callbacks.save_yourself.callback =
582             callbacks->save_yourself.callback;
583         smcConn->callbacks.save_yourself.client_data =
584             callbacks->save_yourself.client_data;
585     }
586
587     if (mask & SmcDieProcMask)
588     {
589         smcConn->callbacks.die.callback = callbacks->die.callback;
590         smcConn->callbacks.die.client_data = callbacks->die.client_data;
591     }
592
593     if (mask & SmcSaveCompleteProcMask)
594     {
595         smcConn->callbacks.save_complete.callback =
596             callbacks->save_complete.callback;
597         smcConn->callbacks.save_complete.client_data =
598             callbacks->save_complete.client_data;
599     }
600
601     if (mask & SmcShutdownCancelledProcMask)
602     {
603         smcConn->callbacks.shutdown_cancelled.callback =
604             callbacks->shutdown_cancelled.callback;
605         smcConn->callbacks.shutdown_cancelled.client_data =
606             callbacks->shutdown_cancelled.client_data;
607     }
608 }