Even more spelling fixed
[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 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  *      $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     XtFree((char *)pathname);
185 }
186
187 /*
188  * This methods parses the -session argument and
189  * returns the name of the session file if present.
190  */
191 char *RoamApp::parseSessionArg(int *argc, char **argv)
192 {
193     LOG_DEFINEFILEPTR(log);
194     char *filename = NULL;
195
196     if (*argc<3)
197       return NULL;
198     
199     LOG_OPENFILEPTR(log);
200
201     for(int i=0; i<*argc; i++)
202     {
203         LOG_FPRINTF(log, (log,"restart argv[%d]: %s\n",i, argv[i]));
204         if (!strcmp(argv[i], "-session"))
205         {
206             if (i<*argc-1)
207             {
208                 filename = argv[i+1];
209                 for (int j=i+2; j < *argc; )
210                   argv[i++] = argv[j++]; 
211                 *argc -= 2;
212             }
213             break;
214         }
215     }
216     
217     LOG_CLOSEFILEPTR(log);
218     return filename;
219 }
220
221 /*
222  *  This method implements the restore operation for RoamApp.
223  *  Creates and initializes a RoamMenuWindow or SendMsgDialog
224  *  for each MainWindow in the session file.
225  */
226 void 
227 RoamApp::restoreSession(void)
228 {
229     char buf[MAXPATHLEN+1];
230
231     if (! session_fp)
232       _exit(0);
233     
234     _mailview = NULL;
235     for(;;)
236     {
237         if (fscanf(session_fp,"%s",buf) == EOF)
238           break;
239         
240         switch (buf[0])
241         {
242           case 'R':
243           {
244             RoamMenuWindow      *rmw = NULL;
245             
246             rmw = RoamMenuWindow::restoreSession(buf);
247             if(_mailview == NULL)
248             {
249                 dtmail_mapped = 1;
250                 _mailview = rmw;
251             }  
252             break;
253           }
254           case 'S':
255             SendMsgDialog::restoreSession(buf);
256             break;
257           default:
258           {
259             LOG_DEFINEFILEPTR(log);
260             LOG_OPENFILEPTR(log);
261             LOG_FPRINTF(log, (log, "%s contains neither an R or an S", buf));
262             LOG_CLOSEFILEPTR(log);
263             break;      
264           }
265         }
266     }
267
268
269 /*
270  * This method implements the SmSaveLocal SaveYourself XSMP operation for the
271  * RoamApp object:
272  *   1. Gets a session file name from Dt services and opens the session file. 
273  *   2. Invokes a saveSessionLocal on each top level window.
274  *   3. Updates the WM_COMMAND property. 
275  */
276 void 
277 RoamApp::smpSaveSessionLocal(void)
278 {
279     char *pathname = NULL, *filename = NULL;
280     char **save_argv = NULL;
281     int save_argc = 0;
282     char **argv = NULL;
283     int argc = 0;
284     
285     if (! DtSessionSavePath(_w, &pathname, &filename))
286       return;
287     
288     if (! (session_fp = fopen(pathname, "w+")))
289     {
290         perror(pathname);
291         XtFree((char *)pathname);
292         XtFree((char *)filename);
293         session_fp = NULL;
294         return;
295     }
296     chmod(pathname, S_IRUSR | S_IRGRP | S_IWUSR | S_IWGRP);
297     
298     for(int i = 0; i<_numWindows; i++)
299       _windows[i]->smpSaveSessionLocal();
300     
301     fclose(session_fp);
302     session_fp = NULL;
303     
304     XtVaGetValues(_w, XtNrestartCommand, &argv, NULL);
305
306 #if 0
307     for (i=0; NULL != argv[i]; i++) {}
308     save_argv = (char**) XtMalloc((i+3)*sizeof(char*));
309     for (save_argc=0; save_argc<i; save_argc++)
310       save_argv[save_argc] = argv[save_argc];
311 #else
312     save_argc = 0;
313     save_argv = (char**) XtMalloc(3*sizeof(char*));
314     save_argv[save_argc++] = argv[0];
315 #endif
316     save_argv[save_argc++] = "-session";
317     save_argv[save_argc++] = filename;
318     save_argv[save_argc] = NULL;
319     
320     LOG_DEFINEFILEPTR(log);
321     LOG_OPENFILEPTR(log);
322     for (int j=0; j<save_argc; j++)
323     {
324         LOG_FPRINTF(log, (log, "WM_COMMAND[%d]: %s\n",j,save_argv[j]));
325     }
326     LOG_CLOSEFILEPTR(log);
327     
328     XtVaSetValues(_w, XtNrestartCommand, save_argv, NULL);
329     /* There should be no code after this */
330 }
331
332 /*
333  *
334  */
335 int
336 RoamApp::smpSaveSessionGlobal(void)
337 {
338     int cancel;
339
340     for(int i = 0; i<_numWindows; i++)
341       if (_windows[i]->smpSaveSessionGlobal())
342         cancel = 1;
343     
344     return cancel;
345 }
346
347 /*
348  * Restores a RoamMenuWindow from a RoamMenuWindow::SaveSessionLocal string.
349  */
350 RoamMenuWindow *
351 RoamMenuWindow::restoreSession(char *buf)
352 {
353     RoamMenuWindow *rmw = NULL;
354     char *workspaces = new char[256];
355     int iconic = 0; 
356     int x = 0, y = 0; 
357     int width = 0, height = 0;
358     char *ptr;
359     Atom *workspace_atoms = NULL;
360     int num_workspaces = 0;
361
362     LOG_DEFINEFILEPTR(log);
363     LOG_OPENFILEPTR(log);
364     
365     if (!strncmp(buf,"RoamMenu", 8))
366     { 
367         FILE    *fp = theRoamApp.sessionFile();
368
369         LOG_FPRINTF(log, (log, "Is a RMW"));
370         if (fscanf(
371                 fp, "%s%s%d%d%d%d%d",
372                 buf,workspaces,&iconic,&x,&y,&width,&height) != 7)
373         {
374             fscanf(fp,"[\n]",buf);
375             LOG_CLOSEFILEPTR(log);
376             return NULL;
377         }
378
379         LOG_FPRINTF(log, (log, "Restore: RoamMenu %s %s %d %d %d %d %d\n",
380                           buf,workspaces,iconic,x,y,width,height));
381                 
382         if (0 == strncmp(buf, INBOX, strlen(INBOX)))
383         {
384             DtMail::Session     *d_session;
385             DtMailEnv           error;
386             DtMailObjectSpace   space;
387             char                *inboxname;
388                     
389             d_session = theRoamApp.session()->session();
390             d_session->queryImpl(error,
391                                 d_session->getDefaultImpl(error),
392                                 DtMailCapabilityInboxName,
393                                 &space,
394                                 &inboxname);
395
396             strncpy(buf, inboxname, MAXPATHLEN);
397             buf[MAXPATHLEN] = '\0';
398             if (NULL != inboxname)
399               free(inboxname);
400         }
401
402         rmw =  new RoamMenuWindow(buf);
403         rmw->initialize();
404
405         // Use the appropriate DtWsm* method to restore the window
406         // to the workspace it belonged to.
407         // A problem though: the DtWsm* methods require the widget
408         // to be realized.  We normally realize the window only when
409         // we call manage.  If we call manage now, the window will
410         // pop up in the default workspace and then *move* to the
411         // appropriate workspace later.  To avoid this, we realize,
412         // but not manage, the widget, call the DtWsm* method,
413         // and then manage the widget.  This will cause the window
414         // to appear only in the appropriate workspace.
415         Widget bw = rmw->baseWidget();
416         XtRealizeWidget(bw);
417         XmUpdateDisplay(bw);
418
419         // If the arguments are all valid, use them.
420         // Else let the values in app-defaults take over.
421         if (((iconic == 0) || (iconic == 1)) &&
422             x >= 0 &&
423             y >= 0 &&
424             width > 0 &&
425             height > 0)
426         {
427             XtVaSetValues(bw,
428                         XtNinitialState, 
429                         (iconic ? IconicState: NormalState), 
430                         XtNx, (Position)x, XtNy, (Position)y, 
431                         XtNwidth, (Dimension)width, XtNheight, 
432                         (Dimension)height, NULL);
433   
434             if (workspaces)
435             {
436                 do
437                 {
438                     ptr = strchr (workspaces, '*');
439                     if (ptr != NULL) *ptr = 0;
440                                 
441                     workspace_atoms = (Atom*) XtRealloc(
442                                         (char*) workspace_atoms, 
443                                         sizeof(Atom) * (num_workspaces+1));
444
445                     workspace_atoms[num_workspaces] = 
446                       XmInternAtom (XtDisplay(bw), workspaces, True);
447                                         
448                     num_workspaces++;
449
450                     if (ptr != NULL)
451                     {
452                         *ptr = '*';
453                         workspaces = ptr + 1;
454                     }
455                 } while (ptr != NULL);
456
457                 DtWsmSetWorkspacesOccupied(
458                                         XtDisplay(bw),
459                                         XtWindow (bw),
460                                         workspace_atoms,
461                                         num_workspaces);
462
463                 XtFree((char*) workspace_atoms);
464                 workspace_atoms = NULL;
465                           
466             }
467                 
468         }
469
470         // Manage the RMW now.  This will cause the window
471         // to appear in the correct workspace.
472         rmw->manage();
473     }
474
475     LOG_CLOSEFILEPTR(log);
476     return rmw;
477 }
478
479 /*
480  * This method implements the save yourself operation for
481  * RoamMenuWindow object. The steps involved are:
482  *      1. Get the session file pointer from theRoamApp.
483  *      2. Get the iconic state, mail folder, x, y, width, height and 
484  *         save it. 
485  */
486 void
487 RoamMenuWindow::smpSaveSessionLocal(void)
488 {
489     WmState     *iconic_state = NULL;
490     FILE        *fp = theRoamApp.sessionFile();
491     Display     *display = theRoamApp.display();
492     int         initialstate = 0;
493     Atom        wm_state, actual_type;
494     unsigned long nitems, leftover;
495     int         actual_format;
496     Atom        *ws_presence = NULL;
497     char        *workspace_name=NULL;
498     unsigned long num_workspaces = 0;
499     char        *all_workspace_names;
500     char        *mailboxname;
501     
502     if (fp == NULL)
503       return;
504     
505     _mailbox->save();
506     wm_state = XmInternAtom(display, "WM_STATE", False);
507     XGetWindowProperty(
508                 display,XtWindow(_w), wm_state, 0L,
509                 (long)BUFSIZ, False, wm_state, &actual_type,
510                 &actual_format, &nitems, &leftover,
511                 (unsigned char **) &iconic_state);
512     
513     initialstate = (iconic_state->state == IconicState ? 1: 0);
514
515     // Get the workspaces this window is present.
516     if (DtWsmGetWorkspacesOccupied(
517                                 display, XtWindow(_w),
518                                 &ws_presence, &num_workspaces) == Success)
519     {
520          for (int j = 0; j < num_workspaces; j++)
521          {
522             workspace_name = XGetAtomName (display, ws_presence[j]);
523             if (j == 0)
524             {
525                 all_workspace_names = (char*) malloc((size_t) MAXPATHLEN + 1);
526                 strcpy(all_workspace_names, (char*) workspace_name);
527             }
528             else {
529                 (void) strcat(all_workspace_names, "*");
530                 (void) strcat(all_workspace_names, workspace_name);
531             }
532             
533             XtFree ((char *) workspace_name);
534          }
535
536          XFree((char *)ws_presence);
537       }
538
539     if (_inbox)
540       mailboxname = INBOX;
541     else
542       mailboxname = _mailbox_fullpath;
543
544     (void) fprintf(
545                 fp, "RoamMenu %s %s %d %d %d %d %d\n",
546                 mailboxname,
547                 all_workspace_names, initialstate,
548                 (int)_x, (int)_y, 
549                 (int)_width, (int)_height);
550
551     LOG_DEFINEFILEPTR(log);
552     LOG_OPENFILEPTR(log);
553     LOG_FPRINTF(log, (log, "Save: RoamMenu %s %s %s %d %d %d %d %d\n",
554                       XtName(_w), mailboxname,
555                       all_workspace_names, initialstate,
556                       (int)_x, (int)_y,
557                       (int)_width, (int)_height));
558     LOG_CLOSEFILEPTR(log);
559 }
560
561 /*
562  *
563  */
564 int
565 RoamMenuWindow::smpSaveSessionGlobal(void)
566 {
567     return queryExpunge();
568 }
569
570 void
571 SendMsgDialog::restoreSession(char *buf)
572 {
573     char *workspaces = new char[256];
574     int iconic = 0; 
575     int x = 0, y = 0; 
576     int width = 0, height = 0;
577     char *ptr = NULL;
578     Atom *workspace_atoms = NULL;
579     int num_workspaces=0;
580     SendMsgDialog *smd = NULL;
581
582     LOG_DEFINEFILEPTR(log);
583     LOG_OPENFILEPTR(log);
584
585     if (!strncmp(buf,"SendMsg", 7))
586     {
587         FILE    *fp = theRoamApp.sessionFile();
588
589         LOG_FPRINTF(log, (log, "Is a SMD"));
590
591         if (fscanf(
592                 fp, "%s%s%d%d%d%d%d",
593                 buf,workspaces,&iconic,&x,&y,&width,&height) != 7)
594         {
595             fscanf(fp,"[\n]",buf);
596             LOG_CLOSEFILEPTR(log);
597             return;
598         }
599
600         LOG_FPRINTF(log, (log, "Restore: SendMsg %s %s %d %d %d %d %d\n",
601                           buf,workspaces,iconic,x,y,width,height));
602                 
603         smd =  theCompose.getWin();
604         smd->loadDeadLetter(buf);
605
606         // Use the appropriate DtWsm* method to restore the window
607         // to the workspace it belonged to.
608         // A problem though: the DtWsm* methods require the widget
609         // to be realized.  We normally realize the window only when
610         // we call manage.  If we call manage now, the window will
611         // pop up in the default workspace and then *move* to the
612         // appropriate workspace later.  To avoid this, we realize,
613         // but not manage, the widget, call the DtWsm* method,
614         // and then manage the widget.  This will cause the window
615         // to appear only in the appropriate workspace.
616         Widget bw = smd->baseWidget();
617         XtRealizeWidget(bw);
618         XmUpdateDisplay(bw);
619
620                 
621         // If the values are valid, use them.
622         // Else let the ones in the app-defaults take over.
623         if (((iconic == 0) || (iconic == 1)) &&
624             x >= 0 &&
625             y >= 0 &&
626             width > 0 &&
627             height > 0)
628         {
629             XtVaSetValues(bw,
630                         XtNinitialState, 
631                         (iconic ? IconicState: NormalState), 
632                         XtNx, (Position)x, XtNy, (Position)y, 
633                         XtNwidth, (Dimension)width, XtNheight, 
634                         (Dimension)height, NULL);
635             if (workspaces)
636             {
637                 do
638                 {
639                     ptr = strchr(workspaces, '*');
640                     if (ptr != NULL) *ptr = 0;
641                                 
642                     workspace_atoms = (Atom*) XtRealloc(
643                                         (char*) workspace_atoms, 
644                                         sizeof(Atom)*(num_workspaces+1));
645
646                     workspace_atoms[num_workspaces] = 
647                       XmInternAtom(XtDisplay(bw), workspaces, True);
648
649                     num_workspaces++;
650
651                     if (ptr != NULL)
652                     {
653                         *ptr = '*';
654                         workspaces = ptr + 1;
655                     }
656                 } while (ptr != NULL);
657
658                 DtWsmSetWorkspacesOccupied(
659                                         XtDisplay(bw),
660                                         XtWindow (bw),
661                                         workspace_atoms,
662                                         num_workspaces);
663
664                 XtFree((char*) workspace_atoms);
665                 workspace_atoms = NULL;
666             }
667         }
668
669         // Manage the SMD now.  This will cause the window
670         // to appear in the correct workspace.
671         smd->manage();
672     }
673     
674     LOG_CLOSEFILEPTR(log);
675 }
676
677 /*
678  * This method implements the save yourself operation for
679  * SendMsgDialog object. The steps involved are:
680  *      1. Get the session file pointer from theRoamApp.
681  *      2. Get the iconic state, mail folder, x, y, width, height and 
682  *         save it. 
683  */
684 void
685 SendMsgDialog::smpSaveSessionLocal(void)
686 {
687     WmState     *iconic_state = NULL;
688     FILE        *fp = theRoamApp.sessionFile();
689     Display     *display = theRoamApp.display();
690     int         initialstate = 0;
691     Atom        wm_state, actual_type;
692     unsigned long nitems, leftover;
693     int         actual_format;
694     Position    x=0, y=0;
695     Dimension   width = 0, height = 0;
696     Atom        *ws_presence = NULL;
697     char        *workspace_name = NULL;
698     unsigned long num_workspaces = 0;
699     char        *all_workspace_names;
700     char        *save_filename;
701     int j;
702
703     
704     if(fp == NULL)
705         return;
706     
707     // If tthe SMD is not being used, return.
708     if (!_msgHandle)
709         return;
710     
711     // Create a dead letter if this one is currently in use
712     if ((save_filename = tempnam(_auto_save_path, "session")) == NULL) 
713     {
714         for (int suffix = 1; ; suffix++) {
715             save_filename = (char*) malloc((size_t) MAXPATHLEN + 1);
716             sprintf(save_filename, "%s/session.%d", _auto_save_path, suffix);
717             if (SafeAccess(save_filename, F_OK) != 0)
718               break;
719         }
720     }
721     doAutoSave(save_filename);
722     
723     wm_state = XmInternAtom(display, "WM_STATE", False);
724     XGetWindowProperty(
725                 display, XtWindow(_w), wm_state, 0L,
726                 (long)BUFSIZ, False, wm_state, &actual_type,
727                 &actual_format, &nitems, &leftover,
728                 (unsigned char **) &iconic_state);
729     
730     initialstate = (iconic_state->state == IconicState ? 1: 0);
731
732     // Get the workspaces this window is present.
733     if (DtWsmGetWorkspacesOccupied(
734                                 display, XtWindow (_w),
735                                 &ws_presence, &num_workspaces) == Success)
736     {
737         for (j = 0; j < num_workspaces; j++)
738         {
739             workspace_name = XGetAtomName (display, ws_presence[j]);
740             if (j == 0)
741             {
742                 all_workspace_names = (char*) malloc((size_t) MAXPATHLEN + 1);
743                 strcpy(all_workspace_names, (char*) workspace_name);
744             }
745             else
746             {
747                 (void) strcat(all_workspace_names, "*");
748                 (void) strcat(all_workspace_names, workspace_name);
749             }
750             
751             XtFree((char*) workspace_name);
752         }
753
754          XFree((char *)ws_presence);
755     }
756
757     XtVaGetValues(
758                 _w,
759                 XtNx, &x,
760                 XtNy, &y,
761                 XtNwidth, &width,
762                 XtNheight, &height,
763                 NULL);
764
765     (void) fprintf(
766                 fp,"SendMsg %s %s %d %d %d %d %d\n",
767                 save_filename,
768                 all_workspace_names, initialstate,
769                 (int)x, (int)y, 
770                 (int)width, (int)height);
771
772     LOG_DEFINEFILEPTR(log);
773     LOG_OPENFILEPTR(log);
774     LOG_FPRINTF(log, (log, "Save: SendMsg %s %s %s %d %d %d %d %d\n",
775                       XtName(_w), save_filename,
776                       all_workspace_names, initialstate,
777                       (int)x, (int)y,
778                       (int)width, (int)height));
779     LOG_CLOSEFILEPTR(log);
780     
781     free(save_filename);
782 }
783
784 /*
785  *
786  */
787 int
788 SendMsgDialog::smpSaveSessionGlobal(void)
789 {
790     if (checkDirty())
791     {
792         if (isIconified())
793             MainWindow::manage();
794
795         // Enquire if user really wants this window to go away
796         Boolean really_quit = handleQuitDialog();
797         if (! really_quit)
798           return 1;
799         
800         _takeDown = TRUE;
801         quit();
802     }
803     return 0;
804 }
805
806 /*
807  *  Session Shell save callback.
808  */
809 void 
810 RoamApp::smpSaveSessionCB(Widget , XtPointer client, XtPointer call)
811 {
812     RoamApp             *roamapp = (RoamApp*) client;
813     XtCheckpointToken   cpToken = (XtCheckpointToken) call;
814
815     if (! roamapp->_firstSaveYourselfArrived)
816     {
817         // Skip the first one since things aren't ready yet.
818         roamapp->_firstSaveYourselfArrived = TRUE;
819         return;
820     }
821
822     if (cpToken->cancel_shutdown)
823     {
824         roamapp->unsetQuitQuickly();
825         roamapp->unsetQuitSilently();
826         return;
827     }
828
829     if (cpToken->save_type == SmSaveLocal ||
830         cpToken->save_type == SmSaveBoth)
831       roamapp->smpSaveSessionLocal();
832     
833     if (cpToken->shutdown)
834     {
835         if (cpToken->fast)
836           roamapp->setQuitQuickly();
837
838         if (cpToken->interact_style == SmInteractStyleNone ||
839             cpToken->interact_style == SmInteractStyleErrors)
840           roamapp->setQuitSilently();
841         else if (! cpToken->fast)
842           XtAddCallback(
843                         roamapp->baseWidget(),
844                         XtNinteractCallback, smpInteractCB,
845                         (XtPointer) roamapp);
846     }
847 }
848
849 /*
850  *  Session Shell die callback.
851  */
852 void 
853 RoamApp::smpDieCB(Widget, XtPointer client, XtPointer)
854 {
855     RoamApp *roamapp = (RoamApp*) client;
856     roamapp->closeAllWindows();
857 }
858
859 /*
860  *  Session Shell interact callback.
861  */
862 void 
863 RoamApp::smpInteractCB(Widget, XtPointer client, XtPointer call)
864 {
865     RoamApp *roamapp = (RoamApp*) client;
866     XtCheckpointToken   cpToken = (XtCheckpointToken) call;
867
868     if (cpToken->save_type == SmSaveGlobal ||
869         cpToken->save_type == SmSaveBoth)
870       cpToken->cancel_shutdown = roamapp->smpSaveSessionGlobal();
871 }