sm_client.c revision 6bea0e4f
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 37int _SmcOpcode = 0; 38int _SmsOpcode = 0; 39 40SmsNewClientProc _SmsNewClientProc; 41SmPointer _SmsNewClientData; 42 43SmcErrorHandler _SmcErrorHandler = _SmcDefaultErrorHandler; 44SmsErrorHandler _SmsErrorHandler = _SmsDefaultErrorHandler; 45 46 47static void 48set_callbacks(SmcConn smcConn, unsigned long mask, SmcCallbacks *callbacks); 49 50 51SmcConn 52SmcOpenConnection(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 = 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 if (pData != NULL) { 208 STORE_ARRAY8 (pData, len, previousId); 209 IceFlush (iceConn); 210 } 211 else { 212 SEND_ARRAY8 (iceConn, len, previousId); 213 } 214 215 replyWait.sequence_of_request = IceLastSentSequenceNumber (iceConn); 216 replyWait.major_opcode_of_request = _SmcOpcode; 217 replyWait.minor_opcode_of_request = SM_RegisterClient; 218 replyWait.reply = (IcePointer) &reply; 219 220 gotReply = False; 221 ioErrorOccured = False; 222 223 while (!gotReply && !ioErrorOccured) 224 { 225 ioErrorOccured = (IceProcessMessages ( 226 iceConn, &replyWait, &gotReply) == IceProcessMessagesIOError); 227 228 if (ioErrorOccured) 229 { 230 if (errorStringRet && errorLength > 0) { 231 strncpy (errorStringRet, "IO error occurred opening connection", 232 errorLength); 233 errorStringRet[errorLength - 1] = '\0'; 234 } 235 free (smcConn->vendor); 236 free (smcConn->release); 237 free (smcConn); 238 239 return (NULL); 240 } 241 else if (gotReply) 242 { 243 if (reply.status == 1) 244 { 245 /* 246 * The client successfully registered. 247 */ 248 249 *clientIdRet = reply.client_id; 250 251 smcConn->client_id = strdup (*clientIdRet); 252 } 253 else 254 { 255 /* 256 * Could not register the client because the previous ID 257 * was bad. So now we register the client with the 258 * previous ID set to NULL. 259 */ 260 261 extra = ARRAY8_BYTES (0); 262 263 IceGetHeaderExtra (iceConn, _SmcOpcode, SM_RegisterClient, 264 SIZEOF (smRegisterClientMsg), WORD64COUNT (extra), 265 smRegisterClientMsg, pMsg, pData); 266 267 if (pData != NULL) { 268 STORE_ARRAY8 (pData, 0, ""); 269 IceFlush (iceConn); 270 } 271 else { 272 SEND_ARRAY8 (iceConn, 0, ""); 273 } 274 275 replyWait.sequence_of_request = 276 IceLastSentSequenceNumber (iceConn); 277 278 gotReply = False; 279 } 280 } 281 } 282 283 return (smcConn); 284} 285 286 287 288SmcCloseStatus 289SmcCloseConnection(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 if (pData != NULL) { 308 STORE_CARD32 (pData, (CARD32) count); 309 STORE_CARD32 (pData, (CARD32) 0); /* padding */ 310 311 for (i = 0; i < count; i++) 312 STORE_ARRAY8 (pData, strlen (reasonMsgs[i]), reasonMsgs[i]); 313 314 IceFlush (iceConn); 315 } else { 316 CARD32 count_header[2] = { 317 (CARD32) count, 318 (CARD32) 0 /* padding */ 319 }; 320 IceWriteData32 (iceConn, 8, count_header); 321 322 for (i = 0; i < count; i++) 323 SEND_ARRAY8 (iceConn, strlen (reasonMsgs[i]), reasonMsgs[i]); 324 } 325 326 IceProtocolShutdown (iceConn, _SmcOpcode); 327 IceSetShutdownNegotiation (iceConn, False); 328 closeStatus = IceCloseConnection (iceConn); 329 330 if (smcConn->vendor) 331 free (smcConn->vendor); 332 333 if (smcConn->release) 334 free (smcConn->release); 335 336 if (smcConn->client_id) 337 free (smcConn->client_id); 338 339 if (smcConn->interact_waits) 340 { 341 _SmcInteractWait *ptr = smcConn->interact_waits; 342 _SmcInteractWait *next; 343 344 while (ptr) 345 { 346 next = ptr->next; 347 free (ptr); 348 ptr = next; 349 } 350 } 351 352 if (smcConn->phase2_wait) 353 free (smcConn->phase2_wait); 354 355 if (smcConn->prop_reply_waits) 356 { 357 _SmcPropReplyWait *ptr = smcConn->prop_reply_waits; 358 _SmcPropReplyWait *next; 359 360 while (ptr) 361 { 362 next = ptr->next; 363 free (ptr); 364 ptr = next; 365 } 366 367 } 368 369 free (smcConn); 370 371 if (closeStatus == IceClosedNow) 372 statusRet = SmcClosedNow; 373 else if (closeStatus == IceClosedASAP) 374 statusRet = SmcClosedASAP; 375 else 376 statusRet = SmcConnectionInUse; 377 378 return (statusRet); 379} 380 381 382 383void 384SmcModifyCallbacks(SmcConn smcConn, unsigned long mask, SmcCallbacks *callbacks) 385{ 386 set_callbacks (smcConn, mask, callbacks); 387} 388 389 390 391void 392SmcSetProperties(SmcConn smcConn, int numProps, SmProp **props) 393{ 394 IceConn iceConn = smcConn->iceConn; 395 smSetPropertiesMsg *pMsg; 396 char *pBuf; 397 char *pStart; 398 unsigned int bytes; 399 400 IceGetHeader (iceConn, _SmcOpcode, SM_SetProperties, 401 SIZEOF (smSetPropertiesMsg), smSetPropertiesMsg, pMsg); 402 403 LISTOF_PROP_BYTES (numProps, props, bytes); 404 pMsg->length += WORD64COUNT (bytes); 405 406 pBuf = pStart = IceAllocScratch (iceConn, bytes); 407 memset(pStart, 0, bytes); 408 409 STORE_LISTOF_PROPERTY (pBuf, numProps, props); 410 411 IceWriteData (iceConn, bytes, pStart); 412 IceFlush (iceConn); 413} 414 415 416 417void 418SmcDeleteProperties(SmcConn smcConn, int numProps, char **propNames) 419{ 420 IceConn iceConn = smcConn->iceConn; 421 smDeletePropertiesMsg *pMsg; 422 char *pData; 423 int extra, i; 424 425 extra = 8; 426 427 for (i = 0; i < numProps; i++) 428 extra += ARRAY8_BYTES (strlen (propNames[i])); 429 430 IceGetHeaderExtra (iceConn, _SmcOpcode, SM_DeleteProperties, 431 SIZEOF (smDeletePropertiesMsg), WORD64COUNT (extra), 432 smDeletePropertiesMsg, pMsg, pData); 433 434 if (pData != NULL) { 435 STORE_CARD32 (pData, (CARD32) numProps); 436 STORE_CARD32 (pData, (CARD32) 0); /* padding */ 437 438 for (i = 0; i < numProps; i++) 439 STORE_ARRAY8 (pData, strlen (propNames[i]), propNames[i]); 440 441 IceFlush (iceConn); 442 } 443 else { 444 CARD32 count_header[2] = { 445 (CARD32) numProps, 446 (CARD32) 0 /* padding */ 447 }; 448 IceWriteData32 (iceConn, 8, count_header); 449 450 for (i = 0; i < numProps; i++) 451 SEND_ARRAY8 (iceConn, strlen (propNames[i]), propNames[i]); 452 } 453} 454 455 456 457Status 458SmcGetProperties(SmcConn smcConn, SmcPropReplyProc propReplyProc, 459 SmPointer clientData) 460{ 461 IceConn iceConn = smcConn->iceConn; 462 _SmcPropReplyWait *wait, *ptr; 463 464 if ((wait = malloc (sizeof (_SmcPropReplyWait))) == NULL) 465 { 466 return (0); 467 } 468 469 wait->prop_reply_proc = propReplyProc; 470 wait->client_data = clientData; 471 wait->next = NULL; 472 473 ptr = smcConn->prop_reply_waits; 474 while (ptr && ptr->next) 475 ptr = ptr->next; 476 477 if (ptr == NULL) 478 smcConn->prop_reply_waits = wait; 479 else 480 ptr->next = wait; 481 482 IceSimpleMessage (iceConn, _SmcOpcode, SM_GetProperties); 483 IceFlush (iceConn); 484 485 return (1); 486} 487 488 489 490Status 491SmcInteractRequest(SmcConn smcConn, int dialogType, 492 SmcInteractProc interactProc, SmPointer clientData) 493{ 494 IceConn iceConn = smcConn->iceConn; 495 smInteractRequestMsg *pMsg; 496 _SmcInteractWait *wait, *ptr; 497 498 if ((wait = malloc (sizeof (_SmcInteractWait))) == NULL) 499 { 500 return (0); 501 } 502 503 wait->interact_proc = interactProc; 504 wait->client_data = clientData; 505 wait->next = NULL; 506 507 ptr = smcConn->interact_waits; 508 while (ptr && ptr->next) 509 ptr = ptr->next; 510 511 if (ptr == NULL) 512 smcConn->interact_waits = wait; 513 else 514 ptr->next = wait; 515 516 IceGetHeader (iceConn, _SmcOpcode, SM_InteractRequest, 517 SIZEOF (smInteractRequestMsg), smInteractRequestMsg, pMsg); 518 519 pMsg->dialogType = dialogType; 520 521 IceFlush (iceConn); 522 523 return (1); 524} 525 526 527 528void 529SmcInteractDone(SmcConn smcConn, Bool cancelShutdown) 530{ 531 IceConn iceConn = smcConn->iceConn; 532 smInteractDoneMsg *pMsg; 533 534 IceGetHeader (iceConn, _SmcOpcode, SM_InteractDone, 535 SIZEOF (smInteractDoneMsg), smInteractDoneMsg, pMsg); 536 537 pMsg->cancelShutdown = cancelShutdown; 538 539 IceFlush (iceConn); 540} 541 542 543 544void 545SmcRequestSaveYourself(SmcConn smcConn, int saveType, Bool shutdown, 546 int interactStyle, Bool fast, Bool global) 547{ 548 IceConn iceConn = smcConn->iceConn; 549 smSaveYourselfRequestMsg *pMsg; 550 551 IceGetHeader (iceConn, _SmcOpcode, SM_SaveYourselfRequest, 552 SIZEOF (smSaveYourselfRequestMsg), smSaveYourselfRequestMsg, pMsg); 553 554 pMsg->saveType = saveType; 555 pMsg->shutdown = shutdown; 556 pMsg->interactStyle = interactStyle; 557 pMsg->fast = fast; 558 pMsg->global = global; 559 560 IceFlush (iceConn); 561} 562 563 564 565Status 566SmcRequestSaveYourselfPhase2(SmcConn smcConn, 567 SmcSaveYourselfPhase2Proc saveYourselfPhase2Proc, 568 SmPointer clientData) 569{ 570 IceConn iceConn = smcConn->iceConn; 571 _SmcPhase2Wait *wait; 572 573 if (smcConn->phase2_wait) 574 wait = smcConn->phase2_wait; 575 else 576 { 577 if ((wait = malloc (sizeof (_SmcPhase2Wait))) == NULL) 578 { 579 return (0); 580 } 581 } 582 583 wait->phase2_proc = saveYourselfPhase2Proc; 584 wait->client_data = clientData; 585 586 smcConn->phase2_wait = wait; 587 588 IceSimpleMessage (iceConn, _SmcOpcode, SM_SaveYourselfPhase2Request); 589 IceFlush (iceConn); 590 591 return (1); 592} 593 594 595 596void 597SmcSaveYourselfDone(SmcConn smcConn, Bool success) 598{ 599 IceConn iceConn = smcConn->iceConn; 600 smSaveYourselfDoneMsg *pMsg; 601 602 IceGetHeader (iceConn, _SmcOpcode, SM_SaveYourselfDone, 603 SIZEOF (smSaveYourselfDoneMsg), smSaveYourselfDoneMsg, pMsg); 604 605 pMsg->success = success; 606 607 IceFlush (iceConn); 608} 609 610 611 612static void 613set_callbacks(SmcConn smcConn, unsigned long mask, SmcCallbacks *callbacks) 614{ 615 if (mask & SmcSaveYourselfProcMask) 616 { 617 smcConn->callbacks.save_yourself.callback = 618 callbacks->save_yourself.callback; 619 smcConn->callbacks.save_yourself.client_data = 620 callbacks->save_yourself.client_data; 621 } 622 623 if (mask & SmcDieProcMask) 624 { 625 smcConn->callbacks.die.callback = callbacks->die.callback; 626 smcConn->callbacks.die.client_data = callbacks->die.client_data; 627 } 628 629 if (mask & SmcSaveCompleteProcMask) 630 { 631 smcConn->callbacks.save_complete.callback = 632 callbacks->save_complete.callback; 633 smcConn->callbacks.save_complete.client_data = 634 callbacks->save_complete.client_data; 635 } 636 637 if (mask & SmcShutdownCancelledProcMask) 638 { 639 smcConn->callbacks.shutdown_cancelled.callback = 640 callbacks->shutdown_cancelled.callback; 641 smcConn->callbacks.shutdown_cancelled.client_data = 642 callbacks->shutdown_cancelled.client_data; 643 } 644} 645