-fpermissive to allow GCC to compile old C++
[oweals/cde.git] / cde / programs / dtmail / dtmail / WMSaveSession.C
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 librararies 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  *      $TOG: WMSaveSession.C /main/16 1998/12/09 18:29:33 mgreess $
25  *
26  *      @(#)WMSaveSession.C     1.12 23 May 1995
27  *
28  *      RESTRICTED CONFIDENTIAL INFORMATION:
29  *
30  *      The information in this document is subject to special
31  *      restrictions in a confidential disclosure agreement between
32  *      HP, IBM, Sun, USL, SCO and Univel.  Do not distribute this
33  *      document outside HP, IBM, Sun, USL, SCO, or Univel without
34  *      Sun's specific written approval.  This document and all copies
35  *      and derivative works thereof must be returned or destroyed at
36  *      Sun's request.
37  *
38  *      Copyright 1993, 1994, 1995 Sun Microsystems, Inc.  All rights reserved.
39  *
40  */
41
42 #include <stdio.h>
43 #include <unistd.h>
44 #include <time.h>
45 #include <sys/param.h>
46 #include <sys/stat.h>
47
48 #include <Dt/DtPStrings.h>
49 #include <Dt/Session.h>
50 #include <Xm/Xm.h>
51 #include <Xm/Protocols.h>
52 #include <Xm/MainW.h>
53
54 #include <DtMail/IO.hh>                    // SafeAccess...
55 #include <RoamApp.h>
56 #include <RoamMenuWindow.h>
57 #include <SendMsgDialog.h>
58
59 #include <Dt/Session.h>
60 #include <Dt/DtNlUtils.h>
61 #include <Dt/Wsm.h>
62 #include <Dt/WsmP.h>
63
64
65 #define INBOX   "INBOX"
66
67 // For debugging only
68 #ifdef LOG_SESSION
69
70 char logfile[MAXPATHLEN+1];
71 int  logfile_initd = 0;
72
73 #define LOG_CLOSEFILEPTR(log)   if (log) fclose(log);
74 #define LOG_DEFINEFILEPTR(log)  FILE *log = NULL;
75 #define LOG_FPRINTF(log, args)  if (log) fprintf args;
76 #define LOG_GETFILENAME(lfn) \
77     sprintf(lfn, "%s/%s/dtmail.log", getenv("HOME"), DtPERSONAL_TMP_DIRECTORY);
78 #define LOG_OPENFILEPTR(log) \
79     if (! logfile_initd) \
80     { \
81         logfile_initd = 1; \
82         LOG_GETFILENAME(logfile); \
83     } \
84     if (! (log = fopen(logfile,"a+"))) \
85       perror(logfile);
86
87 #else
88
89 #define LOG_CLOSEFILEPTR(log)
90 #define LOG_DEFINEFILEPTR(log)
91 #define LOG_FPRINTF(log, args)
92 #define LOG_GETFILENAME(lfn)
93 #define LOG_OPENFILEPTR(log)
94
95 #endif
96
97
98 // Data struct to hold the iconic state of a window.
99 typedef struct _WmState
100 {
101     int         state;
102     Window      icon;
103 } WmState;
104
105
106 /*
107  * Initializes the Mailer for XSMP by registering save and die callbacks
108  * on the session shell.
109  */
110 void 
111 RoamApp::initSession(void)
112 {
113     LOG_DEFINEFILEPTR(log);
114     LOG_OPENFILEPTR(log);
115
116 #ifdef LOG_SESSION
117 #define MAXLOGSZ        10000
118     struct stat sbuf;
119     time_t      tloc;
120
121     // If the size of the logfile exceeds a max size, truncate it.
122     if (stat(logfile, &sbuf) == 0)
123       if (sbuf.st_size > MAXLOGSZ)
124         truncate(logfile, 0);
125
126     (void) time(&tloc);
127 #endif
128     
129     session_fp = NULL;
130     XtAddCallback(_w, XtNsaveCallback, smpSaveSessionCB, (XtPointer) this);
131     XtAddCallback(_w, XtNdieCallback, smpDieCB, (XtPointer) this);
132
133     LOG_FPRINTF(log, (log,"Session Initialized at: %s\n", ctime(&tloc)));
134     LOG_CLOSEFILEPTR(log);
135 }
136
137 /*
138  * This method takes a file name and computes the full pathname 
139  * using Dt services and then opens the session file pointed
140  * to by pathname.
141  */
142 void
143 RoamApp::openSessionFile(char *filename)
144 {
145     struct stat s;
146     char *pathname = NULL;
147
148     if (filename == NULL)
149       return;
150     
151     session_fp = NULL;
152
153     LOG_DEFINEFILEPTR(log);
154     LOG_OPENFILEPTR(log);
155
156     // If the session file is an absolute path, just use it.
157     if (filename[0] == '/')
158       pathname = strdup(filename);
159     else if (DtSessionRestorePath(_w, &pathname, filename) == FALSE)
160     {
161         LOG_FPRINTF(log, (log,"DtSessionRestorePath Failed on: %s\n",filename));
162         LOG_CLOSEFILEPTR(log);
163         return;
164     }
165
166     // Sometimes the session file can be empty.
167     // This can cause dtmail to exist as a zombie process on login.
168     // To prevent that, we stat the session file and if necessary,
169     // set the session_fp to NULL.
170     SafeStat(pathname, &s);
171     if (s.st_size == 0)
172       session_fp = NULL;
173     else
174     {
175         if (!(session_fp = fopen(pathname, "r")))
176         {
177             perror(pathname);
178             session_fp = NULL;
179         }
180     }
181
182     LOG_FPRINTF(log, (log,"Opened session file: %s\n",pathname));
183     LOG_CLOSEFILEPTR(log);
184     if (pathname != NULL)
185       XtFree((char *)pathname);
186 }
187
188 /*
189  * This methods parses the -session argument and
190  * returns the name of the session file if present.
191  */
192 char *RoamApp::parseSessionArg(int *argc, char **argv)
193 {
194     LOG_DEFINEFILEPTR(log);
195     char *filename = NULL;
196
197     if (*argc<3)
198       return NULL;
199     
200     LOG_OPENFILEPTR(log);
201
202     for(int i=0; i<*argc; i++)
203     {
204         LOG_FPRINTF(log, (log,"restart argv[%d]: %s\n",i, argv[i]));
205         if (!strcmp(argv[i], "-session"))
206         {
207             if (i<*argc-1)
208             {
209                 filename = argv[i+1];
210                 for (int j=i+2; j < *argc; )
211                   argv[i++] = argv[j++]; 
212                 *argc -= 2;
213             }
214             break;
215         }
216     }
217     
218     LOG_CLOSEFILEPTR(log);
219     return filename;
220 }
221
222 /*
223  *  This method implements the restore operation for RoamApp.
224  *  Creates and initializes a RoamMenuWindow or SendMsgDialog
225  *  for each MainWindow in the session file.
226  */
227 void 
228 RoamApp::restoreSession(void)
229 {
230     char buf[MAXPATHLEN+1];
231
232     if (! session_fp)
233       _exit(0);
234     
235     _mailview = NULL;
236     for(;;)
237     {
238         if (fscanf(session_fp,"%s",buf) == EOF)
239           break;
240         
241         switch (buf[0])
242         {
243           case 'R':
244           {
245             RoamMenuWindow      *rmw = NULL;
246             
247             rmw = RoamMenuWindow::restoreSession(buf);
248             if(_mailview == NULL)
249             {
250                 dtmail_mapped = 1;
251                 _mailview = rmw;
252             }  
253             break;
254           }
255           case 'S':
256             SendMsgDialog::restoreSession(buf);
257             break;
258           default:
259           {
260             LOG_DEFINEFILEPTR(log);
261             LOG_OPENFILEPTR(log);
262             LOG_FPRINTF(log, (log, "%s contains neither an R or an S", buf));
263             LOG_CLOSEFILEPTR(log);
264             break;      
265           }
266         }
267     }
268
269
270 /*
271  * This method implements the SmSaveLocal SaveYourself XSMP operation for the
272  * RoamApp object:
273  *   1. Gets a session file name from Dt services and opens the session file. 
274  *   2. Invokes a saveSessionLocal on each top level window.
275  *   3. Updates the WM_COMMAND property. 
276  */
277 void 
278 RoamApp::smpSaveSessionLocal(void)
279 {
280     char *pathname = NULL, *filename = NULL;
281     char **save_argv = NULL;
282     int save_argc = 0;
283     char **argv = NULL;
284     int argc = 0;
285     
286     if (! DtSessionSavePath(_w, &pathname, &filename))
287       return;
288     
289     if (! (session_fp = fopen(pathname, "w+")))
290     {
291         perror(pathname);
292         XtFree((char *)pathname);
293         XtFree((char *)filename);
294         session_fp = NULL;
295         return;
296     }
297     chmod(pathname, S_IRUSR | S_IRGRP | S_IWUSR | S_IWGRP);
298     
299     for(int i = 0; i<_numWindows; i++)
300       _windows[i]->smpSaveSessionLocal();
301     
302     fclose(session_fp);
303     session_fp = NULL;
304     
305     XtVaGetValues(_w, XtNrestartCommand, &argv, NULL);
306
307 #if 0
308     for (i=0; NULL != argv[i]; i++) {}
309     save_argv = (char**) XtMalloc((i+3)*sizeof(char*));
310     for (save_argc=0; save_argc<i; save_argc++)
311       save_argv[save_argc] = argv[save_argc];
312 #else
313     save_argc = 0;
314     save_argv = (char**) XtMalloc(3*sizeof(char*));
315     save_argv[save_argc++] = argv[0];
316 #endif
317     save_argv[save_argc++] = "-session";
318     save_argv[save_argc++] = filename;
319     save_argv[save_argc] = NULL;
320     
321     LOG_DEFINEFILEPTR(log);
322     LOG_OPENFILEPTR(log);
323     for (int j=0; j<save_argc; j++)
324     {
325         LOG_FPRINTF(log, (log, "WM_COMMAND[%d]: %s\n",j,save_argv[j]));
326     }
327     LOG_CLOSEFILEPTR(log);
328     
329     XtVaSetValues(_w, XtNrestartCommand, save_argv, NULL);
330     /* There should be no code after this */
331 }
332
333 /*
334  *
335  */
336 int
337 RoamApp::smpSaveSessionGlobal(void)
338 {
339     int cancel;
340
341     for(int i = 0; i<_numWindows; i++)
342       if (_windows[i]->smpSaveSessionGlobal())
343         cancel = 1;
344     
345     return cancel;
346 }
347
348 /*
349  * Restores a RoamMenuWindow from a RoamMenuWindow::SaveSessionLocal string.
350  */
351 RoamMenuWindow *
352 RoamMenuWindow::restoreSession(char *buf)
353 {
354     RoamMenuWindow *rmw = NULL;
355     char *workspaces = new char[256];
356     int iconic = 0; 
357     int x = 0, y = 0; 
358     int width = 0, height = 0;
359     char *ptr;
360     Atom *workspace_atoms = NULL;
361     int num_workspaces = 0;
362
363     LOG_DEFINEFILEPTR(log);
364     LOG_OPENFILEPTR(log);
365     
366     if (!strncmp(buf,"RoamMenu", 8))
367     { 
368         FILE    *fp = theRoamApp.sessionFile();
369
370         LOG_FPRINTF(log, (log, "Is a RMW"));
371         if (fscanf(
372                 fp, "%s%s%d%d%d%d%d",
373                 buf,workspaces,&iconic,&x,&y,&width,&height) != 7)
374         {
375             fscanf(fp,"[\n]",buf);
376             LOG_CLOSEFILEPTR(log);
377             return NULL;
378         }
379
380         LOG_FPRINTF(log, (log, "Restore: RoamMenu %s %s %d %d %d %d %d\n",
381                           buf,workspaces,iconic,x,y,width,height));
382                 
383         if (0 == strncmp(buf, INBOX, strlen(INBOX)))
384         {
385             DtMail::Session     *d_session;
386             DtMailEnv           error;
387             DtMailObjectSpace   space;
388             char                *inboxname;
389                     
390             d_session = theRoamApp.session()->session();
391             d_session->queryImpl(error,
392                                 d_session->getDefaultImpl(error),
393                                 DtMailCapabilityInboxName,
394                                 &space,
395                                 &inboxname);
396
397             strncpy(buf, inboxname, MAXPATHLEN);
398             buf[MAXPATHLEN] = '\0';
399             if (NULL != inboxname)
400               free(inboxname);
401         }
402
403         rmw =  new RoamMenuWindow(buf);
404         rmw->initialize();
405
406         // Use the appropriate DtWsm* method to restore the window
407         // to the workspace it belonged to.
408         // A problem though: the DtWsm* methods require the widget
409         // to be realized.  We normally realize the window only when
410         // we call manage.  If we call manage now, the window will
411         // pop up in the default workspace and then *move* to the
412         // appropriate workspace later.  To avoid this, we realize,
413         // but not manage, the widget, call the DtWsm* method,
414         // and then manage the widget.  This will cause the window
415         // to appear only in the appropriate workspace.
416         Widget bw = rmw->baseWidget();
417         XtRealizeWidget(bw);
418         XmUpdateDisplay(bw);
419
420         // If the arguments are all valid, use them.
421         // Else let the values in app-defaults take over.
422         if (((iconic == 0) || (iconic == 1)) &&
423             x >= 0 &&
424             y >= 0 &&
425             width > 0 &&
426             height > 0)
427         {
428             XtVaSetValues(bw,
429                         XtNinitialState, 
430                         (iconic ? IconicState: NormalState), 
431                         XtNx, (Position)x, XtNy, (Position)y, 
432                         XtNwidth, (Dimension)width, XtNheight, 
433                         (Dimension)height, NULL);
434   
435             if (workspaces)
436             {
437                 do
438                 {
439                     ptr = strchr (workspaces, '*');
440                     if (ptr != NULL) *ptr = NULL;
441                                 
442                     workspace_atoms = (Atom*) XtRealloc(
443                                         (char*) workspace_atoms, 
444                                         sizeof(Atom) * (num_workspaces+1));
445
446                     workspace_atoms[num_workspaces] = 
447                       XmInternAtom (XtDisplay(bw), workspaces, True);
448                                         
449                     num_workspaces++;
450
451                     if (ptr != NULL)
452                     {
453                         *ptr = '*';
454                         workspaces = ptr + 1;
455                     }
456                 } while (ptr != NULL);
457
458                 DtWsmSetWorkspacesOccupied(
459                                         XtDisplay(bw),
460                                         XtWindow (bw),
461                                         workspace_atoms,
462                                         num_workspaces);
463
464                 XtFree((char*) workspace_atoms);
465                 workspace_atoms = NULL;
466                           
467             }
468                 
469         }
470
471         // Manage the RMW now.  This will cause the window
472         // to appear in the correct workspace.
473         rmw->manage();
474     }
475
476     LOG_CLOSEFILEPTR(log);
477     return rmw;
478 }
479
480 /*
481  * This method implements the save yourself operation for
482  * RoamMenuWindow object. The steps involved are:
483  *      1. Get the session file pointer from theRoamApp.
484  *      2. Get the iconic state, mail folder, x, y, width, height and 
485  *         save it. 
486  */
487 void
488 RoamMenuWindow::smpSaveSessionLocal(void)
489 {
490     WmState     *iconic_state = NULL;
491     FILE        *fp = theRoamApp.sessionFile();
492     Display     *display = theRoamApp.display();
493     int         initialstate = 0;
494     Atom        wm_state, actual_type;
495     unsigned long nitems, leftover;
496     int         actual_format;
497     Atom        *ws_presence = NULL;
498     char        *workspace_name=NULL;
499     unsigned long num_workspaces = 0;
500     char        *all_workspace_names;
501     char        *mailboxname;
502     
503     if (fp == NULL)
504       return;
505     
506     _mailbox->save();
507     wm_state = XmInternAtom(display, "WM_STATE", False);
508     XGetWindowProperty(
509                 display,XtWindow(_w), wm_state, 0L,
510                 (long)BUFSIZ, False, wm_state, &actual_type,
511                 &actual_format, &nitems, &leftover,
512                 (unsigned char **) &iconic_state);
513     
514     initialstate = (iconic_state->state == IconicState ? 1: 0);
515
516     // Get the workspaces this window is present.
517     if (DtWsmGetWorkspacesOccupied(
518                                 display, XtWindow(_w),
519                                 &ws_presence, &num_workspaces) == Success)
520     {
521          for (int j = 0; j < num_workspaces; j++)
522          {
523             workspace_name = XGetAtomName (display, ws_presence[j]);
524             if (j == 0)
525             {
526                 all_workspace_names = (char*) malloc((size_t) MAXPATHLEN + 1);
527                 strcpy(all_workspace_names, (char*) workspace_name);
528             }
529             else {
530                 (void) strcat(all_workspace_names, "*");
531                 (void) strcat(all_workspace_names, workspace_name);
532             }
533             
534             XtFree ((char *) workspace_name);
535          }
536
537          XFree((char *)ws_presence);
538       }
539
540     if (_inbox)
541       mailboxname = INBOX;
542     else
543       mailboxname = _mailbox_fullpath;
544
545     (void) fprintf(
546                 fp, "RoamMenu %s %s %d %d %d %d %d\n",
547                 mailboxname,
548                 all_workspace_names, initialstate,
549                 (int)_x, (int)_y, 
550                 (int)_width, (int)_height);
551
552     LOG_DEFINEFILEPTR(log);
553     LOG_OPENFILEPTR(log);
554     LOG_FPRINTF(log, (log, "Save: RoamMenu %s %s %s %d %d %d %d %d\n",
555                       XtName(_w), mailboxname,
556                       all_workspace_names, initialstate,
557                       (int)_x, (int)_y,
558                       (int)_width, (int)_height));
559     LOG_CLOSEFILEPTR(log);
560 }
561
562 /*
563  *
564  */
565 int
566 RoamMenuWindow::smpSaveSessionGlobal(void)
567 {
568     return queryExpunge();
569 }
570
571 void
572 SendMsgDialog::restoreSession(char *buf)
573 {
574     char *workspaces = new char[256];
575     int iconic = 0; 
576     int x = 0, y = 0; 
577     int width = 0, height = 0;
578     char *ptr = NULL;
579     Atom *workspace_atoms = NULL;
580     int num_workspaces=0;
581     SendMsgDialog *smd = NULL;
582
583     LOG_DEFINEFILEPTR(log);
584     LOG_OPENFILEPTR(log);
585
586     if (!strncmp(buf,"SendMsg", 7))
587     {
588         FILE    *fp = theRoamApp.sessionFile();
589
590         LOG_FPRINTF(log, (log, "Is a SMD"));
591
592         if (fscanf(
593                 fp, "%s%s%d%d%d%d%d",
594                 buf,workspaces,&iconic,&x,&y,&width,&height) != 7)
595         {
596             fscanf(fp,"[\n]",buf);
597             LOG_CLOSEFILEPTR(log);
598             return;
599         }
600
601         LOG_FPRINTF(log, (log, "Restore: SendMsg %s %s %d %d %d %d %d\n",
602                           buf,workspaces,iconic,x,y,width,height));
603                 
604         smd =  theCompose.getWin();
605         smd->loadDeadLetter(buf);
606
607         // Use the appropriate DtWsm* method to restore the window
608         // to the workspace it belonged to.
609         // A problem though: the DtWsm* methods require the widget
610         // to be realized.  We normally realize the window only when
611         // we call manage.  If we call manage now, the window will
612         // pop up in the default workspace and then *move* to the
613         // appropriate workspace later.  To avoid this, we realize,
614         // but not manage, the widget, call the DtWsm* method,
615         // and then manage the widget.  This will cause the window
616         // to appear only in the appropriate workspace.
617         Widget bw = smd->baseWidget();
618         XtRealizeWidget(bw);
619         XmUpdateDisplay(bw);
620
621                 
622         // If the values are valid, use them.
623         // Else let the ones in the app-defaults take over.
624         if (((iconic == 0) || (iconic == 1)) &&
625             x >= 0 &&
626             y >= 0 &&
627             width > 0 &&
628             height > 0)
629         {
630             XtVaSetValues(bw,
631                         XtNinitialState, 
632                         (iconic ? IconicState: NormalState), 
633                         XtNx, (Position)x, XtNy, (Position)y, 
634                         XtNwidth, (Dimension)width, XtNheight, 
635                         (Dimension)height, NULL);
636             if (workspaces)
637             {
638                 do
639                 {
640                     ptr = strchr(workspaces, '*');
641                     if (ptr != NULL) *ptr = NULL;
642                                 
643                     workspace_atoms = (Atom*) XtRealloc(
644                                         (char*) workspace_atoms, 
645                                         sizeof(Atom)*(num_workspaces+1));
646
647                     workspace_atoms[num_workspaces] = 
648                       XmInternAtom(XtDisplay(bw), workspaces, True);
649
650                     num_workspaces++;
651
652                     if (ptr != NULL)
653                     {
654                         *ptr = '*';
655                         workspaces = ptr + 1;
656                     }
657                 } while (ptr != NULL);
658
659                 DtWsmSetWorkspacesOccupied(
660                                         XtDisplay(bw),
661                                         XtWindow (bw),
662                                         workspace_atoms,
663                                         num_workspaces);
664
665                 XtFree((char*) workspace_atoms);
666                 workspace_atoms = NULL;
667             }
668         }
669
670         // Manage the SMD now.  This will cause the window
671         // to appear in the correct workspace.
672         smd->manage();
673     }
674     
675     LOG_CLOSEFILEPTR(log);
676 }
677
678 /*
679  * This method implements the save yourself operation for
680  * SendMsgDialog object. The steps involved are:
681  *      1. Get the session file pointer from theRoamApp.
682  *      2. Get the iconic state, mail folder, x, y, width, height and 
683  *         save it. 
684  */
685 void
686 SendMsgDialog::smpSaveSessionLocal(void)
687 {
688     WmState     *iconic_state = NULL;
689     FILE        *fp = theRoamApp.sessionFile();
690     Display     *display = theRoamApp.display();
691     int         initialstate = 0;
692     Atom        wm_state, actual_type;
693     unsigned long nitems, leftover;
694     int         actual_format;
695     Position    x=0, y=0;
696     Dimension   width = 0, height = 0;
697     Atom        *ws_presence = NULL;
698     char        *workspace_name = NULL;
699     unsigned long num_workspaces = 0;
700     char        *all_workspace_names;
701     char        *save_filename;
702     int j;
703
704     
705     if(fp == NULL)
706         return;
707     
708     // If tthe SMD is not being used, return.
709     if (!_msgHandle)
710         return;
711     
712     // Create a dead letter if this one is currently in use
713     if ((save_filename = tempnam(_auto_save_path, "session")) == NULL) 
714     {
715         for (int suffix = 1; ; suffix++) {
716             save_filename = (char*) malloc((size_t) MAXPATHLEN + 1);
717             sprintf(save_filename, "%s/session.%d", _auto_save_path, suffix);
718             if (SafeAccess(save_filename, F_OK) != 0)
719               break;
720         }
721     }
722     doAutoSave(save_filename);
723     
724     wm_state = XmInternAtom(display, "WM_STATE", False);
725     XGetWindowProperty(
726                 display, XtWindow(_w), wm_state, 0L,
727                 (long)BUFSIZ, False, wm_state, &actual_type,
728                 &actual_format, &nitems, &leftover,
729                 (unsigned char **) &iconic_state);
730     
731     initialstate = (iconic_state->state == IconicState ? 1: 0);
732
733     // Get the workspaces this window is present.
734     if (DtWsmGetWorkspacesOccupied(
735                                 display, XtWindow (_w),
736                                 &ws_presence, &num_workspaces) == Success)
737     {
738         for (j = 0; j < num_workspaces; j++)
739         {
740             workspace_name = XGetAtomName (display, ws_presence[j]);
741             if (j == 0)
742             {
743                 all_workspace_names = (char*) malloc((size_t) MAXPATHLEN + 1);
744                 strcpy(all_workspace_names, (char*) workspace_name);
745             }
746             else
747             {
748                 (void) strcat(all_workspace_names, "*");
749                 (void) strcat(all_workspace_names, workspace_name);
750             }
751             
752             XtFree((char*) workspace_name);
753         }
754
755          XFree((char *)ws_presence);
756     }
757
758     XtVaGetValues(
759                 _w,
760                 XtNx, &x,
761                 XtNy, &y,
762                 XtNwidth, &width,
763                 XtNheight, &height,
764                 NULL);
765
766     (void) fprintf(
767                 fp,"SendMsg %s %s %d %d %d %d %d\n",
768                 save_filename,
769                 all_workspace_names, initialstate,
770                 (int)x, (int)y, 
771                 (int)width, (int)height);
772
773     LOG_DEFINEFILEPTR(log);
774     LOG_OPENFILEPTR(log);
775     LOG_FPRINTF(log, (log, "Save: SendMsg %s %s %s %d %d %d %d %d\n",
776                       XtName(_w), save_filename,
777                       all_workspace_names, initialstate,
778                       (int)x, (int)y,
779                       (int)width, (int)height));
780     LOG_CLOSEFILEPTR(log);
781     
782     free(save_filename);
783 }
784
785 /*
786  *
787  */
788 int
789 SendMsgDialog::smpSaveSessionGlobal(void)
790 {
791     if (checkDirty())
792     {
793         if (isIconified())
794             MainWindow::manage();
795
796         // Enquire if user really wants this window to go away
797         Boolean really_quit = handleQuitDialog();
798         if (! really_quit)
799           return 1;
800         
801         _takeDown = TRUE;
802         quit();
803     }
804     return 0;
805 }
806
807 /*
808  *  Session Shell save callback.
809  */
810 void 
811 RoamApp::smpSaveSessionCB(Widget , XtPointer client, XtPointer call)
812 {
813     RoamApp             *roamapp = (RoamApp*) client;
814     XtCheckpointToken   cpToken = (XtCheckpointToken) call;
815
816     if (! roamapp->_firstSaveYourselfArrived)
817     {
818         // Skip the first one since things aren't ready yet.
819         roamapp->_firstSaveYourselfArrived = TRUE;
820         return;
821     }
822
823     if (cpToken->cancel_shutdown)
824     {
825         roamapp->unsetQuitQuickly();
826         roamapp->unsetQuitSilently();
827         return;
828     }
829
830     if (cpToken->save_type == SmSaveLocal ||
831         cpToken->save_type == SmSaveBoth)
832       roamapp->smpSaveSessionLocal();
833     
834     if (cpToken->shutdown)
835     {
836         if (cpToken->fast)
837           roamapp->setQuitQuickly();
838
839         if (cpToken->interact_style == SmInteractStyleNone ||
840             cpToken->interact_style == SmInteractStyleErrors)
841           roamapp->setQuitSilently();
842         else if (! cpToken->fast)
843           XtAddCallback(
844                         roamapp->baseWidget(),
845                         XtNinteractCallback, smpInteractCB,
846                         (XtPointer) roamapp);
847     }
848 }
849
850 /*
851  *  Session Shell die callback.
852  */
853 void 
854 RoamApp::smpDieCB(Widget, XtPointer client, XtPointer)
855 {
856     RoamApp *roamapp = (RoamApp*) client;
857     roamapp->closeAllWindows();
858 }
859
860 /*
861  *  Session Shell interact callback.
862  */
863 void 
864 RoamApp::smpInteractCB(Widget, XtPointer client, XtPointer call)
865 {
866     RoamApp *roamapp = (RoamApp*) client;
867     XtCheckpointToken   cpToken = (XtCheckpointToken) call;
868
869     if (cpToken->save_type == SmSaveGlobal ||
870         cpToken->save_type == SmSaveBoth)
871       cpToken->cancel_shutdown = roamapp->smpSaveSessionGlobal();
872 }