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