30f0a8a87580aafa65aef9ea1807cd5c04af80ff
[oweals/cde.git] / cde / programs / dtmail / dtmail / RoamMenuWindow.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  *+SNOTICE
25  *
26  *      $TOG: RoamMenuWindow.C /main/80 1999/07/07 14:23:51 mgreess $
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  *+ENOTICE
41  */
42 /*
43  *                   Common Desktop Environment
44  *
45  *   (c) Copyright 1993, 1994, 1995 Hewlett-Packard Company
46  *   (c) Copyright 1993, 1994, 1995 International Business Machines Corp.
47  *   (c) Copyright 1993, 1994, 1995 Sun Microsystems, Inc.
48  *   (c) Copyright 1993, 1994, 1995 Novell, Inc.
49  *   (c) Copyright 1995 Digital Equipment Corp.
50  *   (c) Copyright 1995 Fujitsu Limited
51  *   (c) Copyright 1995 Hitachi, Ltd.
52  *                                                                   
53  *
54  *                     RESTRICTED RIGHTS LEGEND                              
55  *
56  *Use, duplication, or disclosure by the U.S. Government is subject to
57  *restrictions as set forth in subparagraph (c)(1)(ii) of the Rights in
58  *Technical Data and Computer Software clause in DFARS 252.227-7013.  Rights
59  *for non-DOD U.S. Government Departments and Agencies are as set forth in
60  *FAR 52.227-19(c)(1,2).
61
62  *Hewlett-Packard Company, 3000 Hanover Street, Palo Alto, CA 94304 U.S.A.
63  *International Business Machines Corp., Route 100, Somers, NY 10589 U.S.A. 
64  *Sun Microsystems, Inc., 2550 Garcia Avenue, Mountain View, CA 94043 U.S.A.
65  *Novell, Inc., 190 River Road, Summit, NJ 07901 U.S.A.
66  *Digital Equipment Corp., 111 Powdermill Road, Maynard, MA 01754, U.S.A.
67  *Fujitsu Limited, 1015, Kamikodanaka Nakahara-Ku, Kawasaki 211, Japan
68  *Hitachi, Ltd., 6, Kanda Surugadai 4-Chome, Chiyoda-ku, Tokyo 101, Japan
69  */
70
71 #include <stdio.h>
72 #include <unistd.h>
73 #include <sys/param.h>
74
75 #if !defined(USL)
76 #include <strings.h>
77 #endif
78 #include <errno.h>
79 #include <unistd.h>
80 #include <sys/utsname.h>
81 #ifdef SunOS
82 #include <sys/systeminfo.h>
83 #endif
84 #include <X11/Xlib.h>
85 #include <X11/Intrinsic.h>
86 #include <X11/cursorfont.h>
87 #include <Xm/TextF.h>
88 #include <Xm/Text.h>
89 #include <Xm/Form.h>
90 #include <Xm/RepType.h>
91 #include <Xm/PanedW.h>
92 #include <Xm/PushB.h>
93 #include <Xm/RowColumn.h>
94 #include <Xm/Label.h>
95 #include <Xm/LabelG.h>
96 #include <Xm/List.h>
97 #include <Xm/Xm.h>
98 #include <Dt/Dnd.h>
99 #include <DtMail/DtMailTypes.h>
100 #include <DtMail/IO.hh>
101 #include "SelectFileCmd.h"
102 #include "RoamMenuWindow.h"
103 #include "RoamApp.h"
104 #include "ButtonInterface.h"
105 #include "WorkingDialogManager.h"
106 #ifdef DEAD_WOOD
107 #include "QuestionDialogManager.h"
108 #endif /* DEAD_WOOD */
109 #include "MemUtils.hh"
110 #include "Help.hh"
111 #include "DtMailHelp.hh"
112 #include "MailMsg.h"
113 #include "SendMsgDialog.h"
114 #include "AttachArea.h"
115 #include "Attachment.h"
116
117 #include <DtMail/OptCmd.h>
118 #include "ComposeCmds.hh"
119 #include "EUSDebug.hh"
120
121 #include "SortCmd.hh"
122
123 extern int force( Widget );
124
125  static const char * NormalIcon = "DtMail";
126  static const char * EmptyIcon = "DtMnone";
127  static const char * NewMailIcon = "DtMnew";
128  static const char * MailDragIcon = "DtMmsg";
129
130 extern nl_catd  DtMailMsgCat;
131 #define MAXIMUM_PATH_LENGTH     2048
132
133 #define         RMW_CONCAT_MAILRC_KEY(buf, pfx, key) \
134 { if (NULL==(pfx)) (void) sprintf((buf), "%s", (key)); \
135   else (void) sprintf((buf), "%s_%s", (pfx), (key)); }
136
137 char *
138 RoamMenuWindow:: _supported[] =
139 {
140   "TARGETS", "MESSAGES", "STRING", "DELETE"
141 };
142 enum {TARGETS,MESSAGES, STR, DEL};
143
144 XtResource
145 RoamMenuWindow::_resources[] =
146 {
147   {
148     "fullheader",
149     "FullHeader",
150     XtRBoolean,
151     sizeof( Boolean ),
152     XtOffset ( RoamMenuWindow *, _full_header_resource ),
153     XtRBoolean,
154     ( XtPointer ) 0,
155   },
156
157   {
158     "mailbox",
159     "MailBox",
160     XtRString,
161     sizeof( XtRString ),
162     XtOffset ( RoamMenuWindow *, _mailbox_name_resource ),
163     XtRString,
164     ( XtPointer ) NULL,
165   },
166
167   {
168     "mailfiles",
169     "MailFiles",
170     XtRString,
171     sizeof( XtRString ),
172     XtOffset ( RoamMenuWindow *, _mail_files_resource ),
173     XtRString,
174     ( XtPointer ) NULL,
175   },
176
177 };
178
179
180 // We need to maintain a constant WM_CLASS_NAME for SQE test
181 // suites to run consistently for all RMWs.  We do that by
182 // maintaining a constant "name", as in WM_CLASS_NAME, for all
183 // RMWs by passing "dtmail" to a RMW's parent
184 // at creation time.  We distinguish individual RMWs via the
185 // title which indicates what mail container they are currently
186 // looking at.  The title is passed here as name; its dynamic
187 // (i.e., each RMW has its own "name", as in WM_NAME).
188 // If you are going to change the name, talk to SQE
189 // and get their consent for whatever change you are making.
190 //
191 // Note also that the name chosen must match whatever is specified
192 // in dtwm.fp (front panel configuration file) as the CLIENT_NAME
193 // for the Mail CONTROL. This is so PUSH_RECALL works.
194 // Typically this is the executable name.
195
196 RoamMenuWindow::RoamMenuWindow (char *name) : MenuWindow ("dtmail", True)
197 {
198     DtMailEnv mail_error;
199     
200     // Initialize mail_error.
201     mail_error.clear();
202     
203     // Get a handle to the Inbox.
204     char                *mail_file = NULL;
205     DtMailObjectSpace   space;
206     DtMail::Session     *d_session = theRoamApp.session()->session();
207     DtMail::MailRc      *mailrc = d_session->mailRc(mail_error);
208     const char          *value = NULL;
209     char                *buffer = NULL;
210
211     _forward_filename = NULL;
212     // Set the _mailbox_name here.  
213     // In the absence of the RMW's title being set via title(),
214     // the _mailbox_name is what will be used in initialize().
215     _mailbox_name = NULL;
216     if (name)
217       mailboxName(name);
218     else
219       mailboxName("");
220     _mailbox_fullpath = NULL;
221
222     _mailbox_name_resource = NULL;
223     _mail_files_resource = NULL;
224     _full_header_resource = FALSE;
225
226     _required_conversion = FALSE;
227     _checkformail_when_mapped = FALSE;
228     _delete_on_quit = FALSE;
229     _we_called_newmail = FALSE;
230
231     _dialogs = NULL;
232     _numDialogs = 0;
233     _findDialog = NULL;
234
235     //
236     // ContainerList
237     //
238     _display_cached_list = FALSE;
239     _max_cached_list_size = 0;
240     _first_cached_item = 0;
241     _user_containerlist = NULL;
242     _cached_containerlist = NULL;
243     _filemenu2 = NULL;
244
245     //
246     // File Menu
247     //
248     _file_cmdlist = NULL;
249     _file_separator = NULL;
250     _file_check_new_mail = NULL;
251     _file_open_inbox    = NULL;
252     _file_new_container = NULL;
253     _file_open  = NULL;
254     _file_destroy_deleted_msgs = NULL;
255     _file_quit  = NULL;
256
257     _file_cascade = NULL;
258
259     //
260     // OpenContainer Cascade Menu
261     //
262     _open_container_cmdlist = NULL;
263     _open_container_separator = NULL;
264     _open_container_inbox = NULL;
265     _open_container_other = NULL;
266
267     _open_container_containerlist = NULL;
268     _open_container_containerlist_cached = NULL;
269     _opencontainerMenu = NULL;
270
271     //
272     // Message Menu
273     //
274     _msg_cmdlist = NULL;
275     _msg_separator = NULL;
276     _msg_open = NULL;
277     _msg_save_as = NULL;
278     _msg_print = NULL;
279     _msg_find = NULL;
280     _msg_select_all = NULL;
281     _msg_delete = NULL;
282     _msg_undelete_last = NULL;
283     _msg_undelete_from_list = NULL;
284     
285
286     //
287     // CopyTo Cascade Menu
288     //
289     _copyto_cmdlist = NULL;
290     _copyto_separator = NULL;
291     _copyto_inbox = NULL;
292     _copyto_other = NULL;
293
294     _copyto_containerlist = NULL;
295     _copyto_containerlist_cached = NULL;
296     _copytoMenu = NULL;
297     _message_cascade = NULL;
298     
299
300     //
301     // Edit Menu
302     //
303     _edit_cmdlist = NULL;
304     _edit_copy = NULL;
305     _edit_select_all = NULL;
306
307
308     //
309     // Attachment menu
310     //
311     _att_cmdlist = NULL;
312     _att_save = NULL;
313     _att_select_all = NULL;
314
315     //
316     // View Menu
317     //
318     _view_cmdlist = NULL;
319     _view_separator = NULL;
320     _view_next = NULL;
321     _view_previous = NULL;
322     _view_abbrev_headers = NULL;
323     _view_sortTD = NULL;
324     _view_sortSender = NULL;    
325     _view_sortSubject = NULL;   
326     _view_sortSize = NULL;      
327     _view_sortStatus = NULL;
328     
329     //
330     // Compose Menu
331     //
332     _comp_cmdlist = NULL;
333     _comp_separator = NULL;
334     _comp_new = NULL;
335     _comp_new_include = NULL;
336     _comp_forward = NULL;
337     _comp_replySender = NULL;
338     _comp_replyAll = NULL;
339     _comp_replySinclude = NULL;
340     _comp_replyAinclude = NULL;
341     
342     
343     //
344     // Move Menu
345     //
346     _move_cmdlist = NULL;
347     _move_separator = NULL;
348     _move_inbox = NULL;
349     _move_other = NULL;
350
351     _move_containerlist = NULL;
352     _move_containerlist_cached = NULL;
353     _moveMenu = NULL;
354     _move_cascade = NULL;
355
356
357     // Help Menu
358     _help_cmdlist = NULL;
359     _help_separator = NULL;
360     _help_overview = NULL;
361     _help_tasks = NULL;
362     _help_reference = NULL;
363     _help_on_item = NULL;
364     _help_using_help = NULL;
365     _help_about_mailer = NULL;
366     
367     //
368     // Message Popup
369     //
370     _msgsPopup_cmdlist = NULL;
371     _msgsPopup_separator = NULL;
372
373     _menuPopupMsgs = NULL;
374     _msgsPopupMenu = NULL;
375     _msgsPopupMoveMenu = NULL;
376     
377     //
378     // Text Popup
379     //
380     _textPopup_cmdlist = NULL;
381     _textPopup_separator = NULL;
382     
383     //
384     // Attachment Popup
385     //
386     _attPopup_cmdlist = NULL;
387     _attPopup_separator = NULL;
388     _attActions_cmdlist = NULL;
389
390     _attachmentMenu = NULL;
391
392     //
393     // ConvertContainerCmd
394     //
395     _convertContainerCmd = NULL;
396     _openContainerCmd = NULL;
397
398     //
399     // Message view pane buttons
400     //
401     _delete_button = NULL;
402     _next_button = NULL;
403     _previous_button = NULL;
404     _replySender_button = NULL;
405     _print_button = NULL;
406     _move_copy_button = NULL;
407
408     
409     _mailbox    = NULL;
410     d_session->queryImpl(mail_error,
411                          d_session->getDefaultImpl(mail_error),
412                          DtMailCapabilityInboxName,
413                          &space,
414                          &mail_file);
415     if (strcmp(mail_file, mailboxName()) == 0)
416       _inbox = TRUE;
417     else
418       _inbox = FALSE;
419
420     free((void*)mail_file);
421
422     _list       = NULL;
423     _genDialog  = NULL;
424
425     //
426     // Initialize private variables
427     //
428     _mbox_image = 0;
429     _mbox_mask  = 0;
430
431     _my_editor = NULL;
432     _message = NULL;
433     _message_summary = NULL;
434     _rowOfLabels = NULL;
435     _rowOfButtons = NULL;
436     _rowOfMessageStatus = NULL;
437
438     _quitWorkprocID = 0;
439     _clear_message_p = FALSE;
440     _is_loaded = FALSE;
441
442
443     buffer = XtMalloc(BUFSIZ);
444     if (buffer)
445     {
446         if (_inbox)
447         {
448             RMW_CONCAT_MAILRC_KEY(buffer, DTMAS_INBOX, "sortby");
449         }
450         else
451         {
452             RMW_CONCAT_MAILRC_KEY(buffer, mailboxName(), "sortby");
453         }
454     }
455     
456     mail_error.clear();
457     mailrc->getValue(mail_error, buffer, &value);
458     if (mail_error.isSet() || NULL == value)
459       _last_sorted_by = SortTimeDate;
460     else
461       _last_sorted_by = (SortBy) atoi(value);
462
463     free((void*) value);
464     XtFree(buffer);
465
466 }
467
468 RoamMenuWindow::~RoamMenuWindow() 
469 {
470     DtMailEnv   error;
471
472     error.clear();
473     theRoamApp.session()->close(error, _mailbox);
474     if (error.isSet()) {
475         // Cannot return error to caller since there's
476         // no caller.  What do we do?
477         // exit(0)??
478     }
479     
480     if (NULL != _forward_filename)
481       free(_forward_filename);
482     if (_mailbox_name)
483         free((void*) _mailbox_name);
484     if (_mailbox_fullpath)
485         free((void*) _mailbox_fullpath);
486
487     if (NULL != _dialogs)
488         delete []_dialogs;
489     if (NULL != _findDialog)
490       delete _findDialog;
491
492
493     // ContainerLists
494     if (NULL != _user_containerlist)
495       delete _user_containerlist;
496     if (NULL != _cached_containerlist)
497       delete _cached_containerlist;
498     if (NULL != _filemenu2)
499       free((void*) _filemenu2);
500
501     // File Menu
502     delete      _file_cmdlist;
503     delete      _file_separator;
504     delete      _file_check_new_mail;
505     delete      _file_open_inbox;
506     delete      _file_new_container;
507 #if defined(USE_OLD_FILE_OPEN)
508     delete      _file_open;
509 #endif
510     delete      _file_destroy_deleted_msgs;
511     delete      _file_quit;
512
513     // OpenContainer Cascade Menu
514     delete      _open_container_cmdlist;
515     delete      _open_container_separator;
516     delete      _open_container_inbox;
517     delete      _open_container_other;
518
519     if (NULL != _open_container_containerlist)
520       delete _open_container_containerlist;
521     if (NULL != _open_container_containerlist_cached)
522       delete _open_container_containerlist_cached;
523
524
525     // Message Menu
526     delete      _msg_cmdlist;
527     delete      _msg_separator;
528     delete      _msg_open;
529     delete      _msg_save_as;
530     delete      _msg_print;
531     delete      _msg_find;
532     delete      _msg_delete;
533     delete      _msg_undelete_last;
534     delete      _msg_undelete_from_list;
535
536     // CopyTo Cascade Menu
537     delete      _copyto_cmdlist;
538     delete      _copyto_separator;
539     delete      _copyto_inbox;
540     delete      _copyto_other;
541
542     if (NULL != _copyto_containerlist)
543       delete _copyto_containerlist;
544     if (NULL != _copyto_containerlist_cached)
545       delete _copyto_containerlist_cached;
546
547     // Edit Menu
548     delete      _edit_cmdlist;
549     delete      _edit_copy;
550     delete      _edit_select_all;
551
552     // Attachment menu
553     delete      _att_cmdlist;
554     delete      _att_save;
555     delete      _att_select_all;
556
557     // View Menu
558     delete      _view_cmdlist;
559     delete      _view_separator;
560     delete      _view_next;
561     delete      _view_previous;
562     delete      _view_abbrev_headers;
563     delete      _view_sortTD;
564     delete      _view_sortSender;       
565     delete      _view_sortSubject;      
566     delete      _view_sortSize; 
567     delete      _view_sortStatus;
568     
569     // Compose Menu
570     delete      _comp_cmdlist;
571     delete      _comp_separator;
572     delete      _comp_new;
573     delete      _comp_new_include;
574     delete      _comp_forward;
575     delete      _comp_replySender;
576     delete      _comp_replyAll;
577     delete      _comp_replySinclude;
578     delete      _comp_replyAinclude;
579     
580     // Move menu
581     delete      _move_cmdlist;
582     delete      _move_separator;
583     delete      _move_inbox;
584     delete      _move_other;
585
586     if (NULL != _move_containerlist)
587       delete _move_containerlist;
588     if (NULL != _move_containerlist_cached)
589       delete _move_containerlist_cached;
590
591     // Help Menu
592     delete      _help_separator;
593     delete      _help_cmdlist;
594     delete      _help_overview;
595     delete      _help_tasks;
596     delete      _help_reference;
597     delete      _help_on_item;
598     delete      _help_using_help;
599     delete      _help_about_mailer;
600     
601     // Message Popup
602     delete      _msgsPopup_cmdlist;
603     delete      _msgsPopup_separator;
604
605     delete      _menuPopupMsgs;
606
607     // Text Popup
608     delete      _textPopup_cmdlist;
609     delete      _textPopup_separator;
610
611     // Attachment Popup
612     delete      _attPopup_cmdlist;
613     delete      _attPopup_separator;
614     delete      _attActions_cmdlist;
615     
616     // ConvertContainerCmd
617     delete      _convertContainerCmd;
618     delete      _openContainerCmd;
619     
620     // Message view pane buttons
621     delete      _delete_button;
622     delete      _next_button;
623     delete      _previous_button;
624     delete      _replySender_button;
625     delete      _print_button;
626     delete      _move_copy_button;
627     
628     delete      _genDialog;
629
630     if (_list)
631     {
632         _list->shutdown();
633         delete  _list;
634     }
635
636     // Private
637     if (_mbox_image)
638         XmDestroyPixmap(XtScreen(baseWidget()), _mbox_image);
639     if (_mbox_mask)
640         XmDestroyPixmap(XtScreen(baseWidget()), _mbox_mask);
641     delete      _my_editor;
642 }
643
644 void
645 RoamMenuWindow::initialize()
646 {
647     XmRepTypeInstallTearOffModelConverter();
648     MenuWindow::initialize();
649
650     if (!this->baseWidget())
651     {
652         fprintf(
653                 stderr, "%s",
654                 GETMSG(DT_catd, 2, 3,
655                   "Unable to initialize windows. Exiting.\n"));
656         exit(1);
657     }
658
659     busyCursor();
660     setStatus(GETMSG(DT_catd, 3, 2, "Initializing..."));
661
662     // XInternAtom(XtDisplay(this->baseWidget()) ,"STRING", False);
663     // XInternAtom(XtDisplay(this->baseWidget()) ,"MESSAGES", False);
664     getResources(_resources, XtNumber(_resources));
665     if (_mailbox_name_resource) mailboxName(_mailbox_name_resource);
666     
667     // Mailbox image & mask
668     {
669         Screen *screen = XtScreen(baseWidget());
670         char    icon_name[256];
671
672         sprintf(icon_name, "%s.m", MailDragIcon);
673         _mbox_image = XmGetPixmap(screen, icon_name,
674             BlackPixelOfScreen(screen), WhitePixelOfScreen(screen));
675
676         sprintf(icon_name, "%s.m_m.bm", MailDragIcon);
677         _mbox_mask = XmGetPixmapByDepth(screen, icon_name, 1, 0, 1);
678
679         if (_mbox_image == XmUNSPECIFIED_PIXMAP ||
680             _mbox_mask == XmUNSPECIFIED_PIXMAP)
681           _mbox_image = _mbox_mask = 0;
682     }
683     
684     // Add an event handler for structureNotify.
685     // This EH will handle exposure, configure notifies ...
686     XtAddEventHandler(
687                 this->baseWidget(), StructureNotifyMask, False,
688                 (XtEventHandler) &RoamMenuWindow::structurenotify,
689                 (XtPointer) this);
690
691     _convertContainerCmd = new ConvertContainerCmd(
692                                         "convertContainer", 
693                                         "convertContainer", 
694                                         TRUE, this);
695     _openContainerCmd = new OpenContainerCmd(
696                                         "openContainer", 
697                                         "openContainer",
698                                         TRUE, this);
699     _genDialog = new DtMailGenDialog("Dialog", _main);
700     setIconName(NormalIcon);
701 }
702
703 Boolean
704 RoamMenuWindow::inbox()
705 {
706     return(_inbox);
707 }
708
709 Widget
710 RoamMenuWindow::createWorkArea(Widget parent)
711 {
712     Widget form1, panedW;
713     Widget form2, form3;
714     Dimension x, y, width, height, bwid;
715     VacationCmd *vacation_cmd = theRoamApp.vacation();
716
717     form1 = XmCreateForm(parent, "Work_Area",  NULL, 0);
718     XtVaSetValues(form1, XmNresizePolicy, XmRESIZE_NONE, NULL);
719
720     printHelpId("form1", form1);
721     /* add help callback */
722     // XtAddCallback(form1, XmNhelpCallback, HelpCB, helpId);
723     XtAddCallback(form1, XmNhelpCallback, HelpCB, (void *)DTMAILWINDOWID);
724
725     panedW = XtCreateManagedWidget("panedW", xmPanedWindowWidgetClass,
726                                    form1, NULL, 0);
727     printHelpId ("panedW", panedW);
728     /* add help callback */
729     // XtAddCallback(panedW, XmNhelpCallback, HelpCB, helpId);
730
731     XtVaSetValues(panedW,
732         XmNrightAttachment,XmATTACH_FORM, 
733         XmNleftAttachment,XmATTACH_FORM, 
734         XmNtopAttachment,XmATTACH_FORM,
735         XmNbottomAttachment, XmATTACH_FORM,
736         XmNsashIndent, -30,
737         XmNsashWidth, 18,
738         XmNsashHeight, 12,
739         NULL );
740
741
742     form2 = XtCreateManagedWidget("form2", xmFormWidgetClass, panedW, NULL, 0);
743     XtVaSetValues(form2, XmNallowResize, True, NULL);
744     printHelpId ("form2", form2);
745     /* add help callback */
746     // XtAddCallback(form2, XmNhelpCallback, HelpCB, helpId);
747
748     _rowOfLabels =
749       XtCreateManagedWidget("RowOfLabels", xmFormWidgetClass, form2, NULL, 0);
750
751     printHelpId("rowOfLabels", _rowOfLabels);
752     /* add help callback */
753     // XtAddCallback(_rowOfLabels, XmNhelpCallback, HelpCB, helpId);
754     XtAddCallback(
755         _rowOfLabels, XmNhelpCallback, HelpCB, (void *)DTMAILWINDOWROWOFLABELSID);
756
757     XtVaSetValues(_rowOfLabels, 
758                   XmNrightAttachment,XmATTACH_FORM, 
759                   XmNleftAttachment,XmATTACH_FORM, 
760                   XmNtopAttachment,XmATTACH_FORM,
761                   XmNtopOffset, 5,
762                   XmNorientation, XmHORIZONTAL,
763                   XmNspacing, 120,
764                   XmNmarginWidth, 10,
765                   XmNentryAlignment, XmALIGNMENT_CENTER,
766                   NULL);
767
768     _list = new MsgScrollingList( this, form2, "Message_List");
769     msgListDragSetup();
770
771     DtMailEnv error;
772     DtMail::Session *d_session = theRoamApp.session()->session();
773     DtMail::MailRc  *mailrc = d_session->mailRc(error);
774     const char      *value = NULL;
775     int             msgnums = False;
776
777     this->addToRowOfLabels(_list);
778
779     // See if the header size has changed.
780     value = NULL;
781     mailrc->getValue(error, "headerlines", &value);
782     if (error.isSet()) value = strdup("15");
783
784     int header_lines = (int) strtol(value, NULL, 10);
785     _list->visibleItems(header_lines);
786     free((void*) value);
787
788     XtAddCallback(
789         _list->get_scrolling_list(), XmNhelpCallback, 
790         HelpCB, (void *)DTMAILMSGLISTID);
791
792     XtVaSetValues(_list->get_scrolling_list(), XmNuserData, this, NULL);
793     _rowOfButtons =
794       XtCreateManagedWidget("RowColumn", xmFormWidgetClass, form2, NULL, 0);
795     printHelpId ("rowOfButtons", _rowOfButtons);
796     // Add help callback
797     // XtAddCallback(_rowOfButtons, XmNhelpCallback, HelpCB, helpId);
798
799
800     // Place it closer to the scrolling list than to the text widget
801     // that is below.
802     XtVaSetValues(XtParent(_list->get_scrolling_list()),
803                 XmNrightAttachment,XmATTACH_FORM, 
804                 XmNleftAttachment,XmATTACH_FORM, 
805                 XmNtopAttachment,XmATTACH_WIDGET,
806                 XmNtopWidget, _rowOfLabels,
807                 XmNtopOffset, 3,
808                 XmNbottomAttachment, XmATTACH_WIDGET,
809                 XmNbottomWidget, _rowOfButtons,
810                 XmNbottomOffset, 7,
811                 NULL );
812
813     XtVaSetValues(_rowOfButtons,
814                   XmNrightAttachment,XmATTACH_FORM, 
815                   XmNleftAttachment,XmATTACH_FORM, 
816                   XmNbottomAttachment, XmATTACH_FORM,
817                   XmNresizable, FALSE, 
818                   NULL );
819
820     this->addToRowOfButtons();
821
822     form3 = XtCreateManagedWidget("form3", xmFormWidgetClass, panedW, NULL, 0);
823     XtVaSetValues(form3, XmNallowResize, True, NULL);
824     printHelpId ("form3", form3);
825     // Add help callback
826     // XtAddCallback(form3, XmNhelpCallback, HelpCB, helpId);
827
828 #if 0
829     XtVaSetValues(form3,
830         XmNrightAttachment,XmATTACH_FORM, 
831         XmNleftAttachment,XmATTACH_FORM, 
832         XmNtopAttachment,XmATTACH_FORM, 
833         NULL );
834 #endif
835
836     _rowOfMessageStatus =
837       XtCreateManagedWidget("Message_Status", xmFormWidgetClass, form3, NULL,0);
838
839      XtVaSetValues(_rowOfMessageStatus,
840         XmNrightAttachment,XmATTACH_FORM, 
841         XmNleftAttachment,XmATTACH_FORM, 
842         XmNtopAttachment,XmATTACH_FORM,
843         XmNtopOffset, 5,
844         NULL );
845
846     this->addToRowOfMessageStatus();
847
848     _my_editor = new DtMailEditor(form3, this);
849     _my_editor->initialize();
850     _my_editor->attachArea()->setOwnerShell(this);
851
852     // DtMailEditor contains a widget that contains the textEditor and 
853     // attachArea.  Get that widget...
854
855     Widget wid = _my_editor->container();
856
857     printHelpId ("wid", wid);
858     /* add help callback */
859     // XtAddCallback(wid, XmNhelpCallback, HelpCB, helpId);
860
861     XtVaSetValues(wid,
862         XmNrightAttachment,XmATTACH_FORM, 
863         XmNleftAttachment,XmATTACH_FORM, 
864         XmNtopAttachment,XmATTACH_WIDGET, 
865         XmNtopWidget, _rowOfMessageStatus,
866         XmNbottomAttachment, XmATTACH_FORM,
867         NULL );
868
869     DtMailEnv mail_error;
870
871     // Initialize the mail_error.
872     mail_error.clear();
873     mailboxFullpath(mailboxName());
874
875     // Set the appShell's title to be _mailbox_fullpath
876     if (vacation_cmd != NULL && vacation_cmd->priorVacationRunning())
877       setVacationTitle();
878     else
879       setTitle(NULL);
880
881     // Set the icon name to the folder name.  Extract foldername from full path.
882     char *fname = strrchr(_mailbox_fullpath, '/');
883     if (fname == NULL)
884       setIconTitle(_mailbox_fullpath);
885     else
886     {
887         // Extract the filename from it.
888         fname++;
889         setIconTitle(fname);
890     }
891
892     XtManageChild(_list->baseWidget());
893     XtManageChild(form1);
894     
895     value = NULL;
896     mailrc->getValue(error, "retrieveinterval", &value);
897     if (error.isNotSet() && value && *value != '\0')
898     {
899         long ping = (time_t) strtol(value, NULL, 10);
900         if (ping <= 0)
901           _checkformail_when_mapped = FALSE;
902         else
903           _checkformail_when_mapped = TRUE;
904     }
905     error.clear();
906     if (NULL != value) free((void*) value);
907
908     XtVaGetValues(_main,
909                   XmNx, &x,
910                   XmNy, &y,
911                   XmNwidth, &width,
912                   XmNheight, &height,
913                   XmNborderWidth, &bwid,
914                   NULL);
915     _x = x;
916     _y = y;
917     _width = width;
918     _height = height;
919     _border_width = bwid;
920     return form1;
921 }
922
923 // This routine is just a place holder callback to pass when creating
924 // a mailbox when we doing want to do anything when the mailbox gets
925 // updated.
926 //
927 static DtMailBoolean
928 openCallback(
929         DtMailCallbackOp,
930         const char *,
931         const char *,
932         void *,
933         ...
934 )
935 {
936     return(DTM_FALSE);
937 }
938
939 // msgListTransferCallback
940 //
941 // Handles the transfer of data that is dragged and dropped to the
942 // MsgScrollingList.  Files and buffers are transferred by inserting 
943 // them as messages into the scrolling list.
944 //
945 void
946 RoamMenuWindow::msgListTransferCallback(
947     Widget      ,
948     XtPointer   clientData,
949     XtPointer   callData)
950 {
951     RoamMenuWindow *rmw = (RoamMenuWindow *) clientData;
952     DtDndTransferCallbackStruct *transferInfo =
953                         (DtDndTransferCallbackStruct *) callData;
954     DtDndContext        *dropData = transferInfo->dropData;
955     char                *filepath;
956     int                 ii, numItems;
957     DtMail::MailBox     *mbox, *tmpmbox;
958     DtMailEnv mail_error;
959     MailSession *session = theRoamApp.session();
960
961     DebugPrintf(3, "In RoamMenuWindow::msgListTransferCallback\n");
962
963     // Initialize the mail_error.
964     mail_error.clear();
965
966     numItems = dropData->numItems;
967
968     switch (dropData->protocol) {
969         case DtDND_FILENAME_TRANSFER:
970
971             // Loop through the files that were dropped onto the msg list
972
973             for (ii = 0; ii < numItems; ii++) {
974
975                 // Try to open the file as a mail container.
976                 filepath = dropData->data.files[ii];
977                 tmpmbox = session->open(
978                                 mail_error, filepath, 
979                                 &RoamMenuWindow::syncViewAndStoreCallback,
980                                 rmw, DTM_FALSE, DTM_TRUE);
981
982                 // Reject the drop if we weren't able to open the file.
983                 if (!tmpmbox || mail_error.isSet()) {
984                     transferInfo->status = DtDND_FAILURE;
985                     return;
986                 } else {
987                     // We were able to open the container, so now we get the 
988                     // current mailbox and copy all the messages into it.
989                     mbox = rmw->mailbox();
990                     mbox->copyMailBox(mail_error, tmpmbox);
991                     rmw->checkForMail(mail_error);
992                     delete tmpmbox;
993                 }
994             }
995             break;
996
997         case DtDND_BUFFER_TRANSFER:
998
999             // Loop through the buffers that were dropped onto the msg list
1000
1001             for (ii = 0; ii < numItems; ii++) {
1002
1003                 // Turn the dropped data into a mail buffer to pass to
1004                 // the mailbox constructor.
1005                 DtMailBuffer buf;
1006                 buf.buffer = (char *) transferInfo->dropData->data.buffers->bp;
1007                 buf.size = transferInfo->dropData->data.buffers->size;
1008
1009                 // Convert the buffer into a mailbox object.
1010                 tmpmbox = session->session()->mailBoxConstruct(mail_error,
1011                                                 DtMailBufferObject, &buf,
1012                                                 openCallback, NULL);
1013
1014                 // Reject the drop if we weren't able to convert it to a mailbox
1015                 if (!tmpmbox || mail_error.isSet()) {
1016                     transferInfo->status = DtDND_FAILURE;
1017                     return;
1018                 } else {
1019                     // Parse the dropped data into the tmpmbox.
1020                     tmpmbox->open(mail_error);
1021                     if (mail_error.isSet()) {
1022                         transferInfo->status = DtDND_FAILURE;
1023                         delete tmpmbox;
1024                         return;
1025                     }
1026                     mbox = rmw->mailbox();
1027                     mbox->copyMailBox(mail_error, tmpmbox);
1028                     rmw->checkForMail(mail_error);
1029                     delete tmpmbox;
1030                 }
1031             }
1032             break;
1033
1034         default:
1035             transferInfo->status = DtDND_FAILURE;
1036             return;
1037     }
1038 }
1039
1040 // msgListDropRegister
1041 //
1042 // Register the message list to accept file & buffer drops
1043 //
1044 void
1045 RoamMenuWindow::msgListDropRegister()
1046 {
1047     static XtCallbackRec transferCBRec[] = { 
1048         {&RoamMenuWindow::msgListTransferCallback, NULL}, {NULL, NULL} };
1049
1050     // Pass the RoamMenuWindow object (this) as clientData.
1051     transferCBRec[0].closure = this;
1052
1053     DtDndVaDropRegister(_list->get_scrolling_list(),
1054             DtDND_FILENAME_TRANSFER | DtDND_BUFFER_TRANSFER,
1055             (unsigned char)(XmDROP_MOVE | XmDROP_COPY), transferCBRec,
1056             DtNtextIsBuffer, True,
1057             NULL);
1058 }
1059
1060 // msgListDropEnable
1061 //
1062 // Enable the message list for drops by restoring the operation
1063 //
1064 void
1065 RoamMenuWindow::msgListDropEnable()
1066 {
1067     Arg args[1];
1068
1069     XtSetArg(args[0], XmNdropSiteOperations, XmDROP_MOVE | XmDROP_COPY);
1070     XmDropSiteUpdate(_list->get_scrolling_list(), args, 1);
1071 }
1072
1073 // msgListDropDisable
1074 //
1075 // Disable the message list for drops by setting the operation to noop
1076 //
1077 void
1078 RoamMenuWindow::msgListDropDisable()
1079 {
1080     Arg args[1];
1081
1082     XtSetArg(args[0], XmNdropSiteOperations, XmDROP_NOOP);
1083     XmDropSiteUpdate(_list->get_scrolling_list(), args, 1);
1084 }
1085
1086
1087 // msgListConvertCallback
1088 //
1089 // Provide the msg list as a mailbox for the drag
1090 //
1091 void
1092 RoamMenuWindow::msgListConvertCallback(
1093     Widget      /* dragContext */,
1094     XtPointer   clientData,
1095     XtPointer   callData)
1096 {
1097     DtDndConvertCallbackStruct *convertInfo =
1098                             (DtDndConvertCallbackStruct *) callData;
1099     DtDndBuffer         *buffer = &(convertInfo->dragData->data.buffers[0]);
1100     RoamMenuWindow      *rmw = (RoamMenuWindow *)clientData;
1101     MsgScrollingList    *msgList;
1102     Widget              listW;
1103     DtMail::MailBox     *mbox;
1104     DtMail::Message     *msg;
1105     DtMailMessageHandle msgHandle;
1106     DtMailBuffer        *mbufList;
1107     int                 *pos_list, pos_count, ii;
1108     unsigned long       bufSize = 0;
1109     char                *bufPtr;
1110     DtMailEnv           error;
1111
1112     DebugPrintf(3, "In RoamMenuWindow:msgListConvertCallback\n");
1113
1114     error.clear();
1115
1116     switch (convertInfo->reason) {
1117         case DtCR_DND_CONVERT_DATA:
1118
1119             msgList = rmw->list();
1120             listW = msgList->get_scrolling_list();
1121             mbox = rmw->mailbox();
1122
1123             if (!XmListGetSelectedPos(listW, &pos_list, &pos_count)) {
1124                 convertInfo->status = DtDND_FAILURE;
1125                 return;
1126             }
1127
1128             mbufList = (DtMailBuffer*)XtMalloc(pos_count*sizeof(DtMailBuffer));
1129         
1130             for (ii = 0; ii < pos_count; ii++) {
1131                     msgHandle = msgList->msgno(pos_list[ii]);
1132                     msg = mbox->getMessage(error, msgHandle);
1133                     if (error.isSet()) {
1134                         convertInfo->status = DtDND_FAILURE;
1135                         return;
1136                     }
1137                     msg->toBuffer(error, mbufList[ii]);
1138                     if (error.isSet()) {
1139                         convertInfo->status = DtDND_FAILURE;
1140                         return;
1141                     }
1142                     bufSize += mbufList[ii].size + 1;
1143             }
1144
1145             bufPtr = XtMalloc((unsigned int)bufSize);
1146
1147             buffer->bp = bufPtr;
1148             buffer->size = (int)bufSize;
1149             buffer->name = "Mailbox";
1150
1151             for (ii = 0; ii < pos_count; ii++) {
1152                 strncpy(bufPtr, (char *)mbufList[ii].buffer, 
1153                                 (unsigned int)mbufList[ii].size);
1154                 bufPtr += mbufList[ii].size;
1155                 bufPtr[0] = '\n';
1156                 bufPtr++;
1157                 delete mbufList[ii].buffer;
1158             }
1159
1160             XtFree((char *)mbufList);
1161             XtFree((char *)pos_list);
1162             break;
1163
1164         case DtCR_DND_CONVERT_DELETE:
1165             // The drag and drop succeeded, so we can now delete the messages
1166             // from the scrolling list.
1167             rmw->list()->deleteSelected();
1168             break;
1169     }
1170 }
1171
1172 // msgListDragFinishCallback
1173 //
1174 // Clean up from the convert callback and restore state
1175 //
1176 void
1177 RoamMenuWindow::msgListDragFinishCallback(
1178         Widget          /* widget */,
1179         XtPointer       clientData,
1180         XtPointer       callData)
1181 {
1182     DtDndDragFinishCallbackStruct *finishInfo =
1183                 (DtDndDragFinishCallbackStruct *) callData;
1184     DtDndContext        *dragData = finishInfo->dragData;
1185     RoamMenuWindow      *rmw = (RoamMenuWindow *) clientData;
1186     MsgScrollingList    *msgList = rmw->list();
1187     DtMailEnv           mail_error;
1188     int                 ii;
1189
1190     DebugPrintf(3, "In RoamMenuWindow::msgListDragFinishCallback\n");
1191
1192     mail_error.clear();
1193
1194     // Re-enable drops on this message list
1195     if (rmw->mailbox()->mailBoxWritable(mail_error) == DTM_TRUE) {
1196         rmw->msgListDropEnable();
1197     }
1198
1199     if (finishInfo->sourceIcon)
1200         XtDestroyWidget(finishInfo->sourceIcon);
1201
1202     // Free any memory allocated for the drag.
1203     for (ii = 0; ii < dragData->numItems; ii++) {
1204         XtFree((char *)dragData->data.buffers[ii].bp);
1205     }
1206
1207 }
1208
1209 // getDragIcon
1210 //
1211 // Use the mailbox pixmap to create a drag icon
1212 //
1213 Widget
1214 RoamMenuWindow::getDragIcon(
1215         Widget          widget)
1216 {
1217     if (_mbox_image && _mbox_mask) {
1218         return DtDndCreateSourceIcon(widget, _mbox_image, _mbox_mask);
1219     } else {
1220         return NULL;
1221     }
1222 }
1223
1224 // msgListDragStart
1225 //
1226 // Translation start a drag from the msg list
1227 //
1228 XtActionProc
1229 RoamMenuWindow::msgListDragStart(
1230         Widget          widget,
1231         XEvent          *event,
1232         String          * /* params */,
1233         Cardinal        * /* numParams */)
1234 {
1235     static XtCallbackRec convertCBRec[] = { 
1236         {&RoamMenuWindow::msgListConvertCallback, NULL},{NULL, NULL} };
1237     static XtCallbackRec dragFinishCBRec[] = {
1238         {&RoamMenuWindow::msgListDragFinishCallback, NULL}, {NULL, NULL} };
1239     RoamMenuWindow      *rmw = NULL;
1240     unsigned char       operations;
1241     Widget              drag_icon;
1242     DtMailEnv           mail_error;
1243
1244     DebugPrintf(3, "In RoamMenuWindow::msgListProcessDrag\n");
1245
1246     mail_error.clear();
1247
1248     XtVaGetValues(widget, XmNuserData, &rmw, NULL);
1249
1250     if (rmw == NULL)
1251         return NULL;
1252
1253     drag_icon = rmw->getDragIcon(widget);
1254     //drag_icon = NULL;
1255
1256     rmw->msgListDropDisable();
1257
1258     // Choose the drag operations based on the writeability of the mailbox
1259
1260     if (rmw->mailbox()->mailBoxWritable(mail_error) == DTM_TRUE) {
1261         // RW Folder.  Permit Copy and Move.
1262         operations = (unsigned char)(XmDROP_COPY | XmDROP_MOVE);
1263     } else {
1264         // RO Folder.  Permit only Copy drags.
1265         operations = (unsigned char)XmDROP_COPY;
1266     }
1267
1268     // Start the drag
1269
1270     convertCBRec[0].closure = (XtPointer) rmw;
1271     dragFinishCBRec[0].closure = (XtPointer) rmw;
1272
1273     if (DtDndVaDragStart(widget, event, DtDND_BUFFER_TRANSFER, 1,
1274                         operations, convertCBRec, dragFinishCBRec,
1275                         DtNsourceIcon, drag_icon,
1276                         NULL) == NULL) {
1277         DebugPrintf(3, "DragStart returned NULL.\n");
1278     }
1279
1280     return NULL;
1281 }
1282
1283 /* ARGSUSED */
1284 Bool
1285 RoamMenuWindow::msgListLookForButton (
1286         Display *,
1287         XEvent * event,
1288         XPointer arg)
1289 {
1290
1291 #define DAMPING 5
1292 #define ABS_DELTA(x1, x2) (x1 < x2 ? x2 - x1 : x1 - x2)
1293
1294     if( event->type == MotionNotify)  {
1295         XEvent * press = (XEvent *) arg;
1296
1297         if (ABS_DELTA(press->xbutton.x_root, event->xmotion.x_root) > DAMPING ||
1298             ABS_DELTA(press->xbutton.y_root, event->xmotion.y_root) > DAMPING)
1299             return(True);
1300     }
1301     else if (event->type == ButtonRelease)
1302         return(True);
1303     return(False);
1304 }
1305
1306 // msgListProcessPress
1307 //
1308 // Translation implementing Motif 1.2.5 ProcessPress function
1309 //
1310
1311 #define SELECTION_ACTION        0
1312 #define TRANSFER_ACTION         1
1313
1314 void
1315 RoamMenuWindow::msgListProcessPress(
1316         Widget          w,
1317         XEvent          *event,
1318         String          *params,
1319         Cardinal        *num_params)
1320 {
1321    int i, action, cur_item;
1322    int *selected_positions, nselected_positions;
1323
1324    DebugPrintf(3, "In RoamMenuWindow::msgListProcessPress\n");
1325
1326    //  This action happens when Button1 is pressed and the Selection
1327    //  and Transfer are integrated on Button1.  It is passed two
1328    //  parameters: the action to call when the event is a selection,
1329    //  and the action to call when the event is a transfer.
1330
1331     if (*num_params != 2 || !XmIsList(w))
1332       return;
1333
1334     action = SELECTION_ACTION;
1335     cur_item = XmListYToPos(w, event->xbutton.y);
1336
1337     if (cur_item > 0)
1338     {
1339         XtVaGetValues(w,
1340                 XmNselectedPositions, &selected_positions,
1341                 XmNselectedPositionCount, &nselected_positions,
1342                 NULL);
1343
1344         for (i=0; i<nselected_positions; i++)
1345         {
1346             if (cur_item == selected_positions[i])
1347             {
1348                 // The determination of whether this is a transfer drag
1349                 // cannot be made until a Motion event comes in.  It is
1350                 // not a drag as soon as a ButtonUp event happens.
1351                 XEvent new_event;
1352                 
1353                 XPeekIfEvent(
1354                         XtDisplay(w),
1355                         &new_event,
1356                         &RoamMenuWindow::msgListLookForButton,
1357                         (XPointer) event);
1358                 switch (new_event.type)
1359                 {
1360                     case MotionNotify:
1361                        action = TRANSFER_ACTION;
1362                        break;
1363                     case ButtonRelease:
1364                        action = SELECTION_ACTION;
1365                        break;
1366                 }
1367                 break;
1368             }
1369         }
1370     }
1371
1372     XtCallActionProc(w, params[action], event, params, *num_params);
1373 }
1374
1375 // msgListDragSetup
1376 //
1377 // Override default list translations to start our own drags
1378 //
1379 void
1380 RoamMenuWindow::msgListDragSetup()
1381 {
1382     Widget msgList = _list->get_scrolling_list();
1383     static char translations[] = "\
1384                 ~c ~s ~m ~a <Btn1Down>:\
1385                     dt-process-press(ListBeginSelect,MsgListDragStart)\n\
1386                 c ~s ~m ~a <Btn1Down>:\
1387                     dt-process-press(ListBeginToggle,MsgListDragStart)";
1388     static char btn2_translations[] = "\
1389                 ~c ~s ~m ~a <Btn2Down>:\
1390                     dt-process-press(ListBeginSelect,MsgListDragStart)\n\
1391                 c ~s ~m ~a <Btn2Down>:\
1392                     dt-process-press(ListBeginToggle,MsgListDragStart)\n\
1393                 <Btn2Motion>:ListButtonMotion()\n\
1394                 ~c ~s ~m ~a <Btn2Up>:ListEndSelect()\n\
1395                 c ~s ~m ~a <Btn2Up>:ListEndToggle()";
1396     int         btn1_transfer = 0;
1397     XtTranslations      new_translations;
1398     static XtActionsRec actionTable[] = {
1399         {"MsgListDragStart", 
1400         (XtActionProc) &RoamMenuWindow::msgListDragStart},
1401         {"dt-process-press", 
1402         (XtActionProc) &RoamMenuWindow::msgListProcessPress}
1403     };
1404
1405     DebugPrintf(3, "In RoamMenuWindow::msgListDragSetup\n");
1406
1407     XtAppAddActions(
1408                 theRoamApp.appContext(),
1409                 actionTable,
1410                 sizeof(actionTable)/sizeof(actionTable[0]));
1411     new_translations = XtParseTranslationTable(translations);
1412     XtOverrideTranslations(msgList, new_translations);
1413
1414     XtVaGetValues(
1415         (Widget)XmGetXmDisplay(XtDisplayOfObject(msgList)),
1416         "enableBtn1Transfer", &btn1_transfer,
1417         NULL);
1418     
1419     if (btn1_transfer != True) {
1420         new_translations = XtParseTranslationTable(btn2_translations);
1421         XtOverrideTranslations(msgList, new_translations);
1422     }
1423 }
1424
1425 void
1426 RoamMenuWindow::open_and_load(
1427     DtMailEnv &error,
1428     DtMailBoolean create,
1429     DtMailBoolean lock)
1430 {
1431     _openContainerCmd->set_create_lock_flags(create, lock);
1432     _openContainerCmd->execute();
1433
1434     // if it required conversion, let conversion handle the error
1435     // (its a callback routine and we have "lost control" of what
1436     // it returns anyway.)
1437     // 
1438     // if it did not require conversion, then open() should have succeeded.
1439     // If it did succeed, then its _mailbox should be set by now.
1440     // If its not set, then either open() failed somewhere or it was
1441     // cancelled by the user.  We now have an error condition.
1442     if ((!_required_conversion) && (_mailbox == NULL))
1443     {
1444         error.setError(DTME_NoMailBox);
1445         return;
1446     }
1447
1448     // If it required conversion, then let the conversion process handle
1449     // errors if any occur.
1450     // Reset the DtMailEnv for this method.
1451     if (_required_conversion) error.clear();
1452
1453     // If it required conversion, and conversion succeeded, then the
1454     // mailbox was also loaded and _is_loaded gets set to TRUE.
1455     // If it required no conversion, then it implies that we already
1456     // have a container in hand and we just load it (implicitly
1457     // setting _is_loaded to TRUE)
1458     if ((!_required_conversion) && (_is_loaded == FALSE))
1459     {
1460         this->load_mailbox(error);
1461         _is_loaded = TRUE;
1462     }
1463 }
1464
1465
1466 // Ideally, open() should set the error if the user cancels the open.  
1467 // And we should error after open() returns at the caller's end...
1468
1469 void
1470 RoamMenuWindow::open(
1471     DtMailEnv & error, 
1472     DtMailBoolean create_flag, 
1473     DtMailBoolean lock_flag
1474 )
1475 {
1476     FORCE_SEGV_DECL(char, tmp);
1477     Dimension win_x, win_y, win_wid, win_ht, win_bwid;
1478     MailSession *ses = theRoamApp.session();
1479     int answer = 0;
1480     char *helpId;
1481
1482     char *buf = new char[2*MAXPATHLEN];
1483
1484     _openContainerCmd->set_create_lock_flags(create_flag, lock_flag);
1485
1486     // Obtain the current dimensions of the RMW
1487     XtVaGetValues(_main,
1488                   XmNx, &win_x,
1489                   XmNy, &win_y,
1490                   XmNwidth, &win_wid,
1491                   XmNheight, &win_ht,
1492                   XmNborderWidth, &win_bwid,
1493                   NULL);
1494     _x = win_x;
1495     _y = win_y;
1496     _width = win_wid;
1497     _height = win_ht;
1498     _border_width = win_bwid;
1499
1500     // Check to see if the mbox is already open.  If it is, we will
1501     // simply make sure it's displayed in the current workspace.
1502     if (ses->isMboxOpen(_mailbox_fullpath))
1503     {
1504         RoamMenuWindow *rmw = NULL;
1505         rmw = ses->getRMW(_mailbox_fullpath);
1506         if (NULL != rmw)
1507         {
1508             ses->activateRMW(rmw);
1509             rmw->displayInCurrentWorkspace();
1510         }
1511         return;
1512     }
1513
1514     // Try to open this folder, but don't take the lock and and don't create it.
1515     _mailbox = ses->open(error, _mailbox_fullpath, 
1516                          &RoamMenuWindow::syncViewAndStoreCallback,
1517                          this, create_flag, lock_flag);
1518     if (error.isSet())
1519     {
1520         if((DTMailError_t) error == DTME_OutOfSpace )
1521         {
1522               ShowErrMsg((char *)error.getClient(),FALSE,(void*)this );
1523               error.setClient(NULL);
1524               delete [] buf;
1525               return;
1526         }
1527         
1528         // Did we ask for a non-existent file?
1529         if ((DTMailError_t)error == DTME_NoSuchFile)
1530         {
1531             // if (create_flag == DTM_TRUE)
1532             if (create_flag == DTM_FALSE)
1533             {
1534                 sprintf(buf,
1535                         GETMSG(DT_catd, 
1536                                 3, 3, 
1537                                 "The mailbox %s does not exist.\nCreate a mailbox with this name?"),
1538                         _mailbox_fullpath);
1539                 _genDialog->setToQuestionDialog(GETMSG(DT_catd, 
1540                                                         3, 4, "Mailer"),
1541                                              buf);
1542                 helpId = DTMAILHELPERROR;
1543                 answer = _genDialog->post_and_return(GETMSG(DT_catd, 
1544                                                              3, 5, 
1545                                                              "OK"), 
1546                                                      GETMSG(DT_catd,
1547                                                              1, 5,
1548                                                              "Cancel"),
1549                                                      helpId);
1550
1551                 if (answer == 1) open(error, DTM_TRUE, lock_flag);
1552                 if (answer == 2) {
1553                     delete [] buf;
1554                     return;
1555                 }
1556             }
1557             else {
1558                 // A special case should be taken care
1559                 // The create_flag is TRUE but still can not be created
1560                 //      This is because the path is something like
1561                 //      /valid_path/not_such_dir/file_name.
1562                 //     The full file path is not valid so that we need flag
1563                 //     an error
1564                 sprintf(buf,
1565                         GETMSG(DT_catd,
1566                                 3, 44,
1567                                 "Unable to create %s."),
1568                         _mailbox_fullpath);
1569                 _genDialog->setToQuestionDialog(GETMSG(DT_catd,
1570                                                         3, 4, "Mailer"),
1571                                              buf);
1572                 helpId =  DTMAILHELPNOCREATE;
1573                 answer = _genDialog->post_and_return(GETMSG(DT_catd,
1574                                                              3, 5,
1575                                                              "OK"),
1576                                                      helpId);
1577                delete [] buf;
1578                return;
1579             }
1580         }
1581         else if (((DTMailError_t)error == DTME_OtherOwnsWrite) ||
1582                  ((DTMailError_t)error == DTME_AlreadyLocked))
1583         {
1584             // See if they want to take the lock.
1585 //          sprintf(buf, 
1586 //                  GETMSG(DT_catd, 3, 6, "The mailbox %s is locked.\n\
1587 // You can manually unlock the mailbox and try again\n\
1588 // or contact your System Administrator."),
1589 //                 _mailbox_fullpath);
1590
1591 //          _genDialog->setToErrorDialog(
1592 //                              GETMSG(DT_catd, 3, 7, "Mailer"),
1593 //                              buf);
1594 //          helpId = DTMAILHELPTAKELOCK;
1595 //          _genDialog->post_and_return(
1596 //                              GETMSG(DT_catd, 3, 8, "OK"),
1597 //                              helpId);
1598
1599 //          error.setError(DTME_GetLockRefused);
1600             // The above else-if code doesn't make sense.  If ses->open() failed
1601             // because the folder was already locked or not writable then 
1602             // posting the specified error dialog and setting the error to GetLockRefused
1603             // is meaningless.  Especially since the calling function 
1604             // OpenContainerCmd::doit() doesn't even check the error we 
1605             // return.  Lets post a meaningful error dialog and return.
1606             postErrorDialog(error);
1607             delete [] buf;
1608             return;
1609         }
1610         else if ((DTMailError_t)error == DTME_BadRunGroup)
1611         {
1612
1613             sprintf(buf, "%s", GETMSG(DT_catd, 2, 4,
1614                    "Mailer has not been properly installed,\n\
1615 and cannot run because the execution group\n\
1616 is incorrectly set."));
1617
1618             _genDialog->setToQuestionDialog(
1619                                 GETMSG(DT_catd, 1, 6, "Mailer"),
1620                                 buf);
1621             
1622             // No choice at this state other than to OK.
1623
1624             helpId = DTMAILHELPBADGROUPID;
1625             answer = _genDialog->post_and_return(
1626                                 GETMSG(DT_catd, 3, 9, "OK"),
1627                                 helpId);
1628             delete [] buf;
1629             return;
1630
1631         }
1632         else if ((DTMailError_t)error == DTME_NoPermission)
1633         {
1634             /* NL_COMMENT
1635              * The %s is the name of the mailbox the user doesn't have
1636              * permission to view.
1637              */
1638             sprintf(buf, GETMSG(DT_catd, 2, 5,
1639                    "You do not have permission to view %s"), _mailbox_fullpath);
1640
1641             _genDialog->setToQuestionDialog(
1642                                 GETMSG(DT_catd, 1, 7, "Mailer"),
1643                                 buf);
1644             
1645             // No choice at this state other than to OK.
1646
1647             helpId = DTMAILHELPNOVIEW;
1648             answer = _genDialog->post_and_return(
1649                                 GETMSG(DT_catd, 3, 10, "OK"),
1650                                 helpId);
1651             delete [] buf;
1652             return;
1653         }
1654         else if ((DTMailError_t)error == DTME_IsDirectory)
1655         {
1656             sprintf(buf, GETMSG(DT_catd, 2, 6,
1657                     "The mailbox %s is a directory and can not be opened."),
1658                     _mailbox_fullpath);
1659
1660             _genDialog->setToQuestionDialog(GETMSG(DT_catd, 1, 8, "Mailer"),
1661                                             buf);
1662
1663             helpId = DTMAILHELPDIRECTORYONLY;
1664             answer = _genDialog->post_and_return(GETMSG(DT_catd, 3, 11, "OK"),
1665                                                  helpId);
1666             delete [] buf;
1667             return;
1668         }
1669         else if ((DTMailError_t)error == DTME_AlreadyOpened)
1670         {
1671            sprintf(buf, GETMSG(DT_catd,20,1,
1672                    "The mailbox %s is already open."), _mailbox_fullpath);
1673  
1674            _genDialog->setToQuestionDialog(GETMSG(DT_catd, 1, 8, "Mailer"),
1675                                            buf);
1676  
1677            // there is no help message for this error
1678            // open a defect and put helpId later
1679            helpId = NULL;
1680            answer = _genDialog->post_and_return(GETMSG(DT_catd, 3, 11, "OK"),
1681                                                 helpId);
1682            delete [] buf;
1683            return;
1684         }
1685         else
1686         {
1687             // This is a real error. Punt!
1688             this->postErrorDialog(error);
1689         }
1690     }
1691
1692     if(_mailbox)
1693     {
1694         if (_mailbox->mailBoxWritable(error) == DTM_TRUE)
1695           msgListDropRegister();
1696         _mailbox->registerErrMsgFunc(ShowErrMsg,this);
1697         if (isIconified())
1698           _mailbox->hideAccessEvents(DTM_TRUE);
1699         else
1700           _mailbox->hideAccessEvents(DTM_FALSE);
1701     }
1702     delete [] buf;
1703     return;
1704 }
1705
1706 void RoamMenuWindow::createMenuPanes()
1707 {
1708     this->createContainerList();
1709
1710     this->construct_file_menu();
1711
1712     this->construct_message_menu();
1713
1714     this->construct_edit_menu();
1715
1716     this->construct_attachment_menu();
1717
1718     this->construct_view_menu();
1719
1720     this->construct_compose_menu();
1721
1722     this->construct_move_menu();
1723
1724     this->construct_help_menu();
1725
1726     this->construct_message_popup();
1727
1728     this->construct_text_popup();
1729
1730     this->construct_attachment_popup();
1731
1732     this->syncCachedContainerList();
1733
1734 }
1735
1736 void
1737 RoamMenuWindow::resetCacheList(int new_size)
1738 {
1739     // Remove the extra items in the list
1740     for (int i = _cached_containerlist->length(); i > new_size; i--) {
1741
1742         _cached_containerlist->remove(i-1);
1743         _open_container_containerlist_cached->remove(i-1);
1744         _copyto_containerlist_cached->remove(i-1);
1745         _move_containerlist_cached->remove(i-1);
1746
1747         _menuBar->removeCommand(_opencontainerMenu, _first_cached_item+i-1);
1748         _menuBar->removeCommand(_copytoMenu, _first_cached_item+i-1);
1749         _menuBar->removeCommand(_moveMenu, _first_cached_item+i-1);
1750         _menuBar->removeCommand(_msgsPopupMoveMenu, _first_cached_item+i-1);
1751     }
1752 }
1753
1754 void
1755 RoamMenuWindow::propsChanged(void)
1756 {
1757     MailSession         *ses = theRoamApp.session();
1758     DtMail::Session     *d_session = ses->session();
1759     DtMail::MailRc      *mailrc = get_mail_rc();
1760     DtMailEnv            error;
1761     const char          *value = NULL;
1762     char                *inbox_path = NULL;
1763     DtMailObjectSpace    space;
1764     Boolean              should_be_inbox;
1765
1766     if (! _is_loaded) return;
1767     enableWorkAreaResize();
1768
1769     d_session->queryImpl(
1770                         error,
1771                         d_session->getDefaultImpl(error),
1772                         DtMailCapabilityInboxName,
1773                         &space,
1774                         &inbox_path);
1775     should_be_inbox = (inbox_path && 0 == strcmp(inbox_path, mailboxName()));
1776
1777     RoamMenuWindow      *rmw = NULL;
1778     char                *password = NULL;
1779     password = MailRetrievalOptions::getPassword(DTMAS_INBOX);
1780
1781     if (_inbox != should_be_inbox)
1782     {
1783
1784         if (_inbox)
1785         {
1786             char buf[2048];
1787             int answer;
1788
1789             //
1790             // Remove inbox attributes
1791             //
1792             displayInCurrentWorkspace();
1793             sprintf(
1794                 buf, "%s",
1795                 GETMSG(DT_catd, 99, 99,"The INBOX path has changed.\nReopen?"));
1796             _genDialog->setToQuestionDialog(
1797                                         GETMSG(DT_catd, 3, 22, "Mailer"),
1798                                         buf);
1799             answer = _genDialog->post_and_return(
1800                                         GETMSG(DT_catd, 3, 29, "OK"),
1801                                         GETMSG(DT_catd, 3, 19, "Cancel"),
1802                                         DTMAILHELPERROR);
1803
1804             rmw = ses->getRMW(inbox_path);
1805             if (rmw)
1806             {
1807                 rmw->_inbox = TRUE;
1808                 rmw->_mailbox->createMailRetrievalAgent(password);
1809                 rmw->_open_container_inbox->deactivate();
1810                 rmw->_file_open_inbox->deactivate();
1811             }
1812
1813             if (answer == 1)
1814             {
1815                 if (NULL != rmw)
1816                   rmw->displayInCurrentWorkspace();
1817                 else
1818                   view_mail_file(inbox_path, DTM_FALSE);
1819             }
1820
1821             _inbox = FALSE;
1822             _mailbox->deleteMailRetrievalAgent();
1823             _open_container_inbox->activate();
1824             _file_open_inbox->activate();
1825             
1826         }
1827         else
1828         {
1829             _inbox = TRUE;
1830             _mailbox->createMailRetrievalAgent(password);
1831             _open_container_inbox->deactivate();
1832             _file_open_inbox->deactivate();
1833         }
1834     }
1835     else
1836     {
1837         if (_inbox) _mailbox->createMailRetrievalAgent(password);
1838         else
1839         {
1840             rmw = ses->getRMW(inbox_path);
1841             if (rmw) rmw->_mailbox->createMailRetrievalAgent(password);
1842         }
1843     }
1844
1845     if (password) free(password);
1846
1847
1848     // See if the header size has changed.
1849     //
1850     mailrc->getValue(error, "headerlines", &value);
1851     if (error.isSet())
1852     { 
1853         value = strdup("15");
1854         error.clear();
1855     }
1856
1857     int header_lines = (int) strtol(value, NULL, 10);
1858     if (header_lines != _list->visibleItems())
1859         _list->visibleItems(header_lines);
1860
1861     free((void*) value);
1862
1863     _list->checkDisplayProp();
1864     _my_editor->textEditor()->update_display_from_props();
1865
1866     value = NULL;
1867     mailrc->getValue(error, "dontdisplaycachedfiles", &value);
1868     if (error.isNotSet() && value != NULL)
1869     {
1870         if (_display_cached_list)
1871           // They just turned off the Display Up To prop so
1872           //reset the cache list to zero length.
1873           resetCacheList(0);
1874
1875         _max_cached_list_size = 0;
1876         _display_cached_list = FALSE;
1877         free((void*) value);
1878     }
1879     else
1880     {
1881         error.clear();
1882         value = NULL;
1883         mailrc->getValue(error, "cachedfilemenusize", &value);
1884         if (error.isNotSet() && value != NULL && *value != '\0')
1885         {
1886             int new_size;
1887
1888             new_size = (int) strtol(value, NULL, 10);
1889             if (new_size != _max_cached_list_size && new_size >=0)
1890             {
1891                 // They just changed the display number so chop the 
1892                 // list if it is bigger than the new size just set 
1893                 if (new_size < _max_cached_list_size)
1894                   resetCacheList(new_size);
1895
1896                 _max_cached_list_size = new_size;
1897             }
1898         }
1899         if (NULL != value)
1900           free((void*) value);
1901     }
1902
1903     error.clear(); 
1904     value = NULL;
1905     mailrc->getValue(error, "filemenu2", &value);
1906     if  ( (value == NULL && _filemenu2 != NULL) ||
1907           (value != NULL && _filemenu2 == NULL) ||
1908           (value != NULL && _filemenu2 != NULL &&
1909            strcmp(value, _filemenu2) != 0) )
1910     {
1911         // Recreate the containter list
1912         this->createContainerList();
1913
1914         // Recreate the File menu
1915         this->construct_file_menu();    
1916
1917         // Recreate the Message menu
1918         this->construct_message_menu(); 
1919
1920         // Recreate the Move menu...
1921         this->construct_move_menu();    
1922
1923         // Recreate the Message popup menu
1924         this->construct_message_popup();        
1925     }
1926     if (NULL != value)
1927       free((void*) value);
1928
1929     value = NULL;
1930     mailrc->getValue(error, "retrieveinterval", &value);
1931     if (error.isNotSet() && value && *value != '\0')
1932     {
1933         long ping = (time_t) strtol(value, NULL, 10);
1934         if (ping <= 0)
1935           _checkformail_when_mapped = FALSE;
1936         else
1937           _checkformail_when_mapped = TRUE;
1938     }
1939     error.clear();
1940     if (NULL != value) free((void*) value);
1941
1942     disableWorkAreaResize();
1943 }
1944
1945 void RoamMenuWindow::registerDialog( ViewMsgDialog *dialog )
1946 {
1947     int i;
1948     ViewMsgDialog **newList = (ViewMsgDialog **)-1;
1949   
1950     // Allocate a new list large enough to hold the new
1951     // object, and copy the contents of the current list 
1952     // to the new list
1953   
1954     newList = new ViewMsgDialog*[_numDialogs + 1];
1955   
1956     for ( i = 0; i < _numDialogs; i++ )
1957         newList[i] = _dialogs[i];
1958   
1959     // Install the new list and add the window to the list
1960   
1961     if ( _numDialogs > 0 )
1962         delete []_dialogs;
1963     _dialogs =  newList;
1964     _dialogs[_numDialogs] = dialog;
1965     _numDialogs++;
1966
1967   }
1968 void RoamMenuWindow::unregisterDialog ( ViewMsgDialog *dialog )
1969 {
1970   int i, index;
1971   ViewMsgDialog **newList = (ViewMsgDialog **)-1;
1972   
1973   // Allocate a new, smaller list
1974   
1975   newList = new ViewMsgDialog *[_numDialogs - 1];
1976   
1977   // Copy all objects, except the one to be 
1978   // removed, to the new list
1979   
1980   index = 0;
1981   for ( i = 0; i < _numDialogs; i++ )
1982     if ( _dialogs[i] != dialog )
1983     newList[index++] = _dialogs[i];
1984   
1985   // Install the new list
1986   
1987   delete []_dialogs;
1988   _dialogs =  newList;
1989   
1990   _numDialogs--;
1991 }
1992
1993 void
1994 RoamMenuWindow::forwardFilename( char *file )
1995 {
1996   _forward_filename = (char *)realloc(_forward_filename, strlen(file)+1);
1997   strcpy( _forward_filename, file );
1998 }
1999
2000 char *
2001 RoamMenuWindow::forwardFilename()
2002 {
2003   return _forward_filename;
2004 }
2005
2006
2007
2008 // If it is a configure notify, we are interested in it.
2009 // We need to then capture its new position.
2010 // And if the RMW has not been loaded, we need to load it.
2011
2012 void
2013 RoamMenuWindow::structurenotify(
2014     Widget,             // w
2015     XtPointer clientData,
2016     XEvent *event,
2017     Boolean * )         // continue_to_dispatch
2018 {
2019    RoamMenuWindow *rmw=(RoamMenuWindow *) clientData;
2020
2021    if (event->type == ConfigureNotify)
2022    {
2023        rmw->configurenotify(
2024                         event->xconfigurerequest.x,
2025                         event->xconfigurerequest.y,
2026                         event->xconfigurerequest.width,
2027                         event->xconfigurerequest.height,
2028                         event->xconfigurerequest.border_width);
2029    }
2030    else if ((event->type == MapNotify) || ( event->type == UnmapNotify))
2031    {
2032        if (rmw->_mailbox)
2033          if (event->type == UnmapNotify)
2034          {
2035              rmw->_mailbox->save();
2036              rmw->_mailbox->hideAccessEvents(DTM_TRUE);
2037          }
2038          else
2039          {
2040              rmw->_mailbox->hideAccessEvents(DTM_FALSE);
2041              if (FALSE==rmw->_inbox || TRUE==rmw->_checkformail_when_mapped)
2042              {
2043                  DtMailEnv        error;
2044                  DtMail::Session *m_session = theRoamApp.session()->session(); 
2045                  DtMail::MailRc  *mailrc = m_session->mailRc(error);
2046                  const char      *value = NULL;
2047
2048                  mailrc->getValue(error, "retrievemailonmapnotify", &value);
2049                  if (error.isNotSet()) rmw->checkForMail(error);
2050              }
2051          }
2052
2053        rmw->mapnotify();
2054    }       
2055 }
2056
2057 // Capture its position coordinates.
2058
2059 void 
2060 RoamMenuWindow::configurenotify( 
2061     unsigned int win_x, unsigned int win_y,
2062     unsigned int win_wid, unsigned int win_ht,
2063     unsigned int win_bwid
2064 )
2065 {
2066
2067     _x = win_x;
2068     _y = win_y;
2069     _width = win_wid;
2070     _height = win_ht;
2071     _border_width = win_bwid;
2072
2073 }
2074
2075 // If it is not already loaded, then load it (it might involve
2076 // conversion, etc.; all handled by open_and_load())
2077 // If its been loaded already, then mapnotify gets called when
2078 // the state changes from iconic to open (i.e., the user double-clicks
2079 // on an RMW icon).  If we want to load a folder at that time, this
2080 // is the place to do it.
2081
2082
2083 void
2084 RoamMenuWindow::mapnotify()
2085 {
2086     // If its not been loaded, then open and load it.
2087     if (!_is_loaded)
2088     {
2089         DtMailEnv mail_error;
2090         
2091         mail_error.clear();
2092         
2093         theRoamApp.busyAllWindows();
2094         this->open_and_load(
2095                         mail_error,
2096                         (DtMailBoolean) _create_mailbox_file,
2097                         DTM_TRUE);
2098         theRoamApp.unbusyAllWindows();
2099         
2100         // If there's been an error then we quit the container.
2101         if (mail_error.isSet())
2102         {
2103             // Need to remove the base Widgets destroy callback since
2104             // we end up destroying it twice otherwise...
2105             XtRemoveAllCallbacks(this->baseWidget(), XmNdestroyCallback);
2106             this->quit(TRUE);
2107         }
2108         else {
2109             // We need to disable the editable menu options if the mail
2110             // box is readonly.
2111             //
2112             if (_mailbox->mailBoxWritable(mail_error) == DTM_FALSE)
2113             {
2114                 _msg_delete->deactivate();
2115                 _msg_undelete_last->deactivate();
2116                 _msg_undelete_from_list->deactivate();
2117                 _delete_button->deactivate();
2118                 _file_destroy_deleted_msgs->deactivate();
2119                 if (NULL != _move_cascade)
2120                   XtSetSensitive(_move_cascade, FALSE);
2121                 if (NULL != _msgsPopupMoveMenu)
2122                   XtSetSensitive(_msgsPopupMoveMenu, FALSE);
2123                 
2124                 char * readonly = GETMSG(DT_catd, 20, 3, "Read Only");
2125                 setTitle(readonly);
2126             }
2127
2128             if (_list->get_num_messages())
2129               setIconName(NormalIcon);
2130             else
2131               setIconName(EmptyIcon);
2132         }
2133     }
2134     else
2135     {
2136         // If the mailbox has messages, set to normal icon
2137         if (_list->get_num_messages() > 0)
2138           setIconName(NormalIcon);
2139         else
2140           setIconName(EmptyIcon);
2141     }
2142 }
2143
2144 void
2145 RoamMenuWindow::last_sorted_by(SortBy type)
2146 {
2147     char                 id[16];
2148     char                *buffer = NULL;
2149     DtMailEnv            error;
2150     DtMail::Session     *m_session = theRoamApp.session()->session(); 
2151     DtMail::MailRc      *mailrc = m_session->mailRc(error);
2152
2153     _last_sorted_by = type;
2154
2155     ((SortCmd*)_view_sortTD)->setButtonState(FALSE, FALSE);
2156     ((SortCmd*)_view_sortSender)->setButtonState(FALSE, FALSE);
2157     ((SortCmd*)_view_sortSubject)->setButtonState(FALSE, FALSE);
2158     ((SortCmd*)_view_sortSize)->setButtonState(FALSE, FALSE);
2159     ((SortCmd*)_view_sortStatus)->setButtonState(FALSE, FALSE);
2160
2161     XtVaSetValues(_sender_lbl, XmNlabelString, _sender_xms, NULL);
2162     XtVaSetValues(_subject_lbl, XmNlabelString, _subject_xms, NULL);
2163     XtVaSetValues(_date_lbl, XmNlabelString, _date_xms, NULL);
2164     XtVaSetValues(_size_lbl, XmNlabelString, _size_xms, NULL);
2165
2166     buffer = XtMalloc(BUFSIZ);
2167     if (buffer)
2168     {
2169         if (_inbox)
2170         {
2171             RMW_CONCAT_MAILRC_KEY(buffer, DTMAS_INBOX, "sortby");
2172         }
2173         else
2174         {
2175             RMW_CONCAT_MAILRC_KEY(buffer, mailboxName(), "sortby");
2176         }
2177     }
2178     
2179     switch (_last_sorted_by)
2180     {
2181         case SortTimeDate:
2182             XtVaSetValues(_date_lbl, XmNlabelString, _date_key_xms, NULL);
2183             ((SortCmd*)_view_sortTD)->setButtonState(TRUE,FALSE);
2184             if (buffer) mailrc->removeValue(error, buffer);
2185             break;
2186         case SortSender:
2187             XtVaSetValues(_sender_lbl, XmNlabelString, _sender_key_xms, NULL);
2188             ((SortCmd*)_view_sortSender)->setButtonState(TRUE,FALSE);
2189             sprintf(id, "%d", SortSender);
2190             if (buffer) mailrc->setValue(error, buffer, id);
2191             break;
2192         case SortSubject:
2193             XtVaSetValues(_subject_lbl, XmNlabelString, _subject_key_xms, NULL);
2194             ((SortCmd*)_view_sortSubject)->setButtonState(TRUE,FALSE);
2195             sprintf(id, "%d", SortSubject);
2196             if (buffer) mailrc->setValue(error, buffer, id);
2197             break;
2198         case SortSize:  
2199             XtVaSetValues(_size_lbl, XmNlabelString, _size_key_xms, NULL);
2200             ((SortCmd*)_view_sortSize)->setButtonState(TRUE,FALSE);
2201             sprintf(id, "%d", SortSize);
2202             if (buffer) mailrc->setValue(error, buffer, id);
2203             break;
2204         case SortStatus:
2205             ((SortCmd*)_view_sortStatus)->setButtonState(TRUE,FALSE);
2206             sprintf(id, "%d", SortStatus);
2207             if (buffer) mailrc->setValue(error, buffer, id);
2208             break;
2209         default:
2210             XtVaSetValues(_date_lbl, XmNlabelString, _date_key_xms, NULL);
2211             ((SortCmd*)_view_sortTD)->setButtonState(TRUE,FALSE);
2212             if (buffer) mailrc->removeValue(error, buffer);
2213             break;
2214     }
2215     if (buffer) XtFree(buffer);
2216
2217     //_list->layoutLabels();
2218     mailrc->update(error);
2219 }
2220
2221 void
2222 RoamMenuWindow::message( char *text )
2223 {
2224     int text_size = strlen(text);
2225     char *buf, *str;
2226     XmString labelStr;
2227
2228     if (text_size > 0) {
2229         str = GETMSG(DT_catd, 3, 12, "%s");
2230         buf = new char[strlen(str) + text_size + 1];
2231         sprintf(buf, str, text);
2232         labelStr = XmStringCreateLocalized(buf);
2233         _clear_message_p = TRUE;               
2234     }
2235     else {
2236         buf = new char[2];
2237         sprintf(buf, "%s", "");
2238         labelStr = XmStringCreateLocalized(buf);
2239         _clear_message_p = FALSE;
2240     }
2241     
2242     XtVaSetValues(_message, XmNlabelString, labelStr, NULL);
2243     XmUpdateDisplay(this->baseWidget());
2244
2245     XmStringFree(labelStr); 
2246     delete [] buf;
2247 }
2248
2249 void
2250 RoamMenuWindow::setStatus(const char * msg)
2251 {
2252     message((char *)msg);
2253 }
2254
2255 void
2256 RoamMenuWindow::clearStatus(void)
2257 {
2258     setStatus("");
2259 }
2260
2261 void
2262 RoamMenuWindow::message_summary()
2263 {
2264     this->message_summary(
2265                 list()->selected_item_position(),
2266                 list()->get_num_messages(), 
2267                 list()->get_num_new_messages(),
2268                 list()->get_num_deleted_messages());
2269 }
2270
2271 void
2272 RoamMenuWindow::message_summary(
2273     int sel_pos,
2274     int num_msgs,
2275     int num_new,
2276     int num_deleted
2277 )
2278 {
2279     char *buf, *str; 
2280     XmString labelStr;
2281     int num_live_msgs = num_msgs - num_deleted;  // Undeleted msgs
2282     DtMail::MailRc * mailrc = get_mail_rc();
2283     DtMailEnv error;
2284     const char * value = NULL;
2285
2286     mailrc->getValue(error, "nerdmode", &value);
2287     if (error.isSet()) {
2288         str = GETMSG(DT_catd, 3, 13, "Message %d of %d, %d new, %d deleted"); 
2289     }
2290     else {
2291         str = "Message 0x%x of 0x%x, ignoring 0x%x, 0x%x forgotten";
2292     }
2293     if (NULL != value)
2294       free((void*) value);
2295
2296     buf = new char[strlen(str) + 100];
2297     sprintf(buf, str, sel_pos, num_msgs, num_new, num_deleted);
2298
2299     labelStr = XmStringCreateLocalized(buf);
2300     
2301     XtVaSetValues(_message_summary, XmNlabelString, labelStr, NULL);
2302     XmUpdateDisplay(this->baseWidget());
2303
2304     XmStringFree(labelStr);
2305     delete [] buf;
2306 }    
2307
2308 void
2309 RoamMenuWindow::message_selected(
2310     int msg_num,
2311     int num_msgs,
2312     int num_new,
2313     int num_deleted
2314 )
2315 {
2316     char *buf, *str;
2317     XmString labelStr;
2318
2319         /* NL_COMMENT
2320          * The user will see the following message display as:
2321          * "Message 3 of 10, 2 new, 6 deleted"
2322          * This means ??? -- Explain to translator.
2323          */
2324     str = GETMSG(DT_catd, 3, 14, "Message %d of %d, %d new, %d deleted"); 
2325     buf = new char[strlen(str) + 20];
2326     sprintf(buf, str, msg_num, num_msgs, num_new, num_deleted);
2327     
2328     labelStr = XmStringCreateLocalized(buf);
2329
2330     XtVaSetValues(_message_summary, XmNlabelString, labelStr, NULL);
2331     XmUpdateDisplay(this->baseWidget());
2332
2333     XmStringFree(labelStr);
2334     delete [] buf;
2335 }
2336     
2337
2338 FindDialog *
2339 RoamMenuWindow::get_find_dialog()
2340 {
2341   
2342   if (!_findDialog) {
2343     theRoamApp.busyAllWindows();
2344     // No find dialog.  Create it
2345     _findDialog = new FindDialog(this);
2346     _findDialog->initialize();
2347     theRoamApp.unbusyAllWindows();
2348   }
2349
2350   // Show it
2351   _findDialog->manage();
2352   _findDialog->popup();
2353   return _findDialog;
2354 }
2355
2356 Boolean 
2357 RoamMenuWindow::quitWorkproc(XtPointer client_data)
2358 {
2359     RoamMenuWindow      *rmw = (RoamMenuWindow *) client_data;
2360     MailSession         *ses = theRoamApp.session();
2361     static int called = 0;
2362
2363     if (rmw->_numPendingTasks > 0)
2364     {
2365         rmw->busyCursor();
2366         return FALSE;
2367     }
2368     
2369     if (rmw->_quitWorkprocID != 0)
2370     {
2371         XtRemoveWorkProc(rmw->_quitWorkprocID);
2372         rmw->_quitWorkprocID = 0;
2373     }
2374
2375     rmw->normalCursor();
2376     rmw->_genDialog->unmanage();
2377     rmw->unmanage();
2378
2379     if (rmw->_delete_on_quit)
2380     {
2381         rmw->_list->shutdown();
2382         delete rmw;
2383     }
2384     else
2385       ses->deactivateRMW(rmw);
2386
2387     theRoamApp.checkForShutdown();
2388     return TRUE;
2389 }
2390
2391 int 
2392 RoamMenuWindow::queryExpunge()
2393 {
2394     int answer = 0;
2395     DtMailEnv error;
2396     int i = 0;
2397
2398     if (NULL != _mailbox && _mailbox->mailBoxWritable(error) == DTM_TRUE)
2399     {
2400       theRoamApp.busyAllWindows(GETMSG(DT_catd, 3, 15, "Saving..."));
2401
2402       if (_list->get_num_deleted_messages())
2403       {
2404         // We need to deal with deleted messages, based on what the
2405         // user wants to do. There are two properties that control
2406         // this. They are:
2407         //
2408         // keepdeleted - Keep deleted messages on close.
2409         // quietdelete - Delete without asking.
2410         //
2411         // If the user wants to keep the deleted messages, then we
2412         // can just blow by the second. If not, then we have to
2413         // clear the deleted messages, asking first based on the
2414         // second option.
2415         //
2416         DtMail::MailRc * mailrc = get_mail_rc();
2417         const char * value = NULL;
2418
2419         error.clear();
2420         mailrc->getValue(error, "keepdeleted", &value);
2421         if (error.isSet())
2422         {
2423             if (NULL != value)
2424               free((void*) value);
2425
2426             // The user wants to expunge on close. See if they want
2427             // to be asked first.
2428             //
2429             value = NULL;
2430             error.clear();
2431             mailrc->getValue(error, "quietdelete", &value);
2432             if (error.isSet() && !theRoamApp.quitSilently())
2433             {
2434                 if (isIconified())
2435                   manage();
2436
2437                 /* NL_COMMENT
2438                  * This dialog comes up when the user tries to quit the
2439                  * mailbox and the user is asked if he wants to destroy
2440                  * the messages marked for deletion.
2441                  */
2442                 /* NL_COMMENT
2443                  * Messages 16 and 17 are no longer being used.  They are
2444                  * being replaced by message 86 and 87.
2445                  */
2446                 _genDialog->setToQuestionDialog(
2447 #ifdef undef
2448                     GETMSG(DT_catd, 3, 16, "Mailer"),
2449                     GETMSG(DT_catd, 3, 17, "Destroy the messages you have marked\nfor deletion in this mailbox?"));
2450 #endif // undef
2451                 /* NL_COMMENT
2452                  * This dialog comes up when the user tries to quit the
2453                  * mailbox.  The user is asked if they want to destroy
2454                  * the deleted messages.
2455                  */
2456                     GETMSG(DT_catd, 3, 87, "Mailer - Close"),
2457                     GETMSG(DT_catd, 3, 88, "Destroy the deleted messages and close this mailbox?"));
2458                 char * helpId = DTMAILHELPDESTROYMARKMSG;
2459                 int answer = _genDialog->post_and_return(
2460                                 GETMSG(DT_catd, 3, 89, "Destroy and Close"),
2461                                 GETMSG(DT_catd, 3, 73, "Cancel"),
2462                                 GETMSG(DT_catd, 3, 90, "Retain and Close"),
2463                                 helpId);
2464                 if (answer == 1)
2465                 {
2466                     error.clear();
2467                     _mailbox->expunge(error);
2468                     if ((DTMailError_t) error == DTME_OutOfSpace)
2469                     {
2470                         ShowErrMsg(
2471                                 (char *)error.getClient(),
2472                                 FALSE,
2473                                 (void*)this);
2474                         error.setClient(NULL);
2475                     }
2476
2477                     if (_msg_undelete_from_list->dialog())
2478                       _msg_undelete_from_list->dialog()->expunge();
2479                     _list->expunge();
2480
2481                     if (error.isSet())
2482                       postErrorDialog(error);
2483                 }
2484                 else if (answer == 2)
2485                 {
2486                     // This is a very bad way to code selection of the 
2487                     // cancel button.  If someone changes its position
2488                     // in the dialog, this code will break!
2489                     theRoamApp.unbusyAllWindows();
2490                     return 0;
2491                 }
2492             }
2493             else
2494             {
2495                 // If killed by a signal, don't post a dialog.
2496                 error.clear();
2497                 _mailbox->expunge(error);
2498                 if ((DTMailError_t) error == DTME_OutOfSpace)
2499                 {
2500                    ShowErrMsg((char *)error.getClient(),FALSE,(void*)this );
2501                    error.setClient(NULL);
2502                 }
2503
2504                 if (_msg_undelete_from_list->dialog())
2505                   _msg_undelete_from_list->dialog()->expunge();
2506                 _list->expunge();
2507
2508                 if (error.isSet())
2509                   if (! theRoamApp.quitSilently())
2510                     postErrorDialog(error);
2511             }
2512         }
2513         if (NULL != value)
2514           free((void*) value);
2515       }
2516     }
2517     return 1;
2518 }
2519
2520
2521 void 
2522 RoamMenuWindow::quit(Boolean delete_win)
2523 {
2524     DtMailEnv error;
2525     int i = 0;
2526
2527     if (! queryExpunge())
2528       return;
2529
2530     for (i = 0; i < _numDialogs; i++)
2531       _dialogs[i]->unmanage();
2532
2533     XmUpdateDisplay(baseWidget());
2534
2535     for (i = 0; i < _numDialogs; i++)
2536       _dialogs[i]->quit();
2537
2538     theRoamApp.unbusyAllWindows();
2539
2540     this->_delete_on_quit = delete_win;
2541     if (_numPendingTasks > 0)
2542     {
2543         char    *msg;
2544
2545         busyCursor();
2546         msg = GETMSG(
2547                 DT_catd,
2548                 21, 22, "Close pending:  waiting for task to terminate ...");
2549         setStatus(msg);
2550
2551         if (_quitWorkprocID == 0)
2552           _quitWorkprocID = XtAppAddWorkProc(
2553                                         XtWidgetToApplicationContext(_w),
2554                                         &RoamMenuWindow::quitWorkproc,
2555                                         (XtPointer) this);
2556
2557         unmanage();
2558     }
2559     else
2560       quitWorkproc((XtPointer) this);
2561 }
2562
2563 void 
2564 RoamMenuWindow::panicQuit()
2565 {
2566     if (_mailbox != NULL)
2567         _mailbox->unlock();
2568 }
2569
2570 void 
2571 RoamMenuWindow::quit_silently()
2572 {
2573     DtMailEnv error;
2574     int i = 0;
2575
2576     if (_mailbox->mailBoxWritable(error) == DTM_TRUE) {
2577
2578       theRoamApp.busyAllWindows(GETMSG(DT_catd, 3, 15, "Saving..."));
2579
2580       if (_list->get_num_deleted_messages()) {
2581         // We need to deal with deleted messages, based on what the
2582         // user wants to do. There are two properties that control
2583         // this. They are:
2584         //
2585         // keepdeleted - Keep deleted messages on close.
2586         // quietdelete - Delete without asking.
2587         //
2588         // If the user wants to keep the deleted messages, then we
2589         // can just blow by the second. If not, then we have to
2590         // clear the deleted messages, asking first based on the
2591         // second option.
2592         //
2593         DtMail::MailRc * mailrc = get_mail_rc();
2594         const char * value = NULL;
2595
2596         error.clear();
2597         mailrc->getValue(error, "keepdeleted", &value);
2598         if (error.isSet()) {
2599             error.clear();
2600             _mailbox->expunge(error);
2601             if (error.isSet()) {
2602                 this->postErrorDialog(error);
2603             }
2604         }
2605         if (NULL != value)
2606           free((void*) value);
2607
2608       }
2609     }
2610
2611     for (i = 0; i < _numDialogs; i++) {
2612         _dialogs[i]->unmanage();
2613     }
2614
2615     XmUpdateDisplay(this->baseWidget());
2616
2617     for (i = 0; i < _numDialogs; i++) {
2618         _dialogs[i]->quit();
2619     }
2620
2621     this->_delete_on_quit = FALSE;
2622     if (_numPendingTasks > 0)
2623     {
2624         char    *msg;
2625
2626         busyCursor();
2627         msg = GETMSG(
2628                 DT_catd,
2629                 21, 22, "Close pending:  waiting for task to terminate ...");
2630         setStatus(msg);
2631
2632         if (_quitWorkprocID == 0)
2633           _quitWorkprocID = XtAppAddWorkProc(
2634                                         XtWidgetToApplicationContext(_w),
2635                                         &RoamMenuWindow::quitWorkproc,
2636                                         (XtPointer) this);
2637
2638         unmanage();
2639     }
2640     else
2641       quitWorkproc((XtPointer) this);
2642 }
2643
2644 // Callback to open a new mail container.
2645
2646 void
2647 RoamMenuWindow::file_selection_callback(void *client_data, char *selection)
2648 {
2649     if (NULL == selection || 0 == strlen(selection)) return;
2650
2651     RoamMenuWindow *obj=(RoamMenuWindow *) client_data;
2652     obj->view_mail_file(selection, DTM_FALSE);
2653     XtFree(selection);
2654 }
2655
2656
2657 void RoamMenuWindow::reopen_mail_file()
2658 {
2659     char *filename;
2660
2661     theApplication->disableShutdown();
2662
2663     filename = strdup(this->_mailbox_fullpath);
2664     this->unmanage();
2665     this->quit(TRUE);
2666     view_mail_file(filename, DTM_FALSE);
2667     free(filename);
2668
2669     theApplication->enableShutdown();
2670 }
2671
2672 // Given the name of a container, create a new RoamMenuWindow
2673 // and open the container into it.
2674
2675 void RoamMenuWindow::view_mail_file(char *filename, DtMailBoolean create)
2676 {
2677     DtMailEnv           mail_error;
2678     MailSession         *ses = theRoamApp.session();
2679     DtMail::Session     *d_session = ses->session();
2680     RoamMenuWindow      *roamwin = NULL;
2681     char                *expanded_filename = NULL;
2682     char                *plus_filename = NULL;
2683     char                *relative_filename = NULL;
2684
2685     theRoamApp.busyAllWindows(GETMSG(DT_catd, 3, 20, "Opening mailbox..."));
2686
2687     // If the first character of destname is alphanumeric, we can
2688     // safely assume that it is relative to the root folder directory.
2689     // Prepend a '+' and call 'expandPath' to get the actual path.
2690     if (isalnum(filename[0]))
2691     {
2692         plus_filename = (char *) malloc(strlen(filename)+2);
2693         sprintf(plus_filename, "+%s", filename);
2694         expanded_filename = d_session->expandPath(mail_error, plus_filename);
2695         free(plus_filename);
2696     }
2697     else
2698       expanded_filename = d_session->expandPath(mail_error, filename);
2699
2700     // Check to see if the mbox is already open.  If it is, we will
2701     // simply make sure it's displayed in the current workspace.
2702     if (ses->isMboxOpen(expanded_filename))
2703     {
2704         roamwin = ses->getRMW(expanded_filename);
2705         ses->activateRMW(roamwin);
2706         if (NULL != roamwin) roamwin->displayInCurrentWorkspace();
2707     }
2708     else
2709     {
2710         if (DTM_FALSE == create &&
2711             -1 == SafeAccess(expanded_filename, F_OK) &&
2712             ENOENT == errno)
2713         {
2714             char *buf = new char[2048];
2715             int answer;
2716             DtMailGenDialog *dialog = genDialog();
2717
2718             sprintf(
2719                 buf,
2720                 GETMSG(DT_catd, 3, 3, "The mailbox %s does not exist.\nCreate a mailbox with this name?"),
2721                 filename);
2722             dialog->setToQuestionDialog(GETMSG(DT_catd, 3, 22, "Mailer"), buf);
2723             answer = dialog->post_and_return(DTMAILHELPERROR);
2724             delete [] buf;
2725             if (2 == answer) goto do_unbusy;
2726             create = DTM_TRUE;
2727         }
2728     
2729         roamwin = new RoamMenuWindow(expanded_filename);
2730         roamwin->_create_mailbox_file = DTM_TRUE;
2731         roamwin->initialize();
2732         roamwin->mailboxFullpath(expanded_filename);
2733         roamwin->mailboxName(filename);
2734         roamwin->manage();
2735     }
2736
2737     free(expanded_filename);
2738     relative_filename = d_session->getRelativePath(mail_error, filename);
2739     theRoamApp.globalAddToCachedContainerList(relative_filename);
2740     free(relative_filename);
2741
2742 do_unbusy:
2743     theRoamApp.unbusyAllWindows();
2744 }
2745
2746 void
2747 RoamMenuWindow::move_callback(void *client_data, char *selection)
2748 {
2749     DtMailEnv mail_error;
2750
2751     mail_error.clear();
2752     RoamMenuWindow *obj = (RoamMenuWindow *) client_data;
2753
2754     theRoamApp.busyAllWindows(GETMSG(DT_catd, 3, 15, "Saving..."));
2755     obj->_mailbox->save();
2756     theRoamApp.unbusyAllWindows();
2757
2758     obj->_list->copySelected(mail_error, selection, TRUE, FALSE);
2759     if (mail_error.isSet()) obj->postErrorDialog(mail_error);
2760
2761 }
2762
2763 void
2764 RoamMenuWindow::copy_callback(void *client_data, char *selection)
2765 {
2766     DtMailEnv mail_error;
2767
2768     mail_error.clear();
2769     RoamMenuWindow *obj = (RoamMenuWindow *) client_data;
2770
2771     theRoamApp.busyAllWindows(GETMSG(DT_catd, 3, 15, "Saving..."));
2772     obj->_mailbox->save();
2773     theRoamApp.unbusyAllWindows();
2774
2775     obj->_list->copySelected(mail_error, selection, FALSE, FALSE);
2776     if (mail_error.isSet()) obj->postErrorDialog(mail_error);   
2777 }
2778
2779
2780 void
2781 RoamMenuWindow::create_container_callback(void *client_data, char *selection)
2782 {
2783     RoamMenuWindow *obj = (RoamMenuWindow*) client_data;
2784     obj->create_new_container(selection);
2785     XtFree(selection);
2786 }
2787
2788 void
2789 RoamMenuWindow::create_new_container(char *filename)
2790 {
2791     int answer;
2792
2793     if (SafeAccess(filename, F_OK) == 0)
2794     {
2795         char *buf = new char[2048];
2796         sprintf(
2797                 buf,
2798                 GETMSG(DT_catd, 3, 21, "%s already exists.\nOverwrite?"),
2799                 filename);
2800         _genDialog->setToQuestionDialog(GETMSG(DT_catd, 3, 22, "Mailer"), buf);
2801         answer = _genDialog->post_and_return(DTMAILHELPERROR);
2802         if (answer == 2) {
2803             delete [] buf;
2804             return;
2805         }
2806
2807         if (unlink(filename) < 0)
2808         {
2809             sprintf(buf, 
2810                 GETMSG(DT_catd, 3, 23,
2811                   "Unable to overwrite %s.\nCheck file permissions and retry."),
2812                 filename);
2813
2814             _genDialog->setToErrorDialog(GETMSG(DT_catd, 3, 24, "Mailer"), buf);
2815             (void) _genDialog->post_and_return(DTMAILHELPERROR);
2816             delete [] buf;
2817             return;
2818         }
2819         delete [] buf;
2820     }
2821     
2822     // Path filename is ok -- now follow the same route as for Open
2823     this->view_mail_file(filename, DTM_TRUE);
2824 }
2825
2826
2827
2828 // SR - added methods below
2829
2830 ViewMsgDialog*
2831 RoamMenuWindow::ifViewExists(DtMailMessageHandle msg_num)
2832 {
2833
2834     int i;
2835     FORCE_SEGV_DECL(ViewMsgDialog, a_view);
2836
2837     for (i = 0; i < _numDialogs; i++) {
2838         a_view = _dialogs[i];
2839         if (a_view->msgno() == msg_num) {
2840             return(a_view);
2841         }
2842     }
2843     return(NULL);
2844 }
2845
2846         
2847 void
2848 RoamMenuWindow::addToRowOfButtons()
2849 {
2850     FORCE_SEGV_DECL(CmdInterface, ci);
2851     Widget w, prev_widget;
2852     int offset = 10;
2853
2854     _delete_button = new DeleteCmd ( 
2855                                 "Delete",
2856                                 GETMSG(DT_catd, 1, 9, "Delete"), 
2857                                 TRUE, this );
2858     ci  = new ButtonInterface (_rowOfButtons, _delete_button);
2859     w = ci->baseWidget();
2860     XtAddCallback(w, XmNhelpCallback, HelpCB, (void *)DTMAILDELBTNID);
2861     XtVaSetValues(w,
2862         XmNleftAttachment, XmATTACH_FORM,
2863         XmNtopAttachment, XmATTACH_FORM,
2864         XmNbottomAttachment, XmATTACH_FORM,
2865         XmNmarginLeft, offset,
2866         XmNmarginRight, offset,
2867         NULL );
2868     ci->manage();
2869     prev_widget = w;
2870
2871     _next_button  = new NextCmd ( 
2872                         "Next",
2873                         GETMSG(DT_catd, 1, 10, "Next"), 
2874                         TRUE, this );
2875     ci  = new ButtonInterface (_rowOfButtons, _next_button);
2876     w = ci->baseWidget();
2877     XtAddCallback(w, XmNhelpCallback, HelpCB, (void *)DTMAILNEXTBTNID);
2878     XtVaSetValues(w,
2879         XmNleftAttachment, XmATTACH_WIDGET,
2880         XmNleftWidget, prev_widget,
2881         XmNleftOffset, 10,
2882         XmNtopAttachment, XmATTACH_FORM,
2883         XmNbottomAttachment, XmATTACH_FORM,
2884         XmNmarginLeft, offset,
2885         XmNmarginRight, offset,
2886         NULL );
2887     ci->manage();
2888     prev_widget = w;
2889
2890     _previous_button = new PrevCmd ( 
2891                                 "Previous",
2892                                 GETMSG(DT_catd, 1, 11, "Previous"), 
2893                                 TRUE, this );
2894     ci  = new ButtonInterface (_rowOfButtons, _previous_button);
2895     w = ci->baseWidget();
2896     XtAddCallback(w, XmNhelpCallback, HelpCB, (void *)DTMAILPREVBTNID);
2897     XtVaSetValues(w,
2898         XmNleftAttachment, XmATTACH_WIDGET,
2899         XmNleftWidget, prev_widget,
2900         XmNleftOffset, 10,
2901         XmNtopAttachment, XmATTACH_FORM,
2902         XmNbottomAttachment, XmATTACH_FORM,
2903         XmNmarginLeft, offset,
2904         XmNmarginRight, offset,
2905         NULL );
2906     ci->manage();
2907     prev_widget = w;
2908
2909     _replySender_button = new ReplyCmd (
2910                                 "Reply to Sender",
2911                                 GETMSG(DT_catd, 1, 12, "Reply to Sender"), 
2912                                 TRUE, 
2913                                 this, 
2914                                 FALSE );
2915     ci  = new ButtonInterface (_rowOfButtons, _replySender_button);
2916     w = ci->baseWidget();
2917     XtAddCallback(w, XmNhelpCallback, HelpCB, (void *)DTMAILREPLYBTNID);
2918     XtVaSetValues(w,
2919         XmNleftAttachment, XmATTACH_WIDGET,
2920         XmNleftWidget, prev_widget,
2921         XmNleftOffset, 10,
2922         XmNtopAttachment, XmATTACH_FORM,
2923         XmNbottomAttachment, XmATTACH_FORM,
2924         XmNmarginLeft, offset,
2925         XmNmarginRight, offset,
2926         NULL );
2927     ci->manage();
2928     prev_widget = w;
2929
2930
2931     _print_button  = new PrintCmd ( "Print", GETMSG(DT_catd, 1, 13, "Print"),
2932                                 TRUE, TRUE, this);
2933     ci  = new ButtonInterface (_rowOfButtons, _print_button);
2934     w = ci->baseWidget();
2935     XtAddCallback(w, XmNhelpCallback, HelpCB, (void *)DTMAILPRINTBTNID);
2936     XtVaSetValues(w,
2937         XmNleftAttachment, XmATTACH_WIDGET,
2938         XmNleftWidget, prev_widget,
2939         XmNleftOffset, 10,
2940         XmNtopAttachment, XmATTACH_FORM,
2941         XmNbottomAttachment, XmATTACH_FORM,
2942         XmNmarginLeft, offset,
2943         XmNmarginRight, offset,
2944         NULL );
2945     ci->manage();
2946     prev_widget = w;
2947 }
2948
2949 void
2950 RoamMenuWindow::addToRowOfLabels(MsgScrollingList *msglist)
2951 {
2952
2953     XmString             arrow, basexms, spaces, spaces_arrow;
2954     char                 arrow_symbol[2];
2955     char                *glyph_font;
2956
2957     glyph_font = theRoamApp.glyphName();
2958
2959 #if 0
2960     XFontStruct         *xfs;
2961     XmFontListEntry     xmfle;
2962     XmFontList          xmfl, xmfl_old;
2963     Widget               lbl;
2964     
2965     xfs = XLoadQueryFont(XtDisplay(_rowOfLabels), glyph_font);
2966     xmfle = XmFontListEntryCreate("arrow", XmFONT_IS_FONT, (XtPointer) xfs);
2967
2968     lbl = XtVaCreateManagedWidget("t", xmLabelGadgetClass, _rowOfLabels, NULL);
2969     XtVaGetValues(lbl, XmNfontList, &xmfl_old, NULL);
2970     xmfl = XmFontListAppendEntry(xmfl_old, xmfle);
2971 #else
2972 //  Pixel               foreground, background;
2973     XmRenderTable       rt, rt_old;
2974     XmRendition         rend;
2975     Arg                 args[25];
2976     int                 nargs = 0;
2977
2978 //  lbl = XtVaCreateManagedWidget("t", xmLabelGadgetClass, _rowOfLabels, NULL);
2979 //  XtVaGetValues(
2980 //      lbl,
2981 //      XmNrenderTable, &rt_old,
2982 //      XmNforeground, &foreground,
2983 //      XmNbackground, &background,
2984 //      NULL);
2985
2986 //  XtSetArg(args[nargs], XmNrenditionBackground, background); nargs++;
2987 //  XtSetArg(args[nargs], XmNrenditionForeground, foreground); nargs++;
2988 //  XtSetArg(args[nargs], XmNloadModel, XmLOAD_IMMEDIATE); nargs++;
2989
2990     XtSetArg(args[nargs], XmNfontName, glyph_font); nargs++;
2991     XtSetArg(args[nargs], XmNfontType, XmFONT_IS_FONT); nargs++;
2992     rend = XmRenditionCreate(_rowOfLabels, "arrow", args, nargs);
2993 #endif
2994
2995     arrow_symbol[0] = (char) 209;
2996     arrow_symbol[1] = '\0';
2997
2998     spaces = XmStringCreateLocalized("  ");
2999     arrow = XmStringCreate((char*) arrow_symbol, "arrow");
3000     spaces_arrow = XmStringConcat(spaces, arrow);
3001
3002     XmStringFree(spaces);
3003     spaces = XmStringCreateLocalized("    ");
3004
3005     basexms = XmStringCreateLocalized(GETMSG(DT_catd, 1, 14, "Sender"));
3006     _sender_xms = XmStringConcat(basexms, spaces);
3007     _sender_key_xms = XmStringConcat(basexms, spaces_arrow);
3008     XmStringFree(basexms);
3009
3010     _sender_lbl = XtVaCreateManagedWidget(
3011                                 "Sender", xmLabelGadgetClass, 
3012                                 _rowOfLabels,
3013 #if 0
3014                                 XmNfontList, xmfl,
3015                                 XmNrenderTable, rt,
3016 #endif
3017                                 XmNlabelString, _sender_xms,
3018                                 XmNalignment, XmALIGNMENT_BEGINNING,
3019                                 NULL);
3020
3021     XtSetArg(args[nargs], XmNfontName, glyph_font); nargs++;
3022     XtSetArg(args[nargs], XmNfontType, XmFONT_IS_FONT); nargs++;
3023     rend = XmRenditionCreate(_rowOfLabels, "arrow", args, nargs);
3024
3025     XtVaGetValues(_sender_lbl, XmNrenderTable, &rt_old, NULL);
3026     rt = XmRenderTableCopy(rt_old, NULL, 0);
3027     rt = XmRenderTableAddRenditions(rt, &rend, 1, XmMERGE_REPLACE);
3028     XtVaSetValues(_sender_lbl, XmNrenderTable, rt, NULL);
3029
3030     // Add help callback
3031     // printHelpId("Sender", _sender_lbl);
3032     // XtAddCallback(_sender_lbl, XmNhelpCallback, HelpCB, helpId);
3033
3034     basexms = XmStringCreateLocalized(GETMSG(DT_catd, 1, 15, "Subject"));
3035     _subject_xms = XmStringConcat(basexms, spaces);
3036     _subject_key_xms = XmStringConcat(basexms, spaces_arrow);
3037     XmStringFree(basexms);
3038
3039     _subject_lbl = XtVaCreateManagedWidget(
3040                                 "Subject", xmLabelGadgetClass, 
3041                                 _rowOfLabels,
3042 #if 0
3043                                 XmNfontList, xmfl,
3044                                 XmNrenderTable, rt,
3045 #endif
3046                                 XmNlabelString, _subject_xms,
3047                                 XmNalignment, XmALIGNMENT_BEGINNING,
3048                                 NULL);
3049
3050     XtSetArg(args[nargs], XmNfontName, glyph_font); nargs++;
3051     XtSetArg(args[nargs], XmNfontType, XmFONT_IS_FONT); nargs++;
3052     rend = XmRenditionCreate(_rowOfLabels, "arrow", args, nargs);
3053
3054     XtVaGetValues(_subject_lbl, XmNrenderTable, &rt_old, NULL);
3055     rt = XmRenderTableCopy(rt_old, NULL, 0);
3056     rt = XmRenderTableAddRenditions(rt, &rend, 1, XmMERGE_REPLACE);
3057     XtVaSetValues(_subject_lbl, XmNrenderTable, rt, NULL);
3058
3059     // Add help callback
3060     // printHelpId("Subject", _subject_lbl);
3061     // XtAddCallback(_subject_lbl, XmNhelpCallback, HelpCB, helpId);
3062
3063     basexms = XmStringCreateLocalized(GETMSG(DT_catd, 1, 16,"Date and Time"));
3064     _date_xms = XmStringConcat(basexms, spaces);
3065     _date_key_xms = XmStringConcat(basexms, spaces_arrow);
3066     XmStringFree(basexms);
3067
3068     _date_lbl = XtVaCreateManagedWidget(
3069                                 "DateTime", xmLabelGadgetClass, 
3070                                 _rowOfLabels,
3071 #if 0
3072                                 XmNfontList, xmfl,
3073                                 XmNrenderTable, rt,
3074 #endif
3075                                 XmNlabelString, _date_xms,
3076                                 XmNalignment, XmALIGNMENT_BEGINNING,
3077                                 NULL);
3078
3079     XtSetArg(args[nargs], XmNfontName, glyph_font); nargs++;
3080     XtSetArg(args[nargs], XmNfontType, XmFONT_IS_FONT); nargs++;
3081     rend = XmRenditionCreate(_rowOfLabels, "arrow", args, nargs);
3082
3083     XtVaGetValues(_date_lbl, XmNrenderTable, &rt_old, NULL);
3084     rt = XmRenderTableCopy(rt_old, NULL, 0);
3085     rt = XmRenderTableAddRenditions(rt, &rend, 1, XmMERGE_REPLACE);
3086     XtVaSetValues(_date_lbl, XmNrenderTable, rt, NULL);
3087
3088     // Add help callback
3089     // printHelpId("DateTime", _subject_lbl);
3090     // XtAddCallback(_date_lbl, XmNhelpCallback, HelpCB, helpId);
3091
3092     basexms = XmStringCreateLocalized(GETMSG(DT_catd, 1, 17, "Size"));
3093     _size_xms = XmStringConcat(basexms, spaces);
3094     _size_key_xms = XmStringConcat(basexms, spaces_arrow);
3095     XmStringFree(basexms);
3096
3097     _size_lbl = XtVaCreateManagedWidget(
3098                                 "Size", xmLabelGadgetClass, 
3099                                 _rowOfLabels,
3100 #if 0
3101                                 XmNfontList, xmfl,
3102                                 XmNrenderTable, rt,
3103 #endif
3104                                 XmNlabelString, _size_xms,
3105                                 XmNalignment, XmALIGNMENT_BEGINNING,
3106                                 NULL);
3107
3108     XtSetArg(args[nargs], XmNfontName, glyph_font); nargs++;
3109     XtSetArg(args[nargs], XmNfontType, XmFONT_IS_FONT); nargs++;
3110     rend = XmRenditionCreate(_rowOfLabels, "arrow", args, nargs);
3111
3112     XtVaGetValues(_size_lbl, XmNrenderTable, &rt_old, NULL);
3113     rt = XmRenderTableCopy(rt_old, NULL, 0);
3114     rt = XmRenderTableAddRenditions(rt, &rend, 1, XmMERGE_REPLACE);
3115     XtVaSetValues(_size_lbl, XmNrenderTable, rt, NULL);
3116
3117     // Add help callback
3118     // printHelpId("Size", _size_lbl);
3119     // XtAddCallback(_size_lbl, XmNhelpCallback, HelpCB, helpId);
3120
3121     // Adjust labels so the align on the columns
3122     msglist->layoutLabels(_sender_lbl, _subject_lbl, _date_lbl, _size_lbl);
3123
3124     XmStringFree(arrow);
3125     XmStringFree(spaces);
3126     XmStringFree(spaces_arrow);
3127     return;
3128 }
3129
3130 void
3131 RoamMenuWindow::addToRowOfMessageStatus()
3132 {
3133     XmString labelStr1, labelStr2;
3134
3135     // Size of first label
3136     
3137     labelStr1 = XmStringCreateLocalized(GETMSG(DT_catd, 3, 25,
3138            "Loading container..."));
3139
3140     labelStr2 = XmStringCreateLocalized(
3141                         GETMSG(DT_catd, 3, 26, "Folder Summary Information"));
3142
3143     _message = XtCreateManagedWidget(
3144                         "Message_Status_Text", xmLabelWidgetClass,
3145                         _rowOfMessageStatus, NULL, 0);
3146     printHelpId("_message", _message);
3147     /* add help callback */
3148     // XtAddCallback(_message, XmNhelpCallback, HelpCB, helpId);
3149
3150
3151      XtVaSetValues(_message,
3152         XmNalignment, XmALIGNMENT_BEGINNING,
3153         XmNleftAttachment, XmATTACH_FORM,
3154         XmNtopAttachment, XmATTACH_FORM,
3155         XmNbottomAttachment, XmATTACH_FORM,
3156         XmNlabelString, labelStr1,
3157         NULL );
3158     
3159     _message_summary = XtCreateManagedWidget("Message_Summary", 
3160                                         xmLabelWidgetClass,
3161                                         _rowOfMessageStatus, NULL, 0);
3162      XtVaSetValues(_message_summary,
3163         XmNalignment, XmALIGNMENT_END,
3164         XmNlabelString, labelStr2,
3165         XmNrightAttachment, XmATTACH_FORM,
3166         NULL );
3167
3168      XtVaSetValues(_message,
3169          XmNrightAttachment, XmATTACH_WIDGET,
3170          XmNrightWidget, _message_summary,
3171          XmNrightOffset, 10,
3172          NULL);
3173
3174      XmStringFree(labelStr1);
3175      XmStringFree(labelStr2);
3176  
3177 }
3178
3179 void
3180 RoamMenuWindow::createContainerList()
3181 {
3182     FORCE_SEGV_DECL(DtMail::Session, m_session);
3183     DtMailEnv           error;
3184     const char          *val = NULL;
3185     const char          *cached_containerlist_size = NULL;
3186     const char          *display_cfs = NULL;
3187     DtMailBoolean       user_list = DTM_FALSE;
3188
3189     //
3190     // Get names for permanent containers from .mailrc.
3191     // We get the items from the "filemenu2" variable.
3192     if (_filemenu2 != NULL) free (_filemenu2);
3193
3194     m_session = theRoamApp.session()->session();
3195     m_session->mailRc(error)->getValue(error, "filemenu2", &val);
3196     if (error.isNotSet() && val != NULL && *val != '\0')
3197     {
3198         user_list = DTM_TRUE;
3199         _filemenu2 = strdup(val);
3200     }
3201     else _filemenu2 = NULL;
3202
3203     if (NULL != val)
3204       free((void*) val);
3205
3206     // We will use _user_containerlist to keep track of the static set of
3207     // containers coming from the "filemenu2" value. 
3208     // We will use _cached_containerlist to keep track of containers
3209     // which get cached from "Other Mailboxes... operations from the
3210     // Open, CopyTo, and Move menus.
3211
3212     if (_user_containerlist != NULL)
3213         delete (_user_containerlist);
3214     _user_containerlist = new DtVirtArray<ContainerMenuCmd*> (3);
3215
3216     m_session->mailRc(error)->getValue(
3217                                 error,
3218                                 "dontdisplaycachedfiles",
3219                                 &display_cfs);
3220
3221     if (error.isNotSet() && display_cfs != NULL) 
3222       _max_cached_list_size = 0;
3223     else
3224     {
3225         error.clear();
3226         m_session->mailRc(error)->getValue(
3227                                         error, 
3228                                         "cachedfilemenusize",
3229                                         &cached_containerlist_size);
3230         if (error.isNotSet() &&
3231             cached_containerlist_size && 
3232             *cached_containerlist_size)
3233           _max_cached_list_size = 
3234             (int) strtol(cached_containerlist_size, NULL, 10);
3235         else 
3236           _max_cached_list_size = 10;
3237     }
3238
3239     if (NULL != display_cfs)
3240       free((void*) display_cfs);
3241     if (NULL != cached_containerlist_size)
3242       free((void*) cached_containerlist_size);
3243
3244     int size = (_max_cached_list_size ? _max_cached_list_size : 1);
3245     _cached_containerlist = new DtVirtArray<ContainerMenuCmd*> (size);
3246
3247     if (user_list == DTM_TRUE) {
3248         char *expanded_list = m_session->expandPath(error, _filemenu2);
3249         char *token = NULL;
3250
3251         //
3252         // Create arrays to hold the user defined container list and the
3253         // recently visited (cached) container list.
3254         //
3255         if ((token = (char *) strtok(expanded_list, " ")))
3256         {
3257             ContainerMenuCmd *null_container;
3258             
3259             null_container= new ContainerMenuCmd(
3260                                                 strdup(token),
3261                                                 token,
3262                                                 TRUE,
3263                                                 this,
3264                                                 DTM_NONE);
3265             _user_containerlist->append(null_container);
3266             while (token = (char *) strtok(NULL, " "))
3267             {
3268                 null_container= new ContainerMenuCmd(
3269                                                 strdup(token),
3270                                                 token,
3271                                                 TRUE,
3272                                                 this,
3273                                                 DTM_NONE);
3274                 _user_containerlist->append(null_container);
3275             }
3276         }
3277         free(expanded_list);
3278     }
3279
3280     if (_user_containerlist->length() > 0)
3281       _first_cached_item = _user_containerlist->length() +4;
3282     else
3283       _first_cached_item = 3;
3284 }
3285
3286 void
3287 RoamMenuWindow::createOpenContainerList(CmdList * open_container)
3288 {
3289     int                 ncontainers, i;
3290     char                *container_name;
3291     ContainerMenuCmd    *container_cmd;
3292
3293     _open_container_separator = new SeparatorCmd("Separator","Separator", TRUE);
3294
3295     _open_container_inbox = new OpenInboxCmd(
3296                                         "Inbox",
3297                                         GETMSG(DT_catd, 1, 221, "Inbox"),
3298                                         (FALSE == this->inbox()),
3299                                         this);
3300
3301     _open_container_other = new UnifiedSelectMailboxCmd(
3302                                 "Open",
3303                                 GETMSG(DT_catd, 1, 246, "Other Mailboxes..."), 
3304                                 GETMSG(DT_catd, 1, 26, "Mailer - Open"),
3305                                 GETMSG(DT_catd, 1, 27, "Open"),
3306                                 TRUE,
3307                                 RoamMenuWindow::file_selection_callback,
3308                                 this,
3309                                 this->baseWidget(),
3310                                 DTM_TRUE);
3311
3312     //
3313     // We will use _open_container_containerlist to keep track of the
3314     // static set of OpenContainer commands coming from the "filemenu2"
3315     // value.
3316     //
3317     ncontainers = _user_containerlist->length();
3318
3319     if (_open_container_containerlist != NULL)
3320       delete (_open_container_containerlist);
3321     _open_container_containerlist =
3322       new DtVirtArray<ContainerMenuCmd*>(ncontainers);
3323
3324     for (i=0; i<ncontainers; i++)
3325     {
3326         container_name = (*_user_containerlist)[i]->containerName();
3327         if (NULL != container_name)
3328         {
3329             container_cmd = new ContainerMenuCmd(
3330                                                 strdup(container_name),
3331                                                 container_name,
3332                                                 TRUE,
3333                                                 this,
3334                                                 DTM_OPEN);
3335             open_container->add(container_cmd);
3336             _open_container_containerlist->append(container_cmd);
3337         }
3338     }
3339
3340     if (0 < ncontainers)
3341       open_container->add(_open_container_separator);
3342     open_container->add(_open_container_inbox);
3343     open_container->add(_open_container_other);
3344     open_container->add(_open_container_separator);
3345
3346     //
3347     // We will use _open_container_containerlist_cached
3348     // to keep track of OpenContainer which get cached from
3349     // "Other Mailboxes..." operations from the Open, CopyTo, and Move menus.
3350     //
3351
3352     ncontainers =  (_max_cached_list_size ? _max_cached_list_size : 1);
3353
3354     if (_open_container_containerlist_cached != NULL)
3355       delete (_open_container_containerlist_cached);
3356     _open_container_containerlist_cached =
3357       new DtVirtArray<ContainerMenuCmd*> (ncontainers);
3358  
3359     ncontainers = (_display_cached_list ? _cached_containerlist->length() : 0);
3360     for (i=0; i<ncontainers; i++)
3361     {
3362         container_name = (*_cached_containerlist)[i]->containerName();
3363         if (NULL != container_name)
3364         {
3365             container_cmd = new ContainerMenuCmd(
3366                                                 strdup(container_name),
3367                                                 container_name,
3368                                                 TRUE,
3369                                                 this,
3370                                                 DTM_OPEN);
3371             open_container->add(container_cmd);
3372             _open_container_containerlist_cached->append(container_cmd);
3373         }
3374     }
3375 }
3376
3377
3378 void
3379 RoamMenuWindow::construct_file_menu()
3380 {
3381     FORCE_SEGV_DECL(CmdList, cmdList);
3382
3383     _file_separator = new SeparatorCmd( "Separator","Separator", TRUE );
3384     
3385     // Create the "Container" item in the menubar.  And fill 
3386     // with items below the "Container" item in the menubar.
3387     
3388     cmdList = new CmdList( "Mailbox", GETMSG(DT_catd, 1, 18, "Mailbox") );
3389     _file_cmdlist = cmdList;
3390
3391     _file_check_new_mail        = new CheckForNewMailCmd(
3392                                 "Check for New Mail",
3393                                 GETMSG(DT_catd, 1, 19, "Check for New Mail"), 
3394                                 TRUE, 
3395                                 this);
3396     if (this->inbox()) { // Deactivate the Open Inbox item 
3397         _file_open_inbox               = new OpenInboxCmd(
3398                                         "Open Inbox",
3399                                         GETMSG(DT_catd, 1, 20, "Open Inbox"),
3400                                         FALSE,
3401                                         this);
3402     }
3403     else { // Activate the Open Inbox item.
3404         _file_open_inbox               = new OpenInboxCmd(
3405                                         "Open Inbox",
3406                                         GETMSG(DT_catd, 1, 21, "Open Inbox"),
3407                                         TRUE,
3408                                         this);
3409     }
3410
3411     _file_new_container     = new UnifiedSelectMailboxCmd( 
3412                                 "New...",
3413                                 GETMSG(DT_catd, 1, 22, "New..."),
3414                                 GETMSG(DT_catd, 1, 23, "Mailer - New"),
3415                                 GETMSG(DT_catd, 1, 24, "New"),
3416                                 TRUE,
3417                                 RoamMenuWindow::create_container_callback,
3418                                 this,
3419                                 this->baseWidget(),
3420                                 DTM_TRUE);
3421 #if defined(USE_OLD_FILE_OPEN)
3422     _file_open              = new UnifiedSelectMailboxCmd(
3423                                 "Open...",
3424                                 GETMSG(DT_catd, 1, 25, "Open..."), 
3425                                 GETMSG(DT_catd, 1, 26, "Mailer - Open"),
3426                                 GETMSG(DT_catd, 1, 27, "Open"),
3427                                 TRUE,
3428                                 RoamMenuWindow::file_selection_callback,
3429                                 this,
3430                                 this->baseWidget());
3431 #endif
3432
3433     _open_container_cmdlist = new CmdList(
3434                                 "Open Container",
3435                                 GETMSG(DT_catd, 1, 245, "Open"));
3436     createOpenContainerList(_open_container_cmdlist);
3437
3438     _file_destroy_deleted_msgs  = new DestroyCmd(
3439                                         "Destroy Deleted Message",
3440                                         GETMSG(DT_catd, 1, 28, 
3441                                                 "Destroy Deleted Messages"), 
3442                                               TRUE,
3443                                               this);
3444
3445
3446     _file_quit              = new QuitCmd (
3447                                 "Close",
3448                                 GETMSG(DT_catd, 1, 29, "Close"), 
3449                                 TRUE, 
3450                                 this);
3451     
3452     cmdList->add(_file_check_new_mail);
3453     cmdList->add(_file_open_inbox);
3454     cmdList->add(_file_separator);
3455     cmdList->add(_file_new_container);
3456 #if defined(USE_OLD_FILE_OPEN)
3457     cmdList->add(_file_open);
3458 #endif
3459     cmdList->add(_open_container_cmdlist);
3460     cmdList->add(_file_separator);
3461     cmdList->add(_file_destroy_deleted_msgs);
3462     cmdList->add(theRoamApp.mailOptions());
3463     cmdList->add(_file_separator);
3464     cmdList->add(_file_quit);
3465     
3466     _menuBar->addCommands(&_file_cascade, cmdList);
3467  
3468     _opencontainerMenu = _open_container_cmdlist->getPaneWidget();
3469  
3470     XtVaSetValues(
3471                 _opencontainerMenu, 
3472                 XmNpacking, XmPACK_COLUMN, 
3473                 XmNorientation, XmVERTICAL,
3474                 NULL);
3475
3476     XtAddCallback(
3477                 _opencontainerMenu,
3478                 XmNmapCallback, &RoamMenuWindow::map_menu,
3479                 NULL);
3480
3481     XtSetSensitive(_opencontainerMenu, TRUE);
3482 }
3483
3484 void
3485 RoamMenuWindow::createCopyList(CmdList * copy_to)
3486 {
3487     int                 ncontainers, i;
3488     char                *container_name;
3489     ContainerMenuCmd    *container_cmd;
3490
3491     _copyto_separator = new SeparatorCmd("Separator","Separator", TRUE);
3492
3493     _copyto_inbox = new CopyToInboxCmd(
3494                                 "Inbox",
3495                                 GETMSG(DT_catd, 1, 221, "Inbox"), 
3496                                 TRUE, 
3497                                 this);
3498
3499     // This is where we initialize _move_copy_button, so this needs to
3500     // be the first place that we use it.  This routine needs to be
3501     // called before construct_move_menu(), which expects _move_copy_button
3502     // to be intialized.
3503
3504     DtMailEnv error;
3505     DtMail::Session * d_session = theRoamApp.session()->session();
3506     DtMail::MailRc * mailrc = d_session->mailRc(error);
3507     const char *value = NULL;
3508     DtMailBoolean only_show_mailboxes = DTM_FALSE;
3509
3510     mailrc->getValue(error, "movecopytomailboxesonly", &value);
3511     only_show_mailboxes = (error.isSet()) ? DTM_FALSE : DTM_TRUE;
3512     { 
3513         value = strdup("15");
3514         error.clear();
3515     }
3516     if (value)
3517       free((void*) value);
3518
3519     _move_copy_button = new MoveCopyCmd (
3520                                 "Other Mailboxes...",
3521                                 GETMSG(DT_catd, 1, 65, "Other Mailboxes..."),
3522                                 TRUE,
3523                                 RoamMenuWindow::move_callback,
3524                                 RoamMenuWindow::copy_callback,
3525                                 this,
3526                                 this->baseWidget(),
3527                                 only_show_mailboxes);
3528     _copyto_other = new CopyCmd(
3529                                 GETMSG(DT_catd, 1, 237, "Copy"),
3530                                 GETMSG(DT_catd, 1, 65, "Other Mailboxes..."),
3531                                 TRUE,
3532                                 this,
3533                                 (MoveCopyCmd *) _move_copy_button);
3534
3535     //
3536     // We will use _copyto_containerlist to keep track of the
3537     // static set of CopyTo commands coming from the "filemenu2"
3538     // value.
3539     //
3540     ncontainers = _user_containerlist->length();
3541
3542     if (_copyto_containerlist != NULL)
3543       delete (_copyto_containerlist);
3544     _copyto_containerlist =
3545       new DtVirtArray<ContainerMenuCmd *> (ncontainers);
3546
3547     for (i=0; i<ncontainers; i++)
3548     {
3549         container_name = (*_user_containerlist)[i]->containerName();
3550         if (NULL != container_name)
3551         {
3552             container_cmd = new ContainerMenuCmd(
3553                                                 strdup(container_name),
3554                                                 container_name,
3555                                                 TRUE,
3556                                                 this,
3557                                                 DTM_COPY);
3558             copy_to->add(container_cmd);
3559             _copyto_containerlist->append(container_cmd);
3560         }
3561     }
3562
3563     if (0 < ncontainers)
3564       copy_to->add(_copyto_separator);
3565     copy_to->add(_copyto_inbox);
3566     copy_to->add(_copyto_other);
3567     copy_to->add(_copyto_separator);
3568
3569     //
3570     // We will use _copyto_containerlist_cached
3571     // to keep track of CopyTo commands which get cached from
3572     //"Other Mailboxes..." operations from the Open, CopyTo, and Move menus.
3573     //
3574
3575     ncontainers = (_max_cached_list_size ? _max_cached_list_size : 1);
3576
3577     if (_copyto_containerlist_cached != NULL)
3578       delete (_copyto_containerlist_cached);
3579     _copyto_containerlist_cached =
3580       new DtVirtArray<ContainerMenuCmd *> (ncontainers);
3581
3582     ncontainers = (_display_cached_list ? _cached_containerlist->length() : 0);
3583     for (i=0; i<ncontainers; i++)
3584     {
3585         container_name = (*_cached_containerlist)[i]->containerName();
3586         if (NULL != container_name)
3587         {
3588             container_cmd = new ContainerMenuCmd(
3589                                                 strdup(container_name),
3590                                                 container_name,
3591                                                 TRUE,
3592                                                 this,
3593                                                 DTM_COPY);
3594             copy_to->add(container_cmd);
3595             _copyto_containerlist_cached->append(container_cmd);
3596         }
3597     }
3598 }
3599
3600 void
3601 RoamMenuWindow::construct_message_menu()
3602 {
3603     FORCE_SEGV_DECL(CmdList, cmdList);
3604     // Separator for menu items
3605     
3606     _msg_separator= new SeparatorCmd( "Separator","Separator", TRUE );
3607     
3608     _msg_open           = new OpenMsgCmd(
3609                                 "Open",
3610                                 GETMSG(DT_catd, 1, 30, "Open"), 
3611                                 TRUE, this);
3612
3613     _msg_save_as        = new SaveAsTextCmd (
3614                                 "Save As Text...",
3615                                 GETMSG(DT_catd, 1, 31, "Save As Text..."),
3616                                 GETMSG(DT_catd, 1, 32, "Mailer - Message - Save As Text"),
3617                                 TRUE,
3618                                 get_editor()->textEditor(),
3619                                 this,
3620                                 this->baseWidget());
3621
3622     _copyto_cmdlist = new CmdList("Copy To", GETMSG(DT_catd, 1, 33, "Copy To"));
3623     createCopyList(_copyto_cmdlist);
3624
3625     _msg_print          = new PrintCmd(
3626                                 "Print...",
3627                                 GETMSG(DT_catd, 1, 34, "Print..."), 
3628                                 TRUE, FALSE, this);
3629
3630     _msg_find           = new FindCmd (
3631                                 "Find...",
3632                                 GETMSG(DT_catd, 1, 35, "Find..."), 
3633                                 TRUE, this );
3634
3635     _msg_select_all = new SelectAllCmd (
3636                                 "Select All",
3637                                 GETMSG(DT_catd, 1, 36, "Select All"),
3638                                 TRUE, this );
3639
3640     _msg_delete         = new DeleteCmd(
3641                                 "Delete",
3642                                 GETMSG(DT_catd, 1, 37, "Delete"),
3643                                 TRUE, this);
3644
3645     _msg_undelete_last       = new UndeleteCmd ( 
3646                                 "Undelete Last",
3647                                 GETMSG(DT_catd, 1, 38, "Undelete Last"), 
3648                                 TRUE, this, FALSE );
3649
3650     _msg_undelete_from_list   = new UndeleteCmd(
3651                                 "Undelete From List...",
3652                                 GETMSG(DT_catd, 1, 39, 
3653                                         "Undelete From List..."), 
3654                                 TRUE, this, TRUE);
3655
3656     // Message Menu
3657     
3658     cmdList = new CmdList( "Message", GETMSG(DT_catd, 1, 40, "Message") );
3659     _msg_cmdlist = cmdList;
3660
3661     cmdList->add(_msg_open);
3662     cmdList->add(_msg_save_as);
3663     cmdList->add(_copyto_cmdlist);
3664     cmdList->add(_msg_print);
3665     cmdList->add(_msg_find);
3666     cmdList->add(_msg_select_all);
3667
3668     cmdList->add(_msg_separator);
3669
3670     cmdList->add(_msg_delete);
3671     cmdList->add(_msg_undelete_last);
3672     cmdList->add(_msg_undelete_from_list);
3673
3674     _menuBar->addCommands(&_message_cascade, cmdList, FALSE, XmMENU_BAR);
3675  
3676     _copytoMenu = _copyto_cmdlist->getPaneWidget();
3677  
3678     XtVaSetValues(_copytoMenu, 
3679                   XmNpacking, XmPACK_COLUMN, 
3680                   XmNorientation, XmVERTICAL,
3681                   NULL);
3682
3683     XtAddCallback(_copytoMenu, XmNmapCallback, &RoamMenuWindow::map_menu, NULL);
3684
3685     XtSetSensitive(_copytoMenu, TRUE);
3686 }
3687
3688 void
3689 RoamMenuWindow::construct_message_popup(void)
3690 {
3691    _msgsPopup_cmdlist = new CmdList( "MsgsPopup", "MsgsPopup");
3692
3693    LabelCmd *title     = new LabelCmd (
3694                         "Mailer - Messages",
3695                         GETMSG(DT_catd, 1, 42, "Mailer - Messages"), TRUE);
3696    _msgsPopup_separator = new SeparatorCmd( "Separator","Separator", TRUE );
3697    _msgsPopup_cmdlist->add(title);
3698    _msgsPopup_cmdlist->add(_msgsPopup_separator);
3699    _msgsPopup_cmdlist->add(_msg_delete);
3700    _msgsPopup_cmdlist->add(_msg_undelete_last);
3701    _msgsPopup_cmdlist->add(_msg_print);
3702    _msgsPopup_cmdlist->add(_comp_replySender);
3703    _msgsPopup_cmdlist->add(_move_cmdlist);
3704    _msgsPopup_cmdlist->add(_msg_save_as);
3705    _msgsPopup_cmdlist->add(_file_check_new_mail);
3706
3707    Widget parent = XtParent(_list->get_scrolling_list());
3708    _menuPopupMsgs = new MenuBar(parent, "RoamMsgsPopup", XmMENU_POPUP);
3709    _msgsPopupMenu = _menuPopupMsgs->addCommands(_msgsPopup_cmdlist, 
3710                         FALSE, XmMENU_POPUP);
3711    XtAddEventHandler(parent, ButtonPressMask,
3712                         FALSE, MenuButtonHandler, (XtPointer) this);
3713    
3714    _msgsPopupMoveMenu = _move_cmdlist->getPaneWidget();
3715
3716    XtVaSetValues(_msgsPopupMoveMenu, 
3717                  XmNpacking, XmPACK_COLUMN, 
3718                  XmNorientation, XmVERTICAL,
3719                  NULL);
3720    XtAddCallback(_msgsPopupMoveMenu, XmNmapCallback, &RoamMenuWindow::map_menu, NULL);
3721
3722    XtSetSensitive(_msgsPopupMoveMenu, TRUE);
3723  
3724 }
3725
3726 void
3727 RoamMenuWindow::construct_edit_menu()
3728 {
3729     FORCE_SEGV_DECL(CmdList, cmdList);
3730     // Separator for menu items
3731     
3732     _edit_copy = new EditCopyCmd(
3733                         "Copy",
3734                         GETMSG(DT_catd, 1, 43, "Copy"), 
3735                         TRUE, 
3736                         this
3737                      );
3738
3739     _edit_select_all = new EditSelectAllCmd(
3740                         "Select All",
3741                         GETMSG(DT_catd, 1, 44, "Select All"), 
3742                         TRUE,
3743                         this
3744                     );
3745
3746     cmdList = new CmdList("Edit", GETMSG(DT_catd, 1, 45, "Edit"));
3747     _edit_cmdlist = cmdList;
3748
3749     cmdList->add(_edit_copy);
3750     cmdList->add(_edit_select_all);
3751     
3752     _menuBar->addCommands(cmdList);
3753 }
3754
3755 void
3756 RoamMenuWindow::construct_text_popup(void)
3757 {
3758    if (theApplication->bMenuButton() != Button3)
3759        return;
3760
3761    _textPopup_cmdlist = new CmdList( "TextPopup", "TextPopup");
3762
3763     LabelCmd *title     = new LabelCmd (
3764                         "Mailer - Text",
3765                         GETMSG(DT_catd, 1, 46, "Mailer - Text"), TRUE);
3766     _textPopup_separator = new SeparatorCmd( "Separator","Separator", TRUE );
3767
3768     _textPopup_cmdlist->add(title);
3769     _textPopup_cmdlist->add(_textPopup_separator);
3770     _textPopup_cmdlist->add(_edit_copy);
3771     _textPopup_cmdlist->add(_edit_select_all);
3772
3773     Widget parent = _my_editor->textEditor()->get_editor();
3774     _menuPopupText = new MenuBar(parent, "RoamTextPopup", XmMENU_POPUP);
3775     _textPopupMenu = _menuPopupText->addCommands(_textPopup_cmdlist, 
3776                                 FALSE, XmMENU_POPUP);
3777 }
3778
3779
3780 void RoamMenuWindow::construct_view_menu()
3781 {
3782     FORCE_SEGV_DECL(CmdList, cmdList);
3783     FORCE_SEGV_DECL(CmdList, subCmdList);
3784
3785     _view_separator= new SeparatorCmd("Separator","Separator",TRUE);
3786     
3787     _view_next          = new NextCmd ( 
3788                                 "Next",
3789                                 GETMSG(DT_catd, 1, 47, "Next"), TRUE, this );
3790     _view_previous              = new PrevCmd ( 
3791                                 "Previous",
3792                                 GETMSG(DT_catd, 1, 48, "Previous"), TRUE, this );
3793     
3794     _view_abbrev_headers = new AbbrevHeadersCmd(
3795                                 "Abbreviated Headers",
3796                                 GETMSG(DT_catd, 1, 49, "Abbreviated Headers"), 
3797                                 this);
3798
3799
3800     _view_sortTD = new SortCmd ("By Date/Time", 
3801                                 GETMSG(DT_catd, 1, 50, "By Date/Time"),
3802                                 TRUE,
3803                                 this,
3804                                 SortTimeDate);
3805     _view_sortSender = new SortCmd ("By Sender",
3806                                 GETMSG(DT_catd, 1, 51, "By Sender"),
3807                                 TRUE,
3808                                 this,
3809                                 SortSender);
3810     _view_sortSubject = new SortCmd ("By Subject",
3811                                 GETMSG(DT_catd, 1, 52, "By Subject"),
3812                                 TRUE,
3813                                 this,
3814                                 SortSubject);
3815     _view_sortSize = new SortCmd ("By Size",
3816                                 GETMSG(DT_catd, 1, 53, "By Size"),
3817                                 TRUE,
3818                                 this,
3819                                 SortSize);
3820     _view_sortStatus = new SortCmd ("By Status",
3821                                 GETMSG(DT_catd, 1, 54, "By Status"),
3822                                 TRUE,
3823                                 this,
3824                                 SortStatus);
3825
3826     // View Menu
3827     
3828     cmdList = new CmdList( "View", GETMSG(DT_catd, 1, 55, "View") );
3829     _view_cmdlist = cmdList;
3830     
3831     cmdList->add(_view_next);
3832     cmdList->add(_view_previous);
3833     cmdList->add(_view_separator);
3834     cmdList->add(_view_abbrev_headers);
3835     cmdList->add(_view_separator);
3836     cmdList->add(_view_sortTD);
3837     cmdList->add(_view_sortSender);
3838     cmdList->add(_view_sortSubject);
3839     cmdList->add(_view_sortSize);
3840     cmdList->add(_view_sortStatus);
3841     
3842     _menuBar->addCommands ( cmdList );
3843 }
3844
3845
3846 void
3847 RoamMenuWindow::construct_compose_menu()
3848 {
3849     FORCE_SEGV_DECL(CmdList, cmdList);
3850     FORCE_SEGV_DECL(CmdList, subCmdList);
3851
3852     // Separator for menu items
3853     
3854     _comp_separator= new SeparatorCmd( "Separator","Separator", TRUE );
3855     
3856     _comp_new   = new ComposeCmd ( 
3857                         "New Message",
3858                         GETMSG(DT_catd, 1, 56, "New Message"), 
3859                         TRUE, 
3860                         this );
3861     _comp_new_include = new ForwardCmd ( 
3862                         "New, Include All",
3863                         GETMSG(DT_catd, 1, 57, "New, Include All"), 
3864                         TRUE, 
3865                         this, 
3866                         FALSE );
3867     _comp_forward       = new ForwardCmd ( 
3868                         "Forward Message",
3869                         GETMSG(DT_catd, 1, 58, "Forward Message"), 
3870                         TRUE, 
3871                         this, 
3872                         TRUE );
3873
3874     _comp_replySender = new ReplyCmd ( 
3875                               "Reply to Sender",
3876                               GETMSG(DT_catd, 1, 59, "Reply to Sender"), 
3877                               TRUE, 
3878                               this, 
3879                               FALSE );
3880
3881     _comp_replyAll      = new ReplyAllCmd ( 
3882                         "Reply to All",
3883                         GETMSG(DT_catd, 1, 60, "Reply to All"), 
3884                         TRUE, 
3885                         this, 
3886                         FALSE );
3887
3888     _comp_replySinclude= new ReplyCmd ( 
3889                         "Reply to Sender, Include",
3890                         GETMSG(DT_catd, 1, 61, "Reply to Sender, Include"), 
3891                         TRUE, 
3892                         this, 
3893                         TRUE ); 
3894
3895     _comp_replyAinclude= new ReplyAllCmd ( 
3896                         "Reply to All, Include",
3897                         GETMSG(DT_catd, 1, 62, "Reply to All, Include"), 
3898                         TRUE, 
3899                         this, 
3900                         TRUE ); 
3901
3902     
3903     // Compose Menu
3904     
3905     cmdList = new CmdList( "Compose", GETMSG(DT_catd, 1, 63, "Compose") );
3906     _comp_cmdlist = cmdList;
3907     cmdList->add(_comp_new);
3908     cmdList->add(_comp_new_include);
3909     cmdList->add(_comp_forward);
3910     cmdList->add(_comp_separator);
3911     cmdList->add(_comp_replySender);
3912     cmdList->add(_comp_replyAll);
3913     cmdList->add(_comp_replySinclude);
3914     cmdList->add(_comp_replyAinclude);
3915
3916     _menuBar->addCommands ( cmdList );
3917 }
3918
3919 // construct_move_menu() builds the Move menu on the menu bar.  
3920 // There is a user defined set of items at the top, the Inbox,
3921 // the "Mail Filing..." item, and a dynamic list of most recently
3922 // accessed containers at the bottom.
3923
3924 void
3925 RoamMenuWindow::construct_move_menu()
3926 {
3927     int                 ncontainers, i;
3928     char                *container_name;
3929     ContainerMenuCmd    *container_cmd;
3930
3931
3932     if (_move_cmdlist != NULL)
3933       delete _move_cmdlist;
3934     _move_cmdlist = new CmdList( "Move", GETMSG(DT_catd, 1, 64, "Move") );
3935
3936     _move_separator = new SeparatorCmd("Separator","Separator", TRUE );
3937
3938     _move_inbox = new MoveToInboxCmd(
3939                                 "Inbox",
3940                                 GETMSG(DT_catd, 1, 221, "Inbox"),
3941                                 TRUE, 
3942                                 this);
3943
3944     // We expect _move_copy_button to have been initialized already when
3945     // we constructed the copy menu.
3946     _move_other = new MoveCmd(
3947                                 GETMSG(DT_catd, 1, 90, "Move"),
3948                                 GETMSG(DT_catd, 1, 65, "Other Mailboxes..."),
3949                                 TRUE,
3950                                 this,
3951                                 (MoveCopyCmd *) _move_copy_button);
3952
3953     //
3954     // We will use _move_containerlist to keep track of the
3955     // static set of Move commands coming from the "filemenu2"
3956     // value.
3957     //
3958     ncontainers = _user_containerlist->length();
3959
3960     if (_move_containerlist != NULL)
3961       delete _move_containerlist;
3962     _move_containerlist = new DtVirtArray<ContainerMenuCmd *> (ncontainers);
3963
3964     for (i=0; i<ncontainers; i++)
3965     {
3966         container_name = (*_user_containerlist)[i]->containerName();
3967         if (NULL != container_name)
3968         {
3969             container_cmd = new ContainerMenuCmd(
3970                                                 strdup(container_name),
3971                                                 container_name,
3972                                                 TRUE,
3973                                                 this,
3974                                                 DTM_MOVE);
3975             _move_cmdlist->add(container_cmd);
3976             _move_containerlist->append(container_cmd);
3977         }
3978     }
3979
3980     // Move menu
3981     if (0 < ncontainers)
3982       _move_cmdlist->add(_move_separator);
3983     _move_cmdlist->add(_move_inbox);
3984
3985     _move_cmdlist->add(_move_other);
3986     _move_cmdlist->add(_move_separator);
3987
3988     //
3989     // We will use _move_containerlist_cached
3990     // to keep track of Move commands which get cached from
3991     // "Other Mailboxes..." operations from the Open, CopyTo, and Move menus.
3992     //
3993
3994     ncontainers = (_max_cached_list_size ? _max_cached_list_size : 1 );
3995
3996     if (_move_containerlist_cached != NULL)
3997       delete _move_containerlist_cached;
3998     _move_containerlist_cached =
3999       new DtVirtArray<ContainerMenuCmd *> (ncontainers);
4000     
4001     ncontainers = (_display_cached_list ? _cached_containerlist->length() : 0);
4002     for (i=0; i<ncontainers; i++)
4003     {
4004         container_name = (*_cached_containerlist)[i]->containerName();
4005         if (NULL != container_name)
4006         {
4007             container_cmd = new ContainerMenuCmd(
4008                                                 strdup(container_name),
4009                                                 container_name,
4010                                                 TRUE,
4011                                                 this,
4012                                                 DTM_MOVE);
4013             _move_cmdlist->add(container_cmd);
4014             _move_containerlist_cached->append(container_cmd);
4015         }
4016     }
4017
4018
4019     _moveMenu = _menuBar->addCommands(
4020                                 &_move_cascade, _move_cmdlist, 
4021                                 FALSE, XmMENU_BAR);
4022     XtVaSetValues(_moveMenu, 
4023                   XmNpacking, XmPACK_COLUMN, 
4024                   XmNorientation, XmVERTICAL,
4025                   NULL);
4026     XtAddCallback(_moveMenu, XmNmapCallback, &RoamMenuWindow::map_menu, NULL);
4027 }
4028
4029
4030 // Attachment menu
4031 void
4032 RoamMenuWindow::construct_attachment_menu()
4033 {
4034
4035     _att_save   = new SaveAttachCmd (
4036                                 "Save As...",
4037                                 GETMSG(DT_catd, 1, 66, "Save As..."),
4038                                 GETMSG(DT_catd, 1, 67, "Mailer - Attachments - Save As"),
4039                                 FALSE, 
4040                                 RoamMenuWindow::save_attachment_callback,
4041                                 this,
4042                                 this->baseWidget());
4043
4044     _att_select_all = new SelectAllAttachsCmd(
4045                                         "Select All",
4046                                         GETMSG(
4047                                             DT_catd, 1, 68, "Select All"
4048                                         ),
4049                                         this);
4050
4051     _att_cmdlist = new CmdList( 
4052                                         "Attachments",
4053                                         GETMSG(
4054                                                 DT_catd, 1, 69, 
4055                                                 "Attachments"
4056                                         ) 
4057                                 );
4058     _att_cmdlist->add(_att_save);
4059     _att_cmdlist->add(_att_select_all);
4060
4061     // Create a pulldown from the items in the list.  Retain a handle
4062     // to that pulldown since we need to dynamically add/delete entries 
4063     // to this menu based on the selection of attachments.
4064
4065     _attachmentMenu = _menuBar->addCommands(_att_cmdlist);
4066 }
4067
4068 void
4069 RoamMenuWindow::construct_attachment_popup(void)
4070 {
4071    _attPopup_cmdlist = new CmdList( "AttachmentsPopup", "AttachmentsPopup");
4072
4073     LabelCmd *title     = new LabelCmd (
4074                         "Mailer - Attachments",
4075                         GETMSG(DT_catd, 1, 70, "Mailer - Attachments"), TRUE);
4076     _attPopup_separator = new SeparatorCmd( "Separator","Separator", TRUE );
4077
4078     _attPopup_cmdlist->add(title);
4079     _attPopup_cmdlist->add(_attPopup_separator);
4080     _attPopup_cmdlist->add(_att_save);
4081     _attPopup_cmdlist->add(_att_select_all);
4082     _menuPopupAtt = new MenuBar(_my_editor->attachArea()->getClipWindow(), 
4083                                         "RoamAttachmentPopup", XmMENU_POPUP);
4084     _attachmentPopupMenu = _menuPopupAtt->addCommands(_attPopup_cmdlist, 
4085                                 FALSE, XmMENU_POPUP);
4086 }
4087
4088 void
4089 RoamMenuWindow::construct_help_menu()
4090 {
4091     FORCE_SEGV_DECL(CmdList, cmdList);
4092
4093     // Separator for menu items
4094     
4095     _help_separator= new SeparatorCmd( "Separator","Separator", TRUE );
4096     _help_overview = new OnAppCmd("Overview", GETMSG(DT_catd, 1, 71, "Overview"), 
4097                                 TRUE, this);
4098     _help_tasks = new TasksCmd("Tasks", GETMSG(DT_catd, 1, 72, "Tasks"), 
4099                                 TRUE, this);
4100     _help_reference = new ReferenceCmd("Reference",
4101                                 GETMSG(DT_catd, 1, 73, "Reference"), 
4102                                 TRUE, this);
4103     _help_on_item = new OnItemCmd("On Item", GETMSG(DT_catd, 1, 74, "On Item"), 
4104                                 TRUE, this);
4105     _help_using_help = new UsingHelpCmd("Using Help",
4106                                 GETMSG(DT_catd, 1, 75, "Using Help"), 
4107                                 TRUE, this);
4108     cmdList = new CmdList( "Help", GETMSG(DT_catd, 1, 76, "Help") );
4109     _help_cmdlist = cmdList;
4110
4111     cmdList->add ( _help_overview );
4112     cmdList->add ( _help_separator );
4113     cmdList->add ( _help_tasks );
4114     cmdList->add ( _help_reference );
4115     cmdList->add ( _help_separator );
4116     cmdList->add ( _help_on_item );
4117     cmdList->add ( _help_separator );
4118     cmdList->add ( _help_using_help );
4119     cmdList->add ( _help_separator );
4120
4121     _help_about_mailer = new RelNoteCmd("About Mailer...", 
4122                                     GETMSG(DT_catd, 1, 77, "About Mailer..."),
4123                                     TRUE, this);
4124     cmdList->add ( _help_about_mailer );
4125
4126     // Make help menu show up on right side of menubar.
4127     _menuBar->addCommands ( cmdList, TRUE );
4128     
4129 }
4130  
4131 void
4132 RoamMenuWindow::syncCachedContainerList(void)
4133 {
4134     RoamMenuWindow      *rmw = NULL;
4135
4136     rmw = theRoamApp.nextRoamMenuWindow(NULL);
4137     if (NULL == rmw)
4138       return;
4139
4140     // Sync the cached lists to an existing RoamMenuWindow.
4141     for (int i = rmw->_cached_containerlist->length(); i > 0; i--) {
4142         char *name = (*(rmw->_cached_containerlist))[i-1]->containerName();
4143         addToCachedContainerList(name);
4144     }
4145 }
4146
4147 DtMail::MailRc *
4148 RoamMenuWindow::get_mail_rc()
4149 {
4150     DtMailEnv error;
4151
4152     if (NULL == _mailbox) return NULL;
4153     return _mailbox->session()->mailRc(error);
4154 }
4155
4156
4157 void
4158 RoamMenuWindow::load_mailbox(
4159     DtMailEnv & mail_error
4160 )
4161 {
4162     int         count = 0;
4163     
4164     // If there is no mailbox, return.
4165     if (!_mailbox) {
4166         mail_error.clear();
4167         return;
4168     }
4169
4170     // Now load the messages into the scrolling list.
4171     // This will get the DtMailMessageHandles into the _msgs array and
4172     // it will also get their XmStrings into the CharArray of the _list.
4173     theRoamApp.busyAllWindows(GETMSG(DT_catd, 3, 27, "Loading..."));
4174         
4175     // Call load_headers() to get the XmStrings into the XmList!
4176
4177     count = _list->load_headers(mail_error);
4178     
4179     if (mail_error.isSet()) {
4180         // Return whatever error mailbox->get_next_msg() returned.
4181         theRoamApp.unbusyAllWindows();
4182         return;
4183     }
4184
4185     // If no messages
4186
4187     if (count == 0) {
4188         this->message(GETMSG(DT_catd, 3, 28, "Empty container"));
4189         setIconName(EmptyIcon);
4190     }
4191
4192     _list->sort_messages();
4193
4194     theRoamApp.unbusyAllWindows();
4195 }
4196
4197 void
4198 RoamMenuWindow::clear_message()
4199 {
4200     this->message("");
4201 }
4202
4203 void
4204 RoamMenuWindow::text_selected()
4205 {
4206
4207     // turn on sensitivity for Cut/Clear/Copy/Paste/Delete
4208
4209 }
4210
4211 void
4212 RoamMenuWindow::text_unselected()
4213 {
4214
4215     // turn off sensitivity for those items
4216
4217 }
4218
4219     // syncViewAndStore() does the sync-ing of the view of a mail
4220     // container and the storage of that container.
4221     // This method gets invoked every time a message gets expunged
4222     // by the back end based on "timed delete".
4223     // The method needs to then remove the expunged message from the
4224     // deleted messages list, thereby syncing the view to be always
4225     // current with the storage.
4226     // Similarly, the method also gets invoked when the container store
4227     // has received new mail.  The view then needs to be updated....
4228
4229
4230 DtMailBoolean
4231 RoamMenuWindow::syncViewAndStoreCallback(
4232     DtMailCallbackOp op,
4233     const char *path,
4234     const char *,       // prompt_hint
4235     void *client_data,  
4236     ...
4237 )
4238 {
4239
4240     DtMailBoolean bval;
4241     va_list args;
4242
4243     va_start(args, client_data);
4244     RoamMenuWindow * rmw = (RoamMenuWindow *)client_data;
4245
4246     bval = rmw->syncViewAndStore(op, path, args);
4247     
4248     va_end(args);
4249     return(bval);
4250 }
4251
4252 DtMailBoolean
4253 RoamMenuWindow::syncViewAndStore(
4254     DtMailCallbackOp op,
4255     const char *path,
4256     va_list args
4257 )
4258 {
4259
4260     DtMailEnv error;
4261     DtMailMessageHandle tmpMH;
4262     char *errmsg;
4263     int answer;
4264
4265
4266     this->busyCursor();
4267
4268     switch(op) {
4269       case DTMC_NEWMAIL:
4270
4271         // New mail has come in.  Load it in and update the
4272         // view's list of headers to also display it.
4273
4274         tmpMH = va_arg(args, DtMailMessageHandle);
4275         this->_list->load_headers(error, tmpMH);
4276
4277         newMailIndicators();
4278
4279         break;
4280
4281       case DTMC_DELETEMSG:
4282
4283         // A message has been expunged from the store by the back end.  
4284         // The expunge has been done based on "timed delete". 
4285         // Remove the expunged message from the displayed list of
4286         // message headers. 
4287         break;
4288
4289       case DTMC_BADSTATE:
4290
4291         errmsg = GETMSG(DT_catd, 1, 238, "Mailer is confused about the state of this mailbox.\nIt may be that another process has rewritten this mailbox in an unexpected way.\n\nSelecting OK will cause the Mailer to close and reopen the mailbox.\nNOTE that any changes made to the mailbox since the last save may be lost.");
4292         this->_genDialog->setToErrorDialog(
4293                                 GETMSG(DT_catd, 2, 10, "Mailer"),
4294                                 errmsg);
4295         answer = this->_genDialog->post_and_return(
4296                                 GETMSG(DT_catd, 3, 29, "OK"),
4297                                 DTMAILHELPUNKNOWNSTATE);
4298
4299         this->reopen_mail_file();
4300         if (DTM_TRUE)
4301           return(DTM_TRUE);
4302         break;
4303
4304       case DTMC_ACCESSFAILED:
4305         
4306         errmsg = GETMSG(DT_catd, 1, 239, "Mailer can no longer access this mailbox.\nIt may be that another process has deleted the mailbox file.\n\nSelecting OK will cause the Mailer to close and reopen the mailbox.\nNOTE that any changes made to the mailbox since the last save may be lost.\n\nSelecting CANCEL will leave the mailbox unchanged.");
4307         this->_genDialog->setToErrorDialog(
4308                                 GETMSG(DT_catd, 2, 10, "Mailer"),
4309                                 errmsg);
4310         answer = this->_genDialog->post_and_return(
4311                                 GETMSG(DT_catd, 3, 29, "OK"),
4312                                 GETMSG(DT_catd, 3, 19, "Cancel"),
4313                                 DTMAILHELPUNKNOWNSTATE);
4314         this->normalCursor();
4315         if (answer == 1)
4316         {
4317             this->reopen_mail_file();
4318             return(DTM_TRUE);
4319         }
4320         else
4321           return(DTM_FALSE);
4322         break;
4323
4324       case DTMC_SERVERPASSWORDNEEDED:
4325         
4326         {
4327             char *buffer = new char[2048];
4328             char *errmsgarg =   va_arg(args, char*);
4329
4330             sprintf(buffer, "%s", errmsgarg);
4331             this->_genDialog->setToTextFieldDialog(
4332                                 GETMSG(DT_catd, 2, 10, "Mailer"),
4333                                 buffer, DTM_TRUE);
4334             answer = this->_genDialog->post_and_return(
4335                                 GETMSG(DT_catd, 3, 29, "Ok"),
4336                                 GETMSG(DT_catd, 3, 19, "Cancel"),
4337                                 DTMAILHELPUNKNOWNSTATE);
4338             this->normalCursor();
4339             delete [] buffer;
4340             if (answer == 1)
4341             {
4342                 char            *password = NULL;
4343                 DtMailEnv       mail_error;
4344                 password = _genDialog->getTextFieldValue();
4345                 _mailbox->updateMailRetrievalPassword(password);
4346                 _mailbox->checkForMail(error);
4347                 if (NULL != password) free(password);
4348                 return(DTM_TRUE);
4349             }
4350             else
4351               return(DTM_FALSE);
4352         }
4353         break;
4354
4355       case DTMC_SERVERACCESSFAILED:
4356         
4357         {
4358             char *buffer = new char[2048];
4359             char *errmsgarg =   va_arg(args, char*);
4360
4361             errmsg = GETMSG(DT_catd, 1, 256, "Mail server access failed:\n%s");
4362
4363             sprintf(buffer, errmsg, errmsgarg);
4364             this->_genDialog->setToErrorDialog(
4365                                 GETMSG(DT_catd, 2, 10, "Mailer"),
4366                                 buffer);
4367             answer = this->_genDialog->post_and_return(
4368                                 GETMSG(DT_catd, 1, 257, "Options..."),
4369                                 GETMSG(DT_catd, 3, 19, "Cancel"),
4370                                 DTMAILHELPUNKNOWNSTATE);
4371             this->normalCursor();
4372             delete [] buffer;
4373             if (answer == 1)
4374             {
4375                 OptCmd  *optCmd = (OptCmd *) theRoamApp.mailOptions();
4376                 optCmd->displayMailRetrievalOptionsPane();
4377                 return(DTM_TRUE);
4378             }
4379             else
4380               return(DTM_FALSE);
4381         }
4382         break;
4383
4384       case DTMC_GETMAILCOMMANDFAILED:
4385         
4386         {
4387             char *buffer = new char[2048];
4388             char *errmsgarg =   va_arg(args, char*);
4389
4390             errmsg =
4391               GETMSG(DT_catd, 1, 258, "User Getmail command failed:\n%s");
4392
4393             sprintf(buffer, errmsg, errmsgarg);
4394             this->_genDialog->setToErrorDialog(
4395                                 GETMSG(DT_catd, 2, 10, "Mailer"),
4396                                 buffer);
4397             answer = this->_genDialog->post_and_return(
4398                                 GETMSG(DT_catd, 1, 257, "Options..."),
4399                                 GETMSG(DT_catd, 3, 19, "Cancel"),
4400                                 DTMAILHELPUNKNOWNSTATE);
4401             this->normalCursor();
4402             delete [] buffer;
4403             if (answer == 1)
4404             {
4405                 OptCmd  *optCmd = (OptCmd *) theRoamApp.mailOptions();
4406                 optCmd->displayMailRetrievalOptionsPane();
4407                 return(DTM_TRUE);
4408             }
4409             else
4410               return(DTM_FALSE);
4411         }
4412         break;
4413
4414       case DTMC_SERVERACCESSINFO:
4415         
4416         {
4417             char *infomsg = va_arg(args, char*);
4418             message(infomsg);
4419             return DTM_TRUE ;
4420         }
4421         break;
4422
4423       case DTMC_SERVERACCESSINFOERROR:
4424         
4425         {
4426             char *buffer = new char[2048];
4427             char *errmsgarg =   va_arg(args, char*);
4428
4429             sprintf(buffer, "%s", errmsgarg);
4430             this->_genDialog->setToErrorDialog(
4431                                 GETMSG(DT_catd, 2, 10, "Mailer"),
4432                                 buffer);
4433             answer = this->_genDialog->post_and_return(
4434                                 GETMSG(DT_catd, 1, 257, "Options..."),
4435                                 GETMSG(DT_catd, 3, 19, "Cancel"),
4436                                 DTMAILHELPUNKNOWNSTATE);
4437             this->normalCursor();
4438             delete [] buffer;
4439             if (answer == 1)
4440             {
4441                 OptCmd  *optCmd = (OptCmd *) theRoamApp.mailOptions();
4442                 optCmd->displayMailRetrievalOptionsPane();
4443                 return(DTM_TRUE);
4444             }
4445             else
4446               return(DTM_FALSE);
4447         }
4448         break;
4449
4450       case DTMC_INODECHANGED:
4451         
4452         errmsg = GETMSG(DT_catd, 1, 240, "Mailer can no longer access this mailbox.\nAnother process has rewritten the mailbox file changing the inode.\n\nSelecting OK will cause the Mailer to close and reopen the mailbox.\nNOTE that any changes made to the mailbox since the last save may be lost.\n\nSelecting CANCEL will leave the mailbox unchanged.");
4453
4454         this->_genDialog->setToErrorDialog(
4455                                 GETMSG(DT_catd, 2, 10, "Mailer"),
4456                                 errmsg);
4457         answer = this->_genDialog->post_and_return(
4458                                 GETMSG(DT_catd, 3, 29, "OK"),
4459                                 GETMSG(DT_catd, 3, 19, "Cancel"),
4460                                 DTMAILHELPUNKNOWNSTATE);
4461         this->normalCursor();
4462         if (answer == 1)
4463         {
4464             this->reopen_mail_file();
4465             return(DTM_TRUE);
4466         }
4467         else
4468           return(DTM_FALSE);
4469         break;
4470
4471       case DTMC_UNLOCK:
4472         
4473         // We are asked to save changes and close the file.
4474         // The backend will take care of unlocking the file.
4475         this->quit_silently();
4476         return(DTM_TRUE);
4477
4478       case DTMC_QUERYLOCK:
4479
4480         // The file is lock by another mailer.
4481         // Should we ask for the lock?
4482         _genDialog->setToQuestionDialog(GETMSG(DT_catd, 3, 16, "Mailer"),
4483            GETMSG(DT_catd, 3, 82, "Someone else is using this mailbox.\nWould you like to demand exclusive access?"));
4484         answer = _genDialog->post_and_return(GETMSG(DT_catd, 3, 18, "OK"),
4485            GETMSG(DT_catd, 3, 19, "Cancel"), DTMAILHELPTAKELOCK);
4486
4487         this->normalCursor();
4488         if (answer == 1) {
4489           return(DTM_TRUE);
4490         } else {
4491           return(DTM_FALSE);
4492         }
4493
4494     case DTMC_READONLY:
4495
4496       // We are not able to obtain a TT lock on this folder,
4497       // ask user if he wants to open it as read only.
4498       _genDialog->setToQuestionDialog(GETMSG(DT_catd, 3, 16, "Mailer"),
4499                                       GETMSG(DT_catd, 3, 83, "Mailer is unable to obtain exclusive access to this mailbox.\nWould you like to open this mailbox read-only?"));
4500         answer = _genDialog->post_and_return(GETMSG(DT_catd, 3, 18, "OK"),
4501                                              GETMSG(DT_catd, 3, 19, "Cancel"),
4502                                              DTMAILHELPOPENREADONLY);
4503         this->normalCursor();
4504         if (answer == 1) {
4505           return(DTM_TRUE);
4506         } else {
4507           return(DTM_FALSE);
4508         }
4509
4510     case DTMC_READWRITEOVERRIDE:
4511       // We are not able to obtain a lock on this folder,
4512       // ask user if he wants to open it as read only.
4513       _genDialog->setToQuestionDialog(GETMSG(DT_catd, 3, 16, "Mailer"),
4514                                       GETMSG(DT_catd, 3, 94, "Mailer is unable to obtain exclusive access to this\nmailbox because the system is not responding.\n\nFor this time only, you can choose to open this mailbox\nread-only, or to open it read-write without exclusive\naccess (use only if no one else is using this mailbox)."));
4515         answer = _genDialog->post_and_return(GETMSG(DT_catd, 3, 95, "Read-only"),
4516                                              GETMSG(DT_catd, 3, 19, "Cancel"),
4517                                              GETMSG(DT_catd, 3, 96, "Read-Write"), 
4518                                              DTMAILHELPOPENREADWRITEOVERRIDE);
4519         this->normalCursor();
4520         // Now the tricky part - since this method can only return 
4521         // DTM_TRUE or DTM_FALSE, we must have a way to indicate "readOnly",
4522         // "readWrite" or "cancel" - horrid hack: readOnly is DTM_FALSE, 
4523         // "readWrite" is DTM_TRUE, and "cancel" is (DTM_TRUE+DTM_FALSE)*2
4524         //
4525         switch (answer)
4526           {
4527           case 1:       // Read-only
4528             return(DTM_FALSE);
4529           case 3:       // Read-Write
4530             return(DTM_TRUE);
4531           default:      // cancel
4532             return((DtMailBoolean)((DTM_FALSE+DTM_TRUE)*2));
4533           }
4534
4535     case DTMC_DOTDTMAILLOCKFAILED:
4536
4537       {
4538         char *buffer            = new char[2048];
4539         char *lockpath          = va_arg(args, char*);
4540         char *errormsg          = va_arg(args, char*);
4541         char *cancel            = GETMSG(DT_catd, 3, 19, "Cancel");
4542         char *ok                = GETMSG(DT_catd, 3, 18, "OK");
4543         char *mailer            = GETMSG(DT_catd, 3, 16, "Mailer");
4544         char *msgfmt            = GETMSG(DT_catd, 3, 97, "%s\n\nThis may indicate that another Mailer has opened\n%s\n\nYou may open this mailbox READ ONLY by choosing '%s'.\n\nOtherwise, you may choose '%s',\nmake sure that another Mailer has not opened this mailbox,\ndelete %s,\nand reopen this mailbox.");
4545
4546         // We are not able to obtain a .dtmail lock on this folder,
4547         // ask user if he wants to open it as read only.
4548         sprintf(buffer, msgfmt, errormsg, path, ok, cancel, lockpath);
4549         _genDialog->setToQuestionDialog(mailer, buffer);
4550         answer =_genDialog->post_and_return(ok, cancel, DTMAILHELPOPENREADONLY);
4551         this->normalCursor();
4552         delete [] buffer;
4553         if (answer == 1) {
4554           return(DTM_TRUE);
4555         } else {
4556           return(DTM_FALSE);
4557         }
4558       }
4559
4560       default:
4561         this->normalCursor();
4562         return(DTM_FALSE);
4563     }
4564
4565     this->normalCursor();
4566     return(DTM_TRUE);
4567 }
4568
4569 // Convert the rfc file.
4570 // Commented out for PAR 5.  Needs to be uncommented out for PAR 6
4571 // and above.
4572
4573 void
4574 RoamMenuWindow::convert(
4575     char *,             // src
4576     char *              // dest
4577 )
4578 {
4579     // Obsoleted when Bento went away
4580 }
4581
4582 // The back end uses the return value to either continue conversion or
4583 // to stop converting.
4584
4585 int
4586 RoamMenuWindow::ConvertStatusCB(
4587     int current, 
4588     int total, 
4589     void * client_data
4590 )
4591 {
4592
4593     RoamMenuWindow *rmw = (RoamMenuWindow *)client_data;
4594
4595     // Return 0 if the conversion is still to proceed.
4596     // Return 1 if the conversion is to stop (e.g., if the user
4597     // has interrupted it...)
4598
4599     return(rmw->showConversionStatus(current, total));
4600 }
4601
4602 int
4603 RoamMenuWindow::showConversionStatus(
4604     int current, 
4605     int total
4606 )
4607 {
4608     char *buf, *str;
4609     int num_already_converted;  // num msgs already converted as set prev.
4610     int previously_complete;  // percent of converted msgs as set prev.
4611     int now_complete;  // percent of converted messages based on parameters
4612
4613     // Remember,  the number set may differ from the previous call to
4614     // this method.  We are not doing set_convert_data() for every call
4615     // to this method and so, what's set will differ from the previous
4616     // call to this method...
4617
4618     num_already_converted = _convertContainerCmd->get_num_converted();
4619     previously_complete = num_already_converted * 100 / total;
4620
4621     now_complete = current * 100 / total;
4622
4623     if ((now_complete > (previously_complete + 5)) ||
4624         (now_complete == 100)) {
4625         str = GETMSG(DT_catd, 1, 79, "Converting... %d percent complete"); 
4626         // Estimate 4 characters for numbers and 1 null terminator.
4627         buf = new char[strlen(str) + 5];   
4628         sprintf(buf, str, now_complete);
4629         
4630         _convertContainerCmd->updateDialog(buf);
4631         delete [] buf;
4632
4633         _convertContainerCmd->set_convert_data(current, total);
4634     }
4635     else {
4636         _convertContainerCmd->updateAnimation();
4637     }
4638
4639     // Check and see if the user had interrupted the conversion
4640     // If the user had interrupted, we need to stop the back-end
4641     // convert...
4642
4643     if (_convertContainerCmd->interrupted()) {
4644         return(1);
4645     }
4646     else {
4647         return(0);
4648     }
4649 }
4650
4651     
4652 void
4653 RoamMenuWindow::conversionFinishedCallback( 
4654     RoamInterruptibleCmd *,
4655     Boolean interrupted,
4656     void             *clientData
4657 )
4658 {
4659
4660     // Do something only it the conversion really finished.
4661     // If it was interrupted, just return...
4662
4663     if (!interrupted) {
4664         RoamMenuWindow *rmw = (RoamMenuWindow *) clientData;
4665         rmw->conversionFinished();
4666     }
4667 }
4668
4669 // If the conversion finished successfully, then we try to open() again
4670 // and if no problems, load the headers into the scrolling list...
4671
4672 void
4673 RoamMenuWindow::conversionFinished()
4674 {
4675     DtMailEnv mail_error;
4676
4677     // Initialize the mail_error.
4678     mail_error.clear();
4679
4680     mailboxFullpath(_convertContainerCmd->get_destination_name());
4681
4682     this->open(mail_error, 
4683                _openContainerCmd->_open_create_flag,
4684                _openContainerCmd->_open_lock_flag);
4685     
4686     // if the user had cancelled the open, then the RMW will not have
4687     // its mailbox set. Do not proceed to load the mailbox.  Return.
4688
4689     // Ideally, open() should set the mail_error if the user cancels
4690     // the open.  And we should check the mail_error here...
4691
4692     if (mail_error.isSet()) {
4693         return;
4694     }
4695
4696     this->load_mailbox(mail_error);
4697
4698     if (mail_error.isSet()) {
4699
4700         // Post a dialog indicating problems in loading...
4701     }
4702
4703 }
4704
4705
4706 // Post the dialog displaying the error text.
4707 // Also display the minor_code, if resource/environment variable
4708 // wants it.
4709 // User has no choice but to OK
4710 // postErrorDialog() is the benign uncle of postFatalErrorDialog() --
4711 // it does not quit the RMW.
4712
4713 void
4714 RoamMenuWindow::postErrorDialog(
4715     DtMailEnv &mail_error
4716 )
4717 {
4718     char *helpId;
4719
4720     const char *text_str = (const char *)mail_error;
4721
4722     // Assume that the char *text that comes in has already 
4723     // been processed for i18n.
4724
4725     _genDialog->setToErrorDialog(GETMSG(DT_catd, 2, 13, "Mailer"), 
4726                                  (char *)text_str);
4727     
4728     helpId = DTMAILHELPERROR;
4729     int i = _genDialog->post_and_return(GETMSG(DT_catd, 3, 31, "OK"), helpId);
4730
4731     // Clear the Error
4732     mail_error.clear();
4733
4734 }
4735
4736
4737 void
4738 RoamMenuWindow::manage()
4739 {
4740     Dimension win_x, win_y, win_wid, win_ht, win_bwid;
4741
4742     MainWindow::manage();
4743     XmUpdateDisplay(this->baseWidget());
4744     // Obtain the current dimensions of the RMW
4745
4746     XtVaGetValues(_w,
4747                   XmNx, &win_x,
4748                   XmNy, &win_y,
4749                   XmNwidth, &win_wid,
4750                   XmNheight, &win_ht,
4751                   XmNborderWidth, &win_bwid,
4752                   NULL);
4753
4754     _x = win_x;
4755     _y = win_y;
4756     _width = win_wid;
4757     _height = win_ht;
4758     _border_width = win_bwid;
4759
4760 }
4761
4762 void
4763 RoamMenuWindow::expunge(void)
4764 {
4765     DtMailEnv error;
4766     error.clear();
4767     
4768     // First order of business - busy out active windows
4769     //
4770     theRoamApp.busyAllWindows(
4771         GETMSG(DT_catd, 3, 32, "Destroying deleted messages..."));
4772
4773     // Before changing the state of any deleted/undeleted lists,
4774     // perform the destroy deleted operation and make sure that
4775     // it was successful - if there was an error, notify the user
4776     // and discontinue processing
4777     //
4778     _mailbox->expunge(error);
4779     if((DTMailError_t) error == DTME_OutOfSpace )
4780     {
4781        stopAutoSave();
4782        ShowErrMsg((char *)error.getClient(),FALSE,(void *)this );
4783        error.setClient(NULL);
4784        startAutoSave();
4785        theRoamApp.unbusyAllWindows();
4786        return;
4787     }
4788
4789     if (error.isSet()) {
4790         // An error happened - must inform the user
4791         //
4792         postErrorDialog(error);
4793         error.clear();
4794     }
4795     else {
4796         if (_msg_undelete_from_list->dialog())
4797           _msg_undelete_from_list->dialog()->expunge();
4798         
4799         _list->expunge();
4800     }
4801
4802     // Last order of business - unbusy out active windows
4803     //
4804     theRoamApp.unbusyAllWindows();
4805 }
4806
4807 void
4808 RoamMenuWindow::attachment_selected()
4809 {
4810     _att_save->activate();
4811 }
4812
4813
4814 void
4815 RoamMenuWindow::all_attachments_selected()
4816 {
4817     _att_save->deactivate();
4818
4819     if (_attActions_cmdlist != NULL) {
4820         _menuBar->removeCommands(_attachmentMenu, _attActions_cmdlist);
4821         _menuPopupAtt->removeCommands(_attachmentPopupMenu, 
4822                         _attActions_cmdlist);
4823         delete _attActions_cmdlist;
4824         _attActions_cmdlist = NULL;
4825     }
4826 }
4827
4828 void
4829 RoamMenuWindow::all_attachments_deselected()
4830 {
4831     _att_save->deactivate();
4832
4833     if (_attActions_cmdlist != NULL) {
4834         _menuBar->removeCommands(_attachmentMenu, _attActions_cmdlist);
4835         _menuPopupAtt->removeCommands(_attachmentPopupMenu, 
4836                                 _attActions_cmdlist);
4837         delete _attActions_cmdlist;
4838         _attActions_cmdlist = NULL;
4839     }
4840 }
4841
4842 void
4843 RoamMenuWindow::activate_default_message_menu()
4844 {
4845     
4846     _msg_open->activate();
4847
4848     _msg_save_as->activate();
4849
4850     XtSetSensitive(_copyto_cmdlist->getPaneWidget(), TRUE);
4851
4852     _msg_print->activate();
4853
4854     _msg_delete->activate();
4855
4856 }
4857
4858 void
4859 RoamMenuWindow::deactivate_default_message_menu()
4860 {
4861     
4862     _msg_open->deactivate();
4863
4864     _msg_save_as->deactivate();
4865
4866     XtSetSensitive(_copyto_cmdlist->getPaneWidget(), FALSE);
4867
4868     _msg_print->deactivate();
4869
4870     _msg_delete->deactivate();
4871
4872 }  
4873
4874 void
4875 RoamMenuWindow::activate_default_attach_menu()
4876 {
4877     _att_select_all->activate();
4878 }
4879
4880 void
4881 RoamMenuWindow::deactivate_default_attach_menu()
4882 {
4883     _att_select_all->deactivate();
4884 }
4885
4886 void
4887 RoamMenuWindow::newMailIndicators(void)
4888 {
4889     // Set to new mail icon only if the window is iconified
4890     if (this->isIconified()) {
4891         setIconName(NewMailIcon);
4892     }
4893
4894     if ((_we_called_newmail == FALSE) || (this->isIconified())){
4895
4896         // See if we are supposed to ring the bell.
4897         //
4898         DtMailEnv error;
4899         const char * val = NULL;
4900         DtMail::Session * m_session = theRoamApp.session()->session(); 
4901         m_session->mailRc(error)->getValue(error, "flash", &val);
4902         if (error.isNotSet()) {
4903             int flashes = (int) strtol(val, NULL, 10);
4904             flash(flashes);
4905         }
4906         if (NULL != val)
4907           free((void*) val);
4908
4909         val = NULL;
4910         m_session->mailRc(error)->getValue(error, "bell", &val);
4911         if (error.isNotSet()) {
4912             int beeps = (int) strtol(val, NULL, 10);
4913             while(beeps > 0) {
4914                 XBell(XtDisplay(baseWidget()), 0);
4915                 beeps -= 1;
4916             }
4917         }
4918         else // Default to 1 beep
4919             XBell(XtDisplay(baseWidget()), 0);
4920
4921         if (NULL != val)
4922           free((void*) val);
4923
4924         val = NULL;
4925         m_session->mailRc(error)->getValue(error, "realsound", &val);
4926         if (error.isNotSet()) {
4927             struct stat stat;
4928             if (SafeStat("/usr/bin/audioplay", &stat) == 0) {
4929                 char *play_str = new char[1500];
4930                 sprintf(play_str, "/usr/bin/audioplay %s", val);
4931                 system(play_str);
4932                 delete [] play_str;
4933             }
4934         }
4935
4936         if (NULL != val)
4937           free((void*) val);
4938     }
4939
4940     _we_called_newmail = FALSE;
4941 }
4942
4943 void
4944 RoamMenuWindow::save_attachment_callback(
4945     void *client_data,
4946     char *selection
4947 )
4948 {
4949
4950     RoamMenuWindow *obj = (RoamMenuWindow *) client_data;
4951     obj->save_selected_attachment(selection);
4952 }
4953
4954 void
4955 RoamMenuWindow::save_selected_attachment(
4956     char *selection
4957 )
4958 {
4959     DtMailEnv mail_error;
4960
4961     // Initialize the mail_error.
4962     mail_error.clear();
4963
4964     DtMailEditor *editor = this->get_editor();
4965     AttachArea *attacharea = editor->attachArea();
4966     Attachment *attachment = attacharea->getSelectedAttachment();
4967
4968    // Get selected attachment, if none selected, then return.
4969    if ( attachment == NULL ) {
4970           // Let User know that no attachment has been selected???
4971           int answer = 0;
4972           char *helpId = NULL;
4973
4974
4975           _genDialog->setToErrorDialog(
4976                     GETMSG(DT_catd, 1, 80, "Mailer"),             
4977                     GETMSG(DT_catd, 2, 14, "An attachment needs to be selected before issuing the\n\"Save As\" command to save to a file.") );
4978           helpId = DTMAILHELPSELECTATTACH;
4979           answer = _genDialog->post_and_return(
4980                         GETMSG(DT_catd, 3, 33, "OK"), helpId );
4981           return;
4982       }
4983
4984
4985     attachment->saveToFile(mail_error, selection);
4986
4987     if (mail_error.isSet()) {
4988         // do something
4989     }
4990
4991 }
4992
4993 void
4994 RoamMenuWindow::addAttachmentActions(
4995     char **actions,
4996     int indx
4997 )
4998 {
4999     int i;
5000     char *anAction;
5001     AttachmentActionCmd *attachActionCmd;
5002     
5003     if (_attActions_cmdlist == NULL) { 
5004         _attActions_cmdlist = new CmdList("AttachmentActions", "AttachmentActions");
5005     }
5006     else {
5007         _menuBar->removeCommands(_attachmentMenu, _attActions_cmdlist);
5008         _menuPopupAtt->removeCommands(_attachmentPopupMenu, 
5009                                 _attActions_cmdlist);
5010         delete _attActions_cmdlist;
5011         _attActions_cmdlist = new CmdList("AttachmentActions", "AttachmentActions");
5012     }
5013
5014     char *actionLabel;
5015     for (i = 0; i < indx; i++) {
5016         anAction = actions[i];
5017
5018         // Retrieve the localized action label
5019         actionLabel = DtActionLabel(anAction);
5020         attachActionCmd = new AttachmentActionCmd(
5021                                         anAction, 
5022                                         actionLabel,
5023                                         this,
5024                                         i);
5025         _attActions_cmdlist->add(attachActionCmd);
5026         
5027     }
5028     _attachmentMenu = _menuBar->addCommands(
5029                                 _attachmentMenu, 
5030                                 _attActions_cmdlist
5031                         );
5032     _attachmentPopupMenu = _menuPopupAtt->addCommands(
5033                                 _attachmentPopupMenu, 
5034                                 _attActions_cmdlist
5035                         );
5036 }
5037
5038 void
5039 RoamMenuWindow::removeAttachmentActions()
5040 {
5041
5042     // Stubbed out for now
5043 }
5044
5045 void
5046 RoamMenuWindow::invokeAttachmentAction(
5047     int index
5048 )
5049 {
5050
5051     DtMailEditor *editor = this->get_editor();
5052     AttachArea *attacharea = editor->attachArea();
5053     Attachment *attachment = attacharea->getSelectedAttachment();
5054
5055     attachment->invokeAction(index);
5056
5057 }
5058
5059 void
5060 RoamMenuWindow::selectAllAttachments()
5061 {
5062     
5063     DtMailEditor *editor = this->get_editor();
5064     AttachArea *attachArea = editor->attachArea();
5065     
5066     attachArea->selectAllAttachments();
5067
5068 }
5069
5070 // Returns the index of the match, -1 if there is no match.
5071 int
5072 RoamMenuWindow::inList(char *filename, DtVirtArray<ContainerMenuCmd *> *list)
5073 {
5074     ContainerMenuCmd *cmd;
5075
5076     if (list == NULL) return(-1);
5077
5078     if (filename &&
5079         *filename != '/' &&
5080         *filename != '.' && 
5081         *filename != '$' &&
5082         *filename != '~')
5083     { // relative path
5084         
5085         DtMail::Session * d_session = theRoamApp.session()->session();
5086         DtMailEnv error;
5087         DtMail::MailRc * mailrc = d_session->mailRc(error);
5088         const char *value = NULL;
5089         char *newname;
5090
5091         mailrc->getValue(error, "folder", &value);
5092         if (error.isNotSet())
5093         {
5094             newname = (char*)malloc(strlen(filename) + strlen(value) + 2);
5095             sprintf(newname, "%s/%s", value, filename);
5096             for (int i=0; i < list->length(); i++)
5097             {
5098                 cmd = (*list)[i];
5099                 if (strcmp(newname, cmd->containerName()) == 0) {
5100                     free(newname);
5101                     return(i);
5102                 }
5103             }
5104             free((void*) newname);
5105         }
5106
5107         if (NULL != value)
5108           free((void*) value);
5109     }
5110
5111     for (int i=0; i < list->length(); i++)
5112     {
5113         cmd = (*list)[i];
5114         if (filename && strcmp(filename, cmd->containerName()) == 0)
5115           return(i);
5116     }
5117     return(-1);
5118 }
5119
5120
5121 void
5122 RoamMenuWindow::addToCachedContainerList(char *filename)
5123 {
5124     int                 i, index;
5125     ContainerMenuCmd    *null_container, *open_container;
5126     ContainerMenuCmd    *move_container, *copy_container;
5127     char                *name;
5128
5129     if (filename != NULL &&
5130         *filename != '\0' &&
5131         (_max_cached_list_size > 0))
5132     {
5133         DtMail::Session *d_session = theRoamApp.session()->session();
5134         DtMailObjectSpace space;
5135         DtMailEnv       mail_error;
5136         int             is_inbox;
5137         char            *mail_file = NULL;
5138
5139         // Is the file in the user defined list?
5140         if ((index = inList(filename, _user_containerlist)) != -1)
5141           return;
5142
5143         d_session->queryImpl(
5144                         mail_error,
5145                         d_session->getDefaultImpl(mail_error),
5146                         DtMailCapabilityInboxName,
5147                         &space,
5148                         &mail_file);
5149
5150         is_inbox = (0 == strcmp(mail_file, filename));
5151         free((void*) mail_file);
5152         if (is_inbox)
5153           return;
5154
5155         // Is the file in the recently used list?
5156         if ((index = inList(filename, _cached_containerlist)) != -1)
5157         {
5158             // Move filename to top of list and move everything else down.
5159             if (index == 0) return;
5160
5161             //
5162             // Change the filenames that each of the Cmds points to in both
5163             // the move and copy cached lists.
5164             //
5165             name = (*_cached_containerlist)[index]->containerName();
5166
5167             for (i = index; i > 0; i--) {
5168                 char    *s = (*_cached_containerlist)[i-1]->containerName();
5169
5170                 (*_cached_containerlist)[i]->changeContainer(s);
5171                 (*_open_container_containerlist_cached)[i]->changeContainer(s);
5172                 (*_copyto_containerlist_cached)[i]->changeContainer(s);
5173                 (*_move_containerlist_cached)[i]->changeContainer(s);
5174             }
5175
5176             (*_cached_containerlist)[0]->changeContainer(name);
5177             (*_open_container_containerlist_cached)[0]->changeContainer(name);
5178             (*_copyto_containerlist_cached)[0]->changeContainer(name);
5179             (*_move_containerlist_cached)[0]->changeContainer(name);
5180
5181             //
5182             // Rename the labels in the menu.
5183             //
5184             if (_first_cached_item != _first_cached_item + index)
5185             {
5186                 _menuBar->rotateLabels(
5187                                 _opencontainerMenu,
5188                                 _first_cached_item,
5189                                 _first_cached_item + index);
5190                 _menuBar->rotateLabels(
5191                                 _copytoMenu,
5192                                 _first_cached_item,
5193                                 _first_cached_item + index);
5194                 _menuBar->rotateLabels(
5195                                 _moveMenu,
5196                                 _first_cached_item,
5197                                 _first_cached_item + index);
5198                 _menuBar->rotateLabels(
5199                                 _msgsPopupMoveMenu,
5200                                 _first_cached_item,
5201                                 _first_cached_item + index);
5202             }
5203          }
5204          else
5205          {
5206             // Add filename to Recently Used List.
5207             int cached_list_size = _cached_containerlist->length();
5208
5209             // Is there room for the menu to grow?
5210             if (cached_list_size < _max_cached_list_size)
5211             {
5212                 // Create the new command.
5213                 null_container = new ContainerMenuCmd(strdup(filename),
5214                                                         filename,
5215                                                         TRUE,
5216                                                         this,
5217                                                         DTM_NONE);
5218                 open_container = new ContainerMenuCmd(strdup(filename),
5219                                                         filename,
5220                                                         TRUE,
5221                                                         this,
5222                                                         DTM_OPEN);
5223                 copy_container = new ContainerMenuCmd(strdup(filename),
5224                                                         filename,
5225                                                         TRUE,
5226                                                         this,
5227                                                         DTM_COPY);
5228                 move_container = new ContainerMenuCmd(strdup(filename),
5229                                                         filename,
5230                                                         TRUE,
5231                                                         this,
5232                                                         DTM_MOVE);
5233
5234                 // Add it to the end of the arrays.
5235                 _cached_containerlist->append(null_container);
5236                 _open_container_containerlist_cached->append(open_container);
5237                 _copyto_containerlist_cached->append(copy_container);
5238                 _move_containerlist_cached->append(move_container);
5239
5240                 // Add it to the end of the menus.
5241                 _menuBar->addCommand(_opencontainerMenu, open_container);
5242                 _menuBar->addCommand(_copytoMenu, copy_container);
5243                 _menuBar->addCommand(_moveMenu, move_container);
5244                 _menuBar->addCommand(_msgsPopupMoveMenu, move_container);
5245
5246                 // Recursively call addToCachedContainerList to rotate to top.
5247                 cached_list_size = _cached_containerlist->length();
5248                 if (cached_list_size > 1)
5249                   addToCachedContainerList(filename);
5250             }
5251             else
5252             {
5253                 // Add new entry to the bottom of the cache.
5254                 int     i = cached_list_size-1;
5255                 char    *s = filename;
5256                 
5257                 // Replace the end of the arrays.
5258                 (*_cached_containerlist)[i]->changeContainer(strdup(s));
5259                 (*_open_container_containerlist_cached)[i]->changeContainer(
5260                                                                 strdup(s));
5261                 (*_copyto_containerlist_cached)[i]->changeContainer(strdup(s));
5262                 (*_move_containerlist_cached)[i]->changeContainer(strdup(s));
5263
5264                 // Replace the end of the menus.
5265                 i += _first_cached_item;
5266                 _menuBar->changeLabel(_opencontainerMenu, i, s);
5267                 _menuBar->changeLabel(_copytoMenu, i, s);
5268                 _menuBar->changeLabel(_moveMenu, i, s);
5269                 _menuBar->changeLabel(_msgsPopupMoveMenu, i, s);
5270
5271                 // Recursively call addToCachedContainerList to rotate to top.
5272                 if (_first_cached_item != i)
5273                   addToCachedContainerList(filename);
5274             }
5275         }
5276     }
5277 }
5278
5279 void
5280 RoamMenuWindow::showAttachArea()
5281 {
5282     DtMailEditor *editor = this->get_editor();
5283     editor->showAttachArea();
5284 }
5285
5286 void
5287 RoamMenuWindow::hideAttachArea()
5288 {
5289     DtMailEditor *editor = this->get_editor();
5290     editor->hideAttachArea();
5291 }
5292
5293 void
5294 RoamMenuWindow::fullHeader(
5295     Boolean state
5296 )
5297 {
5298     DtMailMessageHandle msgHandle;
5299     DtMailEnv mail_error;
5300
5301     // Initialize the mail_error.
5302     mail_error.clear();
5303
5304     _full_header_resource = state;
5305     
5306     msgHandle = this->list()->current_msg_handle();
5307     if (msgHandle) {
5308         this->list()->display_message(mail_error, msgHandle);
5309     }
5310
5311 }
5312
5313 void 
5314 RoamMenuWindow::postMsgsPopup(XEvent *event)
5315 {
5316         XmMenuPosition(_msgsPopupMenu, (XButtonEvent *)event);
5317         XtManageChild(_msgsPopupMenu);
5318 }
5319
5320 void
5321 RoamMenuWindow::MenuButtonHandler(
5322     Widget ,
5323     XtPointer cd,
5324     XEvent *event,
5325     Boolean *)
5326 {
5327         RoamMenuWindow *obj = (RoamMenuWindow *)cd;
5328
5329         if(event->xany.type != ButtonPress)
5330                 return;
5331
5332         XButtonEvent *be = (XButtonEvent *)event;
5333
5334         if(be->button == theApplication->bMenuButton())
5335                 obj->postMsgsPopup(event);
5336 }
5337
5338 void
5339 RoamMenuWindow::attachmentFeedback(
5340     Boolean bval
5341 )
5342 {
5343     if (bval) {
5344         this->busyCursor();
5345     }
5346     else {
5347         this->normalCursor();
5348     }
5349 }
5350
5351 // map_menu is used to figure out how many columns to split the menu
5352 // into.  It is a callback that is called when the menu is mapped.
5353 // If the menu is over half the height of the screen, it figures out
5354 // how many columns to make the menu, and sets its XmNnumColumns
5355 // attribute to that value.  It calculates the maximum number of columns
5356 // that would fit and never goes beyond that number.
5357
5358 void
5359 RoamMenuWindow::map_menu(
5360                     Widget menu, 
5361                     XtPointer,
5362                     XtPointer)
5363 {
5364         Position y;
5365         Dimension h, w;
5366         short   maxcols, newcols, columns;
5367         int     screenheight = HeightOfScreen(XtScreen(menu));
5368         int     fudgefact = 20; /* to allow for decorations on menu */
5369  
5370         XtVaGetValues(menu,
5371         XmNheight, &h,
5372         XmNwidth, &w,
5373         XmNy, &y,
5374         XmNnumColumns, &columns,
5375         NULL);
5376  
5377  
5378         if ((int) (h + fudgefact) > ((int) screenheight / 2)) {
5379  
5380         /* the menu is taller than half the screen.  We need to find out how
5381            many more columns to specify for the menu to make it fit. */
5382  
5383                 newcols = (columns * (int) ((int) (h + fudgefact)/(int) (screenheight/2))) + 1;
5384                 maxcols = WidthOfScreen(XtScreen(menu))/(int) ((int)w/(int)columns);
5385  
5386                 if (newcols > maxcols)
5387                         newcols = maxcols;
5388  
5389                 XtVaSetValues(menu, XmNnumColumns, newcols, NULL);
5390
5391         }
5392  
5393
5394 }
5395
5396
5397 void
5398 RoamMenuWindow::setTitle(char *suffix)
5399 {
5400     DtMailEnv           mail_error;
5401     MailSession         *ses = theRoamApp.session();
5402     DtMail::Session     *d_session = ses->session();
5403     char *prefix = GETMSG(DT_catd, 1, 6, "Mailer");
5404     char *path = NULL;
5405     char *new_title;
5406     char *format;
5407     int   len;
5408
5409     if (mailbox_fullpath())
5410       path = d_session->getRelativePath(mail_error, mailbox_fullpath());
5411     else if (mailboxName())
5412       path = d_session->getRelativePath(mail_error, mailboxName());
5413     else path = strdup("UNTITLED");
5414
5415     if (suffix)
5416     {
5417         format = "%s - %s [%s]";
5418         len = strlen(format) + strlen(prefix) + strlen(path) + strlen(suffix);
5419         new_title = new char[len];
5420         sprintf(new_title, format, prefix, path, suffix);
5421     }
5422     else
5423     {
5424         format = "%s - %s";
5425         len = strlen(format) + strlen(prefix) + strlen(path);
5426         new_title = new char[len];
5427         sprintf(new_title, format, prefix, path);
5428     }
5429
5430     title(new_title);
5431     delete [] new_title; 
5432     free(path);
5433 }
5434
5435 void
5436 RoamMenuWindow::setVacationTitle()
5437 {
5438     // Add "[Vacation]" to the title of the roam menu window 
5439     char *vacation = GETMSG(DT_catd, 1, 3, "Vacation");
5440     setTitle(vacation);
5441 }
5442
5443 void
5444 RoamMenuWindow::removeVacationTitle()
5445 {
5446     // Reset the title on the roam menu window; take out "[Vacation]"
5447     setTitle(NULL);
5448 }
5449
5450 void
5451 RoamMenuWindow::ShowErrMsg(char * fsname,Boolean compose,void *client_data)
5452 {
5453 Widget parent=NULL;
5454   assert((NULL != fsname));
5455   if(!compose)
5456   {
5457     RoamMenuWindow * self = (RoamMenuWindow *)client_data;
5458     parent = self->GetMainWin();
5459   }
5460   else
5461   {
5462     SendMsgDialog * self = (SendMsgDialog *)client_data;
5463     parent = self->GetMainWin();
5464   }
5465     if(!parent)
5466             parent = theApplication->baseWidget();
5467             DtMailGenDialog *genDialog = new DtMailGenDialog("Dialog",parent,XmDIALOG_FULL_APPLICATION_MODAL);
5468
5469             char *errMsg = (char *) XtCalloc(1,10240+strlen(fsname));
5470
5471
5472                 // Serious error here -- No Space on Filesystem --
5473                 sprintf(errMsg,"Insufficient space on %s filesystem. Dtmail unable to show any new \n messages, delete messages, or save further changes to the open \n mailbox. Please contact your System Administrator to correct the \n filesystem space problem.",fsname);
5474             free(fsname);
5475             genDialog->setToErrorDialog(
5476                                 GETMSG(DT_catd, 1, 6, "Mailer"),
5477                                 errMsg);
5478             XtFree(errMsg);
5479
5480             genDialog->post_and_return(
5481                                 GETMSG(DT_catd, 3, 9, "OK"),
5482                                 NULL);
5483             delete genDialog;
5484 }
5485 void
5486 RoamMenuWindow::stopAutoSave(void)
5487 {
5488     DtMailEnv error;
5489     _mailbox->startAutoSave(error,DTM_FALSE);
5490 }
5491 void
5492 RoamMenuWindow::startAutoSave(void)
5493 {
5494     DtMailEnv error;
5495     _mailbox->startAutoSave(error,DTM_TRUE);
5496 }
5497
5498 void
5499 RoamMenuWindow::sync_work_area_size(void)
5500 {
5501     Dimension width, height;
5502
5503     XtVaGetValues(_workArea, XmNwidth, &width, XmNheight, &height, NULL);
5504
5505     if (_workarea_width && _workarea_height &&
5506         (_workarea_width!=width || _workarea_height!=height))
5507     {
5508         enableWorkAreaResize();
5509         XtVaSetValues(_workArea, XmNwidth, width, XmNheight, height, NULL);
5510         disableWorkAreaResize();
5511     }
5512     _workarea_width = width;
5513     _workarea_height = height;
5514 }