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