2
0

SmXSMP.c 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491
  1. /*
  2. * CDE - Common Desktop Environment
  3. *
  4. * Copyright (c) 1993-2012, The Open Group. All rights reserved.
  5. *
  6. * These libraries and programs are free software; you can
  7. * redistribute them and/or modify them under the terms of the GNU
  8. * Lesser General Public License as published by the Free Software
  9. * Foundation; either version 2 of the License, or (at your option)
  10. * any later version.
  11. *
  12. * These libraries and programs are distributed in the hope that
  13. * they will be useful, but WITHOUT ANY WARRANTY; without even the
  14. * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  15. * PURPOSE. See the GNU Lesser General Public License for more
  16. * details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public
  19. * License along with these libraries and programs; if not, write
  20. * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
  21. * Floor, Boston, MA 02110-1301 USA
  22. */
  23. /*
  24. * (c) Copyright 1995 Digital Equipment Corporation.
  25. * (c) Copyright 1993, 1994, 1995 Hewlett-Packard Company
  26. * (c) Copyright 1993, 1994, 1995 International Business Machines Corp.
  27. * (c) Copyright 1993, 1994, 1995 Sun Microsystems, Inc.
  28. * (c) Copyright 1993, 1994, 1995 Novell, Inc.
  29. * (c) Copyright 1995 FUJITSU LIMITED.
  30. * (c) Copyright 1995 Hitachi.
  31. *
  32. * $TOG: SmXSMP.c /main/40 1999/01/18 15:42:07 samborn $
  33. */
  34. /*************************************<+>*************************************
  35. *****************************************************************************
  36. **
  37. ** File: SmXSMP.c
  38. **
  39. ** Project: DT Session Manager (dtsession)
  40. **
  41. *****************************************************************************
  42. *************************************<+>*************************************/
  43. #include <stdio.h>
  44. #include <unistd.h>
  45. #include <string.h>
  46. #include "SmXSMP.h"
  47. #include "SmAuth.h"
  48. #include "SmWatch.h"
  49. #include "SmProp.h"
  50. #include "Sm.h"
  51. #include "SmUI.h"
  52. #include "SmSave.h"
  53. #include "SmRestore.h"
  54. #include "SmGlobals.h"
  55. #include <X11/Xlib.h>
  56. #include <X11/Intrinsic.h>
  57. #include <X11/Xatom.h>
  58. #include <X11/SM/SMlib.h>
  59. #include <Dt/MsgLog.h>
  60. #include <Dt/Lock.h>
  61. #include <Dt/Wsm.h>
  62. #include <Tt/tt_c.h>
  63. /*
  64. * Private constants
  65. */
  66. #define ERRORMSGLEN 256
  67. #define GET_CLIENT_WORKSPACE_MSG "GetWsmClients"
  68. /*
  69. * Private variables
  70. */
  71. static Boolean authenticationInitialized = False;
  72. static char * networkIds;
  73. /*
  74. * Private functions
  75. */
  76. static void InitializeXSMPGlobals ();
  77. static void PutSessionManagerOnRootWindow (
  78. char *networkIds);
  79. static void InitializeSaveState (
  80. Boolean startUp);
  81. static Boolean SendGetWsmClientsMessage ();
  82. static int GetCurrentWorkspaceNumber ();
  83. static void ProcessInteract (
  84. ClientRecPtr client,
  85. Boolean getWsmClientOK);
  86. static void CancelShutdown ();
  87. static void FreeProps (
  88. PropertyRecPtr pProp);
  89. static void ProcessSaveYourselfResponses ();
  90. /*
  91. * Public variables
  92. */
  93. XSMPSettings smXSMP;
  94. ClientRecPtr connectedList;
  95. Atom XaSmClientId;
  96. /*
  97. * Public functins
  98. */
  99. void InstallIOErrorHandler ();
  100. Status NewClientProc (
  101. SmsConn smsConn,
  102. SmPointer managerData,
  103. unsigned long *maskRet,
  104. SmsCallbacks *callbacksRet,
  105. char **failureReasonRet);
  106. void NewConnectionXtProc (
  107. XtPointer client_data,
  108. int *source,
  109. XtInputId *id);
  110. Status RegisterClientProc (
  111. SmsConn smsConn,
  112. SmPointer managerData,
  113. char *previousId);
  114. void InteractRequestProc (
  115. SmsConn smsConn,
  116. SmPointer managerData,
  117. int dialogType);
  118. void InteractDoneProc (
  119. SmsConn smsConn,
  120. SmPointer managerData,
  121. Bool cancelShutdown);
  122. void SaveYourselfReqProc (
  123. SmsConn smsConn,
  124. SmPointer managerData,
  125. int saveType,
  126. Bool shutdown,
  127. int interactStyle,
  128. Bool fast,
  129. Bool global);
  130. void SaveYourselfPhase2ReqProc (
  131. SmsConn smsConn,
  132. SmPointer managerData);
  133. void SaveYourselfDoneProc (
  134. SmsConn smsConn,
  135. SmPointer managerData,
  136. Bool success);
  137. void CloseConnectionProc (
  138. SmsConn smsConn,
  139. SmPointer managerData,
  140. int count,
  141. char **reasonMsgs);
  142. void CompleteXSMPSave ();
  143. void CloseDownClient (
  144. ClientRecPtr client );
  145. /*
  146. * List manipulation functions
  147. */
  148. void AddClient (
  149. ClientRecPtr newClient);
  150. /*
  151. * Functions
  152. */
  153. Boolean InitXSMP (void)
  154. {
  155. char errorMsg[ERRORMSGLEN];
  156. char *env;
  157. int i;
  158. InitializeXSMPGlobals ();
  159. InstallIOErrorHandler ();
  160. if (!SmsInitialize (SM_VENDOR_NAME, SM_RELEASE_NAME,
  161. NewClientProc, NULL,
  162. HostBasedAuthProc,
  163. ERRORMSGLEN, errorMsg)) {
  164. DtMsgLogMessage (smGD.programName, DtMsgLogError, errorMsg);
  165. PostXSMPFailureDialog (XSMP_FAILURE_SMS_INITIALIZE, True);
  166. }
  167. if (!IceListenForConnections (&smXSMP.numTransports,
  168. &smXSMP.listenObjs,
  169. ERRORMSGLEN, errorMsg)) {
  170. DtMsgLogMessage (smGD.programName, DtMsgLogError, errorMsg);
  171. PostXSMPFailureDialog (XSMP_FAILURE_ICE_LISTEN, True);
  172. }
  173. if (!SetAuthentication (smXSMP.numTransports,
  174. smXSMP.listenObjs,
  175. &smXSMP.authDataEntries))
  176. PostXSMPFailureDialog (XSMP_FAILURE_AUTHENTICATION, False);
  177. authenticationInitialized = True;
  178. if (!InitWatchProcs (smGD.appCon))
  179. PostXSMPFailureDialog (XSMP_FAILURE_ICE_ADD_WATCH, False);
  180. for (i = 0; i < smXSMP.numTransports; i++) {
  181. XtAppAddInput (smGD.appCon,
  182. IceGetListenConnectionNumber (smXSMP.listenObjs[i]),
  183. (XtPointer) XtInputReadMask,
  184. NewConnectionXtProc, (XtPointer) smXSMP.listenObjs[i]);
  185. }
  186. networkIds = IceComposeNetworkIdList (smXSMP.numTransports,
  187. smXSMP.listenObjs);
  188. if (!networkIds)
  189. PostXSMPFailureDialog (XSMP_FAILURE_ICE_COMPOSE_IDS, False);
  190. env = (char *) XtMalloc (strlen (SM_SESSION_MANAGER) +
  191. strlen (networkIds) + 2);
  192. if (!env) {
  193. free (networkIds);
  194. PostXSMPFailureDialog (XSMP_FAILURE_MALLOC, False);
  195. } else {
  196. (void) sprintf (env, "%s=%s", SM_SESSION_MANAGER, networkIds);
  197. (void) putenv (env);
  198. }
  199. PutSessionManagerOnRootWindow (networkIds);
  200. XaSmClientId = XInternAtom(smGD.display, SM_CLIENT_ID, False);
  201. #ifdef DEBUG
  202. printf ("%s\n", env);
  203. #endif /* DEBUG */
  204. return (True);
  205. }
  206. static void
  207. PutSessionManagerOnRootWindow (
  208. char *networkIds)
  209. {
  210. Atom sessionManager;
  211. sessionManager = XInternAtom(smGD.display, SM_SESSION_MANAGER, False);
  212. XChangeProperty(smGD.display, RootWindow(smGD.display, 0),
  213. sessionManager, XA_STRING, 8, PropModeReplace,
  214. (unsigned char *) networkIds, strlen((char *)networkIds));
  215. }
  216. static void
  217. InitializeSaveState (
  218. Boolean startUp)
  219. {
  220. smXSMP.saveState.global = False;
  221. smXSMP.saveState.shutdown = False;
  222. smXSMP.saveState.interactStyle = SmInteractStyleAny;
  223. smXSMP.saveState.clientInteracting = False;
  224. smXSMP.saveState.inProgress = False;
  225. smXSMP.saveState.doneSuccess = True;
  226. smXSMP.saveState.saveComplete = False;
  227. smXSMP.saveState.interactCount = 0;
  228. smXSMP.saveState.numClientIds = 0;
  229. smXSMP.saveState.interactClient = NULL;
  230. if (startUp) {
  231. smXSMP.saveState.clientIds = NULL;
  232. smXSMP.saveState.workspaceNums = NULL;
  233. } else {
  234. if (smXSMP.saveState.clientIds) {
  235. free (smXSMP.saveState.clientIds);
  236. smXSMP.saveState.clientIds = NULL;
  237. }
  238. if (smXSMP.saveState.workspaceNums) {
  239. free (smXSMP.saveState.workspaceNums);
  240. smXSMP.saveState.workspaceNums = NULL;
  241. }
  242. }
  243. }
  244. static void
  245. InitializeXSMPGlobals (void)
  246. {
  247. smXSMP.authDataEntries = NULL;
  248. connectedList = NULL;
  249. smXSMP.xsmpDbList = NULL;
  250. smXSMP.dbVersion = SM_VENDOR_NAME;
  251. smXSMP.dbSessionId = SM_RELEASE_NAME;
  252. InitializeSaveState (True);
  253. }
  254. /*ARGSUSED*/
  255. Status
  256. NewClientProc (
  257. SmsConn smsConn,
  258. SmPointer managerData,
  259. unsigned long *maskRet,
  260. SmsCallbacks *callbacksRet,
  261. char **failureReasonRet)
  262. {
  263. ClientRecPtr newClient;
  264. #ifdef DEBUG
  265. (void) printf ("\nNewClientProc: IceConn fd = %d\n",
  266. IceConnectionNumber (SmsGetIceConnection (smsConn)));
  267. #endif /* DEBUG */
  268. newClient = (ClientRecPtr) XtMalloc (sizeof (ClientRec));
  269. if (!newClient) {
  270. char *str;
  271. str = strdup ((char *) GETMESSAGE (4, 5,
  272. "Unable to malloc memory for operation."));
  273. if (str) {
  274. if ((*failureReasonRet = (char *)
  275. XtMalloc ( strlen (str) + 1)) != NULL)
  276. strcpy (*failureReasonRet, str);
  277. DtMsgLogMessage (smGD.programName, DtMsgLogError, str);
  278. free (str);
  279. }
  280. return (0);
  281. }
  282. *maskRet = 0;
  283. newClient->smConn = smsConn;
  284. newClient->iceConn = SmsGetIceConnection (smsConn);
  285. newClient->clientId = NULL;
  286. newClient->clientHost = NULL;
  287. newClient->screenNum = 0;
  288. newClient->restartHint = SmRestartIfRunning;
  289. newClient->props = NULL;
  290. newClient->active = False;
  291. newClient->saveYourselfDone = False;
  292. newClient->saveYourselfP2Requested = False;
  293. newClient->interactRequested = False;
  294. newClient->next = NULL;
  295. AddClient (newClient);
  296. *maskRet |= SmsRegisterClientProcMask;
  297. callbacksRet->register_client.callback = RegisterClientProc;
  298. callbacksRet->register_client.manager_data = (SmPointer) newClient;
  299. *maskRet |= SmsInteractRequestProcMask;
  300. callbacksRet->interact_request.callback = InteractRequestProc;
  301. callbacksRet->interact_request.manager_data = (SmPointer) newClient;
  302. *maskRet |= SmsInteractDoneProcMask;
  303. callbacksRet->interact_done.callback = InteractDoneProc;
  304. callbacksRet->interact_done.manager_data = (SmPointer) newClient;
  305. *maskRet |= SmsSaveYourselfRequestProcMask;
  306. callbacksRet->save_yourself_request.callback = SaveYourselfReqProc;
  307. callbacksRet->save_yourself_request.manager_data =
  308. (SmPointer) newClient;
  309. *maskRet |= SmsSaveYourselfP2RequestProcMask;
  310. callbacksRet->save_yourself_phase2_request.callback =
  311. SaveYourselfPhase2ReqProc;
  312. callbacksRet->save_yourself_phase2_request.manager_data =
  313. (SmPointer) newClient;
  314. *maskRet |= SmsSaveYourselfDoneProcMask;
  315. callbacksRet->save_yourself_done.callback = SaveYourselfDoneProc;
  316. callbacksRet->save_yourself_done.manager_data = (SmPointer) newClient;
  317. *maskRet |= SmsCloseConnectionProcMask;
  318. callbacksRet->close_connection.callback = CloseConnectionProc;
  319. callbacksRet->close_connection.manager_data = (SmPointer) newClient;
  320. *maskRet |= SmsSetPropertiesProcMask;
  321. callbacksRet->set_properties.callback = SetPropertiesProc;
  322. callbacksRet->set_properties.manager_data = (SmPointer) newClient;
  323. *maskRet |= SmsDeletePropertiesProcMask;
  324. callbacksRet->delete_properties.callback = DeletePropertiesProc;
  325. callbacksRet->delete_properties.manager_data = (SmPointer) newClient;
  326. *maskRet |= SmsGetPropertiesProcMask;
  327. callbacksRet->get_properties.callback = GetPropertiesProc;
  328. callbacksRet->get_properties.manager_data = (SmPointer) newClient;
  329. return (True);
  330. }
  331. /*ARGSUSED*/
  332. void
  333. NewConnectionXtProc (
  334. XtPointer client_data,
  335. int *source,
  336. XtInputId *id)
  337. {
  338. IceConn ice_conn;
  339. IceAcceptStatus status;
  340. #ifdef DEBUG
  341. (void) printf ("NewConnectionXtProc [fd = %d]\n", *source);
  342. #endif /* DEBUG */
  343. if (smXSMP.saveState.shutdown == True)
  344. {
  345. /*
  346. * Don't accept new connections if we are in the middle
  347. * of a shutdown.
  348. */
  349. return;
  350. }
  351. ice_conn = IceAcceptConnection((IceListenObj) client_data, &status);
  352. if (!ice_conn) {
  353. char *message;
  354. message = strdup ((char *) GETMESSAGE (40, 20,
  355. "IceAcceptConnection failed."));
  356. if (message) {
  357. DtMsgLogMessage (smGD.programName, DtMsgLogError,
  358. message);
  359. free (message);
  360. }
  361. } else {
  362. IceConnectStatus cstatus;
  363. while ((cstatus = IceConnectionStatus (ice_conn)) ==
  364. IceConnectPending) {
  365. XtAppProcessEvent (smGD.appCon, XtIMAll);
  366. }
  367. if (cstatus == IceConnectAccepted) {
  368. #ifdef DEBUG
  369. char *connstr;
  370. printf ("ICE Connection opened IceConn fd = %d, ",
  371. IceConnectionNumber (ice_conn));
  372. connstr = IceConnectionString (ice_conn);
  373. printf ("\tAccept at networkId %s\n\n", connstr);
  374. free (connstr);
  375. #else
  376. return;
  377. #endif /* DEBUG */
  378. } else {
  379. #ifdef DEBUG
  380. if (cstatus == IceConnectIOError)
  381. printf ("IO error opening ICE Connection!\n");
  382. else
  383. printf ("ICE Connection rejected!\n");
  384. #endif /* DEBUG */
  385. }
  386. }
  387. }
  388. Status
  389. RegisterClientProc (
  390. SmsConn smsConn,
  391. SmPointer managerData,
  392. char *previousId)
  393. {
  394. ClientRec *client = (ClientRec *) managerData;
  395. char *id = previousId;
  396. Boolean sendSave = False;
  397. char *pchar;
  398. #ifdef DEBUG
  399. int i;
  400. #endif /* DEBUG */
  401. #ifdef DEBUG
  402. (void) printf ("Received REGISTER CLIENT [%d] - id = %s\n",
  403. smsConn, previousId ? previousId : "New Client");
  404. #endif /* DEBUG */
  405. if (!previousId) {
  406. id = SmsGenerateClientID (smsConn);
  407. sendSave = True;
  408. }
  409. else {
  410. ClientRecPtr pClientRec;
  411. XSMPClientDBRecPtr pDbRec;
  412. Boolean found = False;
  413. for (pClientRec = connectedList; pClientRec != NULL;
  414. pClientRec = pClientRec->next) {
  415. if (!strcmp (pClientRec->clientId, previousId)) {
  416. #ifdef DEBUG
  417. (void) printf ("\tAlready connected.\n");
  418. #endif /* DEBUG */
  419. if (!pClientRec->active)
  420. /*
  421. * A client that terminated is
  422. * re-using its id
  423. */
  424. found = True;
  425. break;
  426. }
  427. }
  428. for (pDbRec = smXSMP.xsmpDbList;
  429. pDbRec != NULL && found == False;
  430. pDbRec = pDbRec->next) {
  431. if (!strcmp (pDbRec->clientId, previousId)) {
  432. #ifdef DEBUG
  433. (void) printf ("\tClient in DB.\n");
  434. #endif /* DEBUG */
  435. found = True;
  436. }
  437. }
  438. if (!found) {
  439. /*
  440. * The client is using an invalid id or
  441. * this clientID is already being used.
  442. * Reject the connection.
  443. */
  444. #ifdef DEBUG
  445. (void) printf ("\tID is NOT valid.\n");
  446. #endif /* DEBUG */
  447. free (previousId);
  448. return (0);
  449. }
  450. }
  451. client->clientId = strdup (id);
  452. pchar = SmsClientHostName (smsConn);
  453. if (pchar)
  454. client->clientHost = (strchr (pchar, '/')) + 1;
  455. else
  456. client->clientHost = pchar;
  457. client->active = True;
  458. SmsRegisterClientReply (smsConn, id);
  459. if (sendSave)
  460. SmsSaveYourself (smsConn, SmSaveLocal, False,
  461. SmInteractStyleNone, False);
  462. #ifdef DEBUG
  463. (void) printf ("CLIENTS REGISTERED:\n");
  464. for (i = 1, client = connectedList;
  465. client != NULL;
  466. i++, client = client->next) {
  467. if (client->active)
  468. (void) printf ("\t[%2d] = %s\n", i, client->clientId);
  469. }
  470. #endif /* DEBUG */
  471. return (1);
  472. }
  473. /*ARGSUSED*/
  474. void
  475. InteractRequestProc (
  476. SmsConn smsConn,
  477. SmPointer managerData,
  478. int dialogType)
  479. {
  480. ClientRecPtr client = (ClientRecPtr) managerData;
  481. Boolean getWsmClientOK = True;
  482. #ifdef DEBUG
  483. (void) printf ("Received INTERACT REQUEST [%d]\n", smsConn);
  484. if (dialogType == SmDialogError)
  485. (void) printf ("\tSmDialogError\n");
  486. else if (dialogType == SmDialogNormal)
  487. (void) printf ("\tSmDialogNormal\n");
  488. else
  489. (void) printf ("\tSMlib Error: should have checked for bad value\n");
  490. #endif /* DEBUG */
  491. client->interactRequested = True;
  492. if (smXSMP.saveState.interactCount == 0) {
  493. /*
  494. * Only need to get the Wkspace list once for a save
  495. */
  496. smXSMP.saveState.interactCount++;
  497. if (!SendGetWsmClientsMessage ()) {
  498. char *pch;
  499. pch = strdup ((char *) GETMESSAGE (40, 17,
  500. "An attempt to get a client list from the 'Window Manager' failed."));
  501. if (pch) {
  502. DtMsgLogMessage (smGD.programName,
  503. DtMsgLogWarning, pch);
  504. free (pch);
  505. }
  506. getWsmClientOK = False;
  507. } else {
  508. /*
  509. * Cann't do anything else until the GetWsmClients
  510. * message handler is invoked.
  511. *
  512. * Must cache this client because it is needed in the
  513. * GetWsmClients callback and ToolTalk apparently
  514. * doesn't allow 'client_data' to be assigned to its
  515. * callback funtions.
  516. */
  517. smXSMP.saveState.interactClient = client;
  518. return;
  519. }
  520. }
  521. ProcessInteract (client, getWsmClientOK);
  522. }
  523. /*ARGSUSED*/
  524. void
  525. InteractDoneProc (
  526. SmsConn smsConn,
  527. SmPointer managerData,
  528. Bool cancelShutdown)
  529. {
  530. ClientRecPtr client = (ClientRecPtr) managerData;
  531. #ifdef DEBUG
  532. (void) printf ("Received INTERACT DONE [%d] - Cancel Shutdown = %s\n",
  533. smsConn, cancelShutdown ? "True" : "False");
  534. #endif /* DEBUG */
  535. client->interactRequested = False;
  536. smXSMP.saveState.clientInteracting = False;
  537. if (cancelShutdown)
  538. smXSMP.saveState.shutdownCanceled = True;
  539. if (cancelShutdown &&
  540. smXSMP.saveState.shutdown == True &&
  541. (smXSMP.saveState.interactStyle == SmInteractStyleErrors ||
  542. (smXSMP.saveState.interactStyle == SmInteractStyleAny))) {
  543. ClientRecPtr pClientRec;
  544. char *pch;
  545. for (pClientRec = connectedList; pClientRec != NULL;
  546. pClientRec = pClientRec->next) {
  547. SmsShutdownCancelled (pClientRec->smConn);
  548. #ifdef DEBUG
  549. (void) printf ("Sent ShutdownCancelled to %d\n",
  550. pClientRec->smConn);
  551. #endif /* DEBUG */
  552. }
  553. pch = strdup ((char *) GETMESSAGE (40, 22, "A session shutdown was cancelled by the application '%s'."));
  554. if (pch) {
  555. DtMsgLogMessage (smGD.programName,
  556. DtMsgLogInformation,
  557. pch,
  558. GetArrayPropertyValue (client,
  559. SmProgram));
  560. free (pch);
  561. }
  562. return;
  563. }
  564. ProcessInteract (client, True);
  565. }
  566. /*ARGSUSED*/
  567. void
  568. SaveYourselfReqProc (
  569. SmsConn smsConn,
  570. SmPointer managerData,
  571. int saveType,
  572. Bool shutdown,
  573. int interactStyle,
  574. Bool fast,
  575. Bool global)
  576. {
  577. ClientRecPtr tmpClient;
  578. ClientRecPtr pClientRec;
  579. Boolean notify = True;
  580. #ifdef DEBUG
  581. (void) printf ("Received SAVE YOURSELF REQUEST [%d].\n", smsConn);
  582. (void) printf ("\tglobal = %s\n", global ? "True" : "False");
  583. (void) printf ("\tshutdown = %s\n", shutdown ? "True" : "False");
  584. (void) printf ("\tfast = %s\n", fast ? "True" : "False");
  585. (void) printf ("\tsaveType = ");
  586. switch (saveType) {
  587. case SmSaveLocal: printf ("SmSaveLocal\n"); break;
  588. case SmSaveGlobal: printf ("SmSaveGlobal\n"); break;
  589. case SmSaveBoth: printf ("SmSaveBoth\n"); break;
  590. default: printf ("save type NOT supported\n");
  591. }
  592. (void) printf ("\tinteractStyle = ");
  593. switch (saveType) {
  594. case SmInteractStyleNone: printf ("SmInteractStyleNone\n");
  595. break;
  596. case SmInteractStyleErrors: printf ("SmInteractStyleErrors\n");
  597. break;
  598. case SmInteractStyleAny: printf ("SmInteractStyleAny\n");
  599. break;
  600. default: printf ("interact style NOT supported\n");
  601. }
  602. #endif /* DEBUG */
  603. if (smXSMP.saveState.inProgress) {
  604. char *pch;
  605. pch = strdup ((char *) GETMESSAGE (40, 21, "The session will not be saved because a Save Session is in progress."));
  606. if (pch) {
  607. DtMsgLogMessage (smGD.programName, DtMsgLogError, pch);
  608. free (pch);
  609. }
  610. return;
  611. }
  612. if (!global) {
  613. /*
  614. * The client wants to be told to save itself but
  615. * no other clients should be notified. [smsConn
  616. * will be NULL if this non-global save came from
  617. * a non-XSMP client (e.g via a ToolTalk message).
  618. */
  619. if (smsConn) {
  620. SmsSaveYourself (smsConn, saveType, shutdown,
  621. interactStyle, fast);
  622. #ifdef DEBUG
  623. (void) printf ("\tSent SaveYourself to %d\n", smsConn);
  624. #endif /* DEBUG */
  625. }
  626. return;
  627. }
  628. smXSMP.saveState.inProgress = True;
  629. smXSMP.saveState.shutdown = shutdown;
  630. smXSMP.saveState.shutdownCanceled = False;
  631. smXSMP.saveState.interactStyle = interactStyle;
  632. smXSMP.saveState.global = global;
  633. /*
  634. * Before notifying the clients, setup a directory
  635. * for them to save their state.
  636. */
  637. if (smGD.homeSave || (smGD.sessionType == HOME_SESSION &&
  638. smSettings.startState == DtSM_HOME_STATE)) {
  639. if (smXSMP.saveState.shutdown)
  640. /*
  641. * Leave the old session dir in place. It
  642. * will only be used by XSMP apps.
  643. */
  644. notify = False;
  645. else
  646. SetupSaveState (True, DtSM_HOME_STATE);
  647. } else {
  648. if (smGD.sessionType == CURRENT_SESSION ||
  649. smGD.sessionType == DEFAULT_SESSION)
  650. SetupSaveState (False, DtSM_CURRENT_STATE);
  651. else if (smGD.sessionType == HOME_SESSION &&
  652. smSettings.startState == DtSM_CURRENT_STATE)
  653. SetupSaveState (False, DtSM_HOME_STATE);
  654. else
  655. SetupSaveState (False, DtSM_HOME_STATE);
  656. }
  657. /*
  658. * Before the XSMP clients are saved, the ICCC apps must be
  659. * sent a WM_SAVE_YOURSELF message. This needs to be done because some
  660. * apps do not update their geometry information until they
  661. * get this message. If an ICCC app doesn't update their geometry,
  662. * then an XSMP-based Window Manager will not have the appropriate
  663. * geometry information and the app will not be restore in the
  664. * appropriate location.
  665. */
  666. if (notify) {
  667. ShowWaitState(True);
  668. NotifyProxyClients ();
  669. ShowWaitState(False);
  670. }
  671. for (pClientRec = connectedList; pClientRec != NULL;
  672. pClientRec = pClientRec->next) {
  673. if (pClientRec->active) {
  674. SmsSaveYourself (pClientRec->smConn, saveType,
  675. shutdown, interactStyle, fast);
  676. #ifdef DEBUG
  677. (void) printf ("\tSent saveyourself to %d\n",
  678. pClientRec->smConn);
  679. #endif /* DEBUG */
  680. }
  681. }
  682. /*
  683. * If all of the clients are P2 clients, then process
  684. * the save now because these clients won't send a
  685. * SaveYourselfDone msg until after they have processed
  686. * a P2 message.
  687. */
  688. tmpClient = NULL;
  689. for (pClientRec = connectedList; pClientRec != NULL;
  690. pClientRec = pClientRec->next) {
  691. if (pClientRec->active) {
  692. if (pClientRec->saveYourselfP2Requested)
  693. tmpClient = pClientRec;
  694. else
  695. return;
  696. }
  697. }
  698. if (tmpClient) {
  699. SmsSaveYourselfPhase2 (tmpClient->smConn);
  700. #ifdef DEBUG
  701. (void) printf ("\tSent SaveYourselfPhase2 to %d\n",
  702. pClientRec->smConn);
  703. #endif /* DEBUG */
  704. }
  705. }
  706. /*ARGSUSED*/
  707. void
  708. SaveYourselfPhase2ReqProc (
  709. SmsConn smsConn,
  710. SmPointer managerData)
  711. {
  712. ClientRecPtr client = (ClientRecPtr) managerData;
  713. #ifdef DEBUG
  714. (void) printf ("Received SAVE YOURSELF PHASE 2 REQUEST [%d]\n",
  715. smsConn);
  716. #endif /* DEBUG */
  717. client->saveYourselfP2Requested = True;
  718. /*
  719. * A client may have sent this message in response to
  720. * the SM's start-up SaveYourself message. So if
  721. * a session isn't currently being saved, return.
  722. */
  723. if (!smXSMP.saveState.inProgress) {
  724. /*
  725. * The client is responding to the start-up SaveYourself
  726. * message - this isn't a user-initiated save.
  727. */
  728. SmsSaveComplete (smsConn);
  729. return;
  730. }
  731. ProcessSaveYourselfResponses ();
  732. }
  733. /*ARGSUSED*/
  734. void
  735. SaveYourselfDoneProc (
  736. SmsConn smsConn,
  737. SmPointer managerData,
  738. Bool success)
  739. {
  740. ClientRecPtr pClientRec = (ClientRec *) managerData;
  741. #ifdef DEBUG
  742. (void) printf ("Received SAVE YOURSELF DONE [%d] - Success = %s\n",
  743. smsConn, success ? "True" : "False");
  744. #endif /* DEBUG */
  745. if (!smXSMP.saveState.inProgress) {
  746. /*
  747. * The client is responding to the start-up SaveYourself
  748. * message - this isn't a user-initiated save.
  749. */
  750. SmsSaveComplete (smsConn);
  751. return;
  752. }
  753. /*
  754. * Cache success if it is a failure - it will be needed later
  755. */
  756. if (success == False)
  757. smXSMP.saveState.doneSuccess = False;
  758. pClientRec->saveYourselfDone = True;
  759. ProcessSaveYourselfResponses ();
  760. }
  761. static void
  762. ProcessSaveYourselfResponses (void)
  763. {
  764. ClientRecPtr pClientRec;
  765. Boolean done = False;
  766. /*
  767. * If all clients are marked as saveYourselfDone, complete
  768. * the save.
  769. */
  770. for (done = True, pClientRec = connectedList;
  771. pClientRec != NULL; pClientRec = pClientRec->next) {
  772. if (pClientRec->active &&
  773. pClientRec->saveYourselfDone == False) {
  774. done = False;
  775. break;
  776. }
  777. }
  778. if (done) {
  779. if (smXSMP.saveState.shutdownCanceled)
  780. CancelShutdown ();
  781. else
  782. CompleteXSMPSave ();
  783. return;
  784. }
  785. /*
  786. * If any client is marked as not having sent a
  787. * SaveYourselfDone message and it is has not been
  788. * marked as having requested a SaveYourselfP2,
  789. * then return.
  790. */
  791. for (pClientRec = connectedList; pClientRec != NULL;
  792. pClientRec = pClientRec->next) {
  793. if (pClientRec->active &&
  794. pClientRec->saveYourselfDone == False &&
  795. pClientRec->saveYourselfP2Requested == False)
  796. return;
  797. }
  798. /*
  799. * Only clients which requested a SaveYourselfP2 have not
  800. * responded with a SaveYourselfDone message.
  801. *
  802. * Tell the P2 clients to save themselves.
  803. */
  804. for (pClientRec = connectedList; pClientRec != NULL;
  805. pClientRec = pClientRec->next) {
  806. if (pClientRec->active) {
  807. if (pClientRec->saveYourselfP2Requested &&
  808. !pClientRec->saveYourselfDone) {
  809. #ifdef DEBUG
  810. (void) printf ("\tSent SaveYourselfPhase2 to %d\n",
  811. pClientRec->smConn);
  812. #endif /* DEBUG */
  813. SmsSaveYourselfPhase2 (pClientRec->smConn);
  814. }
  815. }
  816. }
  817. }
  818. /*ARGSUSED*/
  819. void
  820. CloseConnectionProc (
  821. SmsConn smsConn,
  822. SmPointer managerData,
  823. int count,
  824. char **reasonMsgs)
  825. {
  826. ClientRecPtr pClientRec = (ClientRec *) managerData;
  827. ClientRecPtr tmp = pClientRec;
  828. #ifdef DEBUG
  829. int i;
  830. (void) printf ("Received CONNECTION CLOSED [%d]\n", smsConn);
  831. for (i = 0; i < count; i++)
  832. (void) printf ("\tReason [%2d]: %s\n", i+1, reasonMsgs[i]);
  833. #endif /* DEBUG */
  834. if (count > 0) {
  835. PostReasonsDialog (GetArrayPropertyValue (tmp, SmProgram), count, reasonMsgs, True);
  836. SmFreeReasons (count, reasonMsgs);
  837. }
  838. CloseDownClient (pClientRec);
  839. }
  840. void
  841. CompleteXSMPSave (void)
  842. {
  843. ClientRecPtr pClientRec;
  844. /*
  845. * Save the XSMP clients' state and the Proxy clients' state
  846. * and save the rest of the settings, resources, etc.
  847. */
  848. CompleteSave ();
  849. /*
  850. * If this isn't a shutdown, tell the clients that the save
  851. * is complete.
  852. */
  853. if (!smXSMP.saveState.shutdown) {
  854. for (pClientRec = connectedList; pClientRec != NULL;
  855. pClientRec = pClientRec->next) {
  856. if (pClientRec->active) {
  857. SmsSaveComplete (pClientRec->smConn);
  858. #ifdef DEBUG
  859. printf ("SENT SmsSaveComplete to: %d\n",
  860. pClientRec->smConn);
  861. #endif
  862. }
  863. }
  864. }
  865. if (!smXSMP.saveState.shutdown) {
  866. for (pClientRec = connectedList; pClientRec != NULL;
  867. pClientRec = pClientRec->next) {
  868. if (pClientRec->active) {
  869. pClientRec->saveYourselfDone = False;
  870. pClientRec->saveYourselfP2Requested = False;
  871. pClientRec->interactRequested = False;
  872. }
  873. }
  874. InitializeSaveState (False);
  875. } else {
  876. int restartHint;
  877. for (pClientRec = connectedList; pClientRec != NULL;
  878. pClientRec = pClientRec->next) {
  879. if (pClientRec->active) {
  880. SmsDie (pClientRec->smConn);
  881. #ifdef DEBUG
  882. printf ("SENT SmsDie to: %d\n",
  883. pClientRec->smConn);
  884. #endif
  885. }
  886. if (!GetCardPropertyValue (pClientRec,
  887. SmRestartStyleHint,
  888. &restartHint))
  889. restartHint = pClientRec->restartHint;
  890. if (restartHint == SmRestartAnyway)
  891. ExecuteCommandProperty (SmShutdownCommand,
  892. pClientRec);
  893. }
  894. /*
  895. * Cannot exit until all of the clients go away.
  896. */
  897. smXSMP.saveState.saveComplete = True;
  898. return;
  899. }
  900. }
  901. static
  902. void FreeProps (
  903. PropertyRecPtr pProp)
  904. {
  905. PropertyRecPtr tmp;
  906. PropertyRecPtr trail;
  907. int i;
  908. for (tmp = pProp; tmp != NULL; ) {
  909. for (i = 0; i < tmp->prop.num_vals; i++)
  910. XtFree (tmp->prop.vals[i].value);
  911. if (tmp->prop.num_vals > 0)
  912. XtFree ((char *) tmp->prop.vals);
  913. trail = tmp;
  914. tmp = tmp->next;
  915. XtFree ((char *) trail);
  916. }
  917. }
  918. void CloseDownClient (
  919. ClientRecPtr pClientRec )
  920. {
  921. int restartHint;
  922. ClientRecPtr tmp, trail;
  923. SmsConn oldConn;
  924. SmsCleanUp (pClientRec->smConn);
  925. IceSetShutdownNegotiation (pClientRec->iceConn, False);
  926. IceCloseConnection (pClientRec->iceConn);
  927. /* save connection information for later compare */
  928. oldConn = pClientRec->smConn;
  929. pClientRec->iceConn = NULL;
  930. pClientRec->smConn = NULL;
  931. pClientRec->active = False;
  932. if (!GetCardPropertyValue (pClientRec, SmRestartStyleHint,
  933. &restartHint))
  934. restartHint = pClientRec->restartHint;
  935. if (!smXSMP.saveState.inProgress && restartHint == SmRestartImmediately)
  936. ExecuteCommandProperty (SmRestartCommand, pClientRec);
  937. if (restartHint == SmRestartAnyway)
  938. ExecuteCommandProperty (SmResignCommand, pClientRec);
  939. if (restartHint == SmRestartNever) {
  940. /*
  941. * Remove the client from the list
  942. */
  943. for (tmp = trail = connectedList; tmp != NULL;
  944. trail = tmp, tmp = tmp->next) {
  945. if (tmp->smConn == oldConn) {
  946. FreeProps (pClientRec->props);
  947. if (tmp == connectedList)
  948. connectedList = tmp->next;
  949. trail->next = tmp->next;
  950. XtFree ((char *) tmp);
  951. break;
  952. }
  953. }
  954. }
  955. /*
  956. * If a shutdown is occurring and all of the clients
  957. * are inactive, exit.
  958. */
  959. if (smXSMP.saveState.shutdown) {
  960. /*
  961. * Return if any clients are still active
  962. */
  963. for (tmp = connectedList; tmp != NULL; tmp = tmp->next) {
  964. if (tmp->active) {
  965. return;
  966. }
  967. }
  968. /*
  969. * All clients are inactive - its time to exit
  970. */
  971. _DtReleaseLock (smGD.display, SM_RUNNING_LOCK);
  972. SM_EXIT (0);
  973. }
  974. }
  975. /*ARGSUSED*/
  976. static
  977. Tt_callback_action GetWsmClientsHandler(
  978. Tt_message message,
  979. Tt_pattern pattern)
  980. {
  981. int lenClientIds;
  982. int num_args = tt_message_args_count (message);
  983. #ifdef DEBUG
  984. char * pchar;
  985. int i;
  986. #endif
  987. if (num_args != 3) {
  988. smXSMP.saveState.numClientIds = 0;
  989. smXSMP.saveState.clientIds = NULL;
  990. smXSMP.saveState.workspaceNums = NULL;
  991. ProcessInteract (smXSMP.saveState.interactClient, False);
  992. return (TT_CALLBACK_PROCESSED);
  993. }
  994. /*
  995. * Before extracting the new values from this message, free any
  996. * old values.
  997. */
  998. if (smXSMP.saveState.clientIds)
  999. free (smXSMP.saveState.clientIds);
  1000. if (smXSMP.saveState.workspaceNums)
  1001. free (smXSMP.saveState.workspaceNums);
  1002. tt_message_arg_ival (message, 0,
  1003. &smXSMP.saveState.numClientIds);
  1004. tt_message_arg_bval (message, 1,
  1005. (unsigned char **) &smXSMP.saveState.clientIds,
  1006. &lenClientIds);
  1007. tt_message_arg_bval (message, 2,
  1008. (unsigned char **) &smXSMP.saveState.workspaceNums,
  1009. &lenClientIds);
  1010. tt_message_reply (message);
  1011. tt_message_destroy (message);
  1012. #ifdef DEBUG
  1013. (void) printf("GetWsmClientsHandler: num clients = %d\n",
  1014. smXSMP.saveState.numClientIds);
  1015. for (i = 0, pchar = smXSMP.saveState.clientIds;
  1016. i < smXSMP.saveState.numClientIds;
  1017. i++, pchar += strlen (pchar) + 1) {
  1018. (void) printf("\tclient [%2d]: workspace = %2d, id = %s\n",
  1019. i+1, smXSMP.saveState.workspaceNums[i], pchar);
  1020. }
  1021. #endif
  1022. ProcessInteract (smXSMP.saveState.interactClient, True);
  1023. return (TT_CALLBACK_PROCESSED);
  1024. }
  1025. static
  1026. Boolean SendGetWsmClientsMessage (void)
  1027. {
  1028. Tt_message message;
  1029. Tt_status status;
  1030. message = tt_message_create ();
  1031. status = tt_ptr_error (message);
  1032. if (status != TT_OK)
  1033. return (False);
  1034. tt_message_class_set (message, TT_REQUEST);
  1035. tt_message_scope_set (message, TT_SESSION);
  1036. tt_message_address_set (message, TT_PROCEDURE);
  1037. tt_message_session_set (message, tt_default_session());
  1038. tt_message_op_set (message, GET_CLIENT_WORKSPACE_MSG);
  1039. tt_message_callback_add (message, GetWsmClientsHandler);
  1040. /*
  1041. * Three arguments are expected in the reply so apparently
  1042. * they must be accounted for now.
  1043. */
  1044. tt_message_iarg_add (message, TT_OUT, "integer", 0);
  1045. tt_message_barg_add (message, TT_OUT, "stringlist", 0, 0);
  1046. tt_message_barg_add (message, TT_OUT, "intlist", 0, 0);
  1047. status = tt_message_send (message);
  1048. if (status != TT_OK)
  1049. return (False);
  1050. return (True);
  1051. }
  1052. static
  1053. int GetCurrentWorkspaceNumber (void)
  1054. {
  1055. Atom currentWorkspace;
  1056. Atom *workspaceList;
  1057. Window root;
  1058. int rval;
  1059. int numWorkspaces;
  1060. int i;
  1061. root = XDefaultRootWindow (smGD.display);
  1062. rval = DtWsmGetCurrentWorkspace(smGD.display, root, &currentWorkspace);
  1063. if (rval != Success)
  1064. return (-1);
  1065. rval = DtWsmGetWorkspaceList (smGD.display, root, &workspaceList,
  1066. (int *) &numWorkspaces);
  1067. if (rval != Success)
  1068. return (-1);
  1069. for (i = 0; i < numWorkspaces; i++) {
  1070. if (currentWorkspace == workspaceList[i])
  1071. return (currentWorkspace);
  1072. }
  1073. return (-1);
  1074. }
  1075. static
  1076. void CancelShutdown (void)
  1077. {
  1078. ClientRecPtr pClientRec;
  1079. char *pch;
  1080. for (pClientRec = connectedList; pClientRec != NULL;
  1081. pClientRec = pClientRec->next) {
  1082. if (pClientRec->active) {
  1083. ExecuteCommandProperty (SmDiscardCommand, pClientRec);
  1084. pClientRec->saveYourselfDone = False;
  1085. pClientRec->saveYourselfP2Requested = False;
  1086. pClientRec->interactRequested = False;
  1087. }
  1088. }
  1089. UndoSetSavePath ();
  1090. InitializeSaveState (False);
  1091. }
  1092. /*
  1093. * This function can be invoked via different paths:
  1094. *
  1095. * 1. From the InteractRequest callback
  1096. * 2. From the InteractDone callback
  1097. * 3. From the GetWsmClients message callback
  1098. */
  1099. static
  1100. void ProcessInteract (
  1101. ClientRecPtr client,
  1102. Boolean getWsmClientOK)
  1103. {
  1104. int currentWorkspace;
  1105. int i;
  1106. ClientRecPtr pClientRec;
  1107. ClientRecPtr tmp = NULL;
  1108. char *pchar;
  1109. if (!getWsmClientOK) {
  1110. smXSMP.saveState.clientInteracting = True;
  1111. SmsInteract (client->smConn);
  1112. return;
  1113. }
  1114. /*
  1115. * If a client wants to interact and its workspace matches
  1116. * the current workspace, then let it interact.
  1117. */
  1118. currentWorkspace = GetCurrentWorkspaceNumber ();
  1119. for (pClientRec = connectedList;
  1120. pClientRec != NULL;
  1121. pClientRec = pClientRec->next) {
  1122. if (pClientRec->interactRequested) {
  1123. tmp = pClientRec;
  1124. for (i = 0, pchar = smXSMP.saveState.clientIds;
  1125. i < smXSMP.saveState.numClientIds;
  1126. i++, pchar += strlen (pchar) + 1) {
  1127. if ((currentWorkspace ==
  1128. smXSMP.saveState.workspaceNums[i]) &&
  1129. (!strcmp (pchar, pClientRec->clientId))) {
  1130. smXSMP.saveState.clientInteracting =
  1131. True;
  1132. SmsInteract (pClientRec->smConn);
  1133. return;
  1134. }
  1135. }
  1136. }
  1137. }
  1138. /*
  1139. * Tmp didn't meet all of the requirements but it does
  1140. * want to interact so let it.
  1141. */
  1142. if (tmp) {
  1143. smXSMP.saveState.clientInteracting = True;
  1144. SmsInteract (tmp->smConn);
  1145. }
  1146. }
  1147. /*
  1148. * List manipulation functions
  1149. */
  1150. void AddClient (
  1151. ClientRecPtr newClient)
  1152. {
  1153. ClientRecPtr pClient;
  1154. if (!connectedList) {
  1155. connectedList = newClient;
  1156. return;
  1157. }
  1158. /*
  1159. * Find the end of the list
  1160. */
  1161. for (pClient = connectedList; pClient->next != NULL;
  1162. pClient = pClient->next);
  1163. pClient->next = newClient;
  1164. }
  1165. /*
  1166. * The real way to handle IO errors is to check the return status
  1167. * of IceProcessMessages. dtsession properly does this.
  1168. *
  1169. * Unfortunately, a design flaw exists in the ICE library in which
  1170. * a default IO error handler is invoked if no IO error handler is
  1171. * installed. This default handler exits. We must avoid this.
  1172. *
  1173. * To get around this problem, we install an IO error handler that
  1174. * does a little magic. Since a previous IO handler might have been
  1175. * installed, when we install our IO error handler, we do a little
  1176. * trick to get both the previous IO error handler and the default
  1177. * IO error handler. When our IO error handler is called, if the
  1178. * previous handler is not the default handler, we call it. This
  1179. * way, everyone's IO error handler gets called except the stupid
  1180. * default one which does an exit!
  1181. */
  1182. static IceIOErrorHandler prev_handler;
  1183. void
  1184. MyIoErrorHandler (
  1185. IceConn ice_conn)
  1186. {
  1187. if (prev_handler)
  1188. (*prev_handler) (ice_conn);
  1189. }
  1190. void
  1191. InstallIOErrorHandler (void)
  1192. {
  1193. IceIOErrorHandler default_handler;
  1194. prev_handler = IceSetIOErrorHandler (NULL);
  1195. default_handler = IceSetIOErrorHandler (MyIoErrorHandler);
  1196. if (prev_handler == default_handler)
  1197. prev_handler = NULL;
  1198. }
  1199. void XSMPExit (void)
  1200. {
  1201. char * pchar;
  1202. if (authenticationInitialized)
  1203. FreeAuthenticationData (smXSMP.numTransports,
  1204. smXSMP.authDataEntries);
  1205. /*
  1206. * If the local socket file exists, remove it.
  1207. *
  1208. * Assume the format of networkIds is:
  1209. *
  1210. * local/<host_name>:/<socket_file_name>,<other_stuff>
  1211. */
  1212. if (!strncmp (networkIds, "local/", 6)) {
  1213. if (pchar = strchr (networkIds, ':')) {
  1214. pchar++;
  1215. if (pchar && *pchar != '\000') {
  1216. char * pchar2;
  1217. if (pchar2 = strchr (pchar, ',')) {
  1218. struct stat buf;
  1219. /*
  1220. * This modifies networkIds but
  1221. * that's OK because an exit is
  1222. * about to happen.
  1223. */
  1224. *pchar2 = '\000';
  1225. if ((stat (pchar, &buf)) == 0) {
  1226. (void) unlink (pchar);
  1227. }
  1228. }
  1229. }
  1230. }
  1231. }
  1232. }