sm_client.c revision 3c15da26
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 40#ifndef __UNIXOS2__ 41SmsNewClientProc _SmsNewClientProc; 42SmPointer _SmsNewClientData; 43#else 44SmsNewClientProc _SmsNewClientProc = 0; 45SmPointer _SmsNewClientData = 0; 46#endif 47 48SmcErrorHandler _SmcErrorHandler = _SmcDefaultErrorHandler; 49SmsErrorHandler _SmsErrorHandler = _SmsDefaultErrorHandler; 50 51 52static void 53set_callbacks(SmcConn smcConn, unsigned long mask, SmcCallbacks *callbacks); 54 55 56SmcConn 57SmcOpenConnection(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 285SmcCloseStatus 286SmcCloseConnection(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 353void 354SmcModifyCallbacks(SmcConn smcConn, unsigned long mask, SmcCallbacks *callbacks) 355{ 356 set_callbacks (smcConn, mask, callbacks); 357} 358 359 360 361void 362SmcSetProperties(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 387void 388SmcDeleteProperties(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 415Status 416SmcGetProperties(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 448Status 449SmcInteractRequest(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 486void 487SmcInteractDone(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 502void 503SmcRequestSaveYourself(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 523Status 524SmcRequestSaveYourselfPhase2(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 554void 555SmcSaveYourselfDone(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 570static void 571set_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} 603