sm_client.c revision 0a6b08f8
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 = (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 280SmcCloseStatus 281SmcCloseConnection(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 348void 349SmcModifyCallbacks(SmcConn smcConn, unsigned long mask, SmcCallbacks *callbacks) 350{ 351 set_callbacks (smcConn, mask, callbacks); 352} 353 354 355 356void 357SmcSetProperties(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 382void 383SmcDeleteProperties(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 410Status 411SmcGetProperties(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 443Status 444SmcInteractRequest(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 481void 482SmcInteractDone(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 497void 498SmcRequestSaveYourself(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 518Status 519SmcRequestSaveYourselfPhase2(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 549void 550SmcSaveYourselfDone(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 565static void 566set_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