Home | History | Annotate | Line # | Download | only in src
      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