Last of the spelling fixed
[oweals/cde.git] / cde / programs / dtmail / dtmail / RoamCmds.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: RoamCmds.C /main/43 1999/07/13 08:41:44 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 <errno.h>
72 #include <signal.h>
73 #include <ctype.h>
74 #include <string.h>
75 #include <sys/param.h>
76 #include <sys/stat.h>
77 #include <sys/types.h>
78 #include <unistd.h>
79 #include <stdint.h>
80 #include <pwd.h>
81 #include <X11/Intrinsic.h>
82 #include <Xm/Text.h>
83 #include <Xm/FileSBP.h>
84 #include <Xm/FileSB.h>
85 #include <Xm/PushB.h>
86 #include <Xm/ToggleB.h>
87 #include <Xm/PushBG.h>
88 #include <Xm/PanedW.h>
89 #include <Xm/Form.h>
90 #include <Dt/Dts.h>
91 #include <Dt/Action.h>
92 #include <Dt/Help.h>
93 #include <Dt/DtPStrings.h>
94
95 #include <DtMail/IO.hh>
96 #include <DtMail/DtMailError.hh>
97 #ifndef __ppc
98 #include <DtMail/Buffer.hh>
99 #endif
100 #ifdef __ppc
101 #include <DtMail/Buffer.hh>
102 #endif
103 #include <DtMail/OptCmd.h>
104 #include <EUSCompat.h>
105 #include "EUSDebug.hh"
106 #include "Application.h"
107 #include "AttachArea.h"
108 #include "Attachment.h"
109 #include "Dmx.h"
110 #include "DmxPrintJob.h"
111 #include "DtMailEditor.hh"
112 #include "DtMailGenDialog.hh"
113 #include "DtMailHelp.hh"
114 #include "DtMailWDM.hh"
115 #include "FindDialog.h"
116 #include "Help.hh"
117 #include "MailMsg.h"
118 #include "MemUtils.hh"
119 #include "MsgScrollingList.hh"
120 #include "MsgHndArray.hh"
121 #include "RoamApp.h"
122 #include "RoamCmds.h"
123 #include "RoamMenuWindow.h"
124 #include "SendMsgDialog.h"
125 #include "Undelete.hh"
126
127 #if defined(NEED_MMAP_WRAPPER)
128 extern "C" {
129 #endif
130 #include <sys/mman.h>
131 #if defined(NEED_MMAP_WRAPPER)
132 }
133 #endif
134
135 extern "C" {
136 extern XtPointer _XmStringUngenerate (
137                                 XmString string,
138                                 XmStringTag tag,
139                                 XmTextType tag_type,
140                                 XmTextType output_type);
141 }
142
143
144 #include <sys/file.h>
145
146
147 extern void forceUpdate( Widget );
148
149 RoamCmd::RoamCmd
150 (char *name, char *label, int active, RoamMenuWindow *window)
151 : NoUndoCmd (name, label, active)
152 {
153     _menuwindow = window;
154 }
155
156 #ifdef DEAD_WOOD
157 SearchCmd::SearchCmd(
158                      char *name, 
159                      char *label,
160                      int active, 
161                      RoamMenuWindow *window
162                      ) : InterruptibleCmd (name, label, active)
163 {
164     _menuwindow = window;
165     _criteria = NULL;
166 }
167
168 void
169 SearchCmd::execute ( 
170                      TaskDoneCallback callback, 
171                      void *clientData 
172                      )
173 {
174     InterruptibleCmd::execute( callback, clientData );
175 }
176
177 void
178 SearchCmd::execute()
179 {
180     
181     _menuwindow->list()->clearMsgs();
182     _menuwindow->busyCursor();
183     
184     if ( !_criteria ) {
185         _criteria=( char * )realloc(_criteria, strlen( this->name()) + 1);
186         strcpy(_criteria, this->name());
187     }
188     
189     InterruptibleCmd::execute();
190 }
191
192 void
193 SearchCmd::doit()
194 {
195     int         count;
196     DtMailEnv   mail_error;
197     
198     // Initialize the mail_error.
199     mail_error.clear();
200     
201     MsgScrollingList *list=_menuwindow->list();
202     
203     
204     // load_headers will retrieve all of the message headers and
205     // add the handles to the list.
206     //
207     count = list->load_headers(mail_error);
208     
209     _menuwindow->normalCursor();
210     
211     if (count == 0) {
212         _menuwindow->message(GETMSG(DT_catd, 3, 46, "Empty container"));
213         _done = TRUE;
214         return;
215     }
216     
217     list->scroll_to_bottom();
218     _done=TRUE;
219 }      
220
221 void
222 SearchCmd::undoit()
223 {
224     // Just print a message that allows us to trace the execution
225     
226     DebugPrintf(1, "%s: undoit\n", name());
227 }       
228
229 void
230 SearchCmd::updateMessage (char *msg)
231 {
232     InterruptibleCmd::updateMessage(msg);
233 }
234 #endif /* DEAD_WOOD */
235
236 CheckForNewMailCmd::CheckForNewMailCmd( 
237                                         char *name, 
238                                         char *label,
239                                         int active, 
240                                         RoamMenuWindow *window
241                                         ) :  NoUndoCmd ( name, label, active )
242 {
243     _menuwindow = window;
244 }
245
246 void
247 CheckForNewMailCmd::doit()
248 {
249     DtMailEnv error;
250     // Initialize the mail_error.
251     error.clear();
252     _menuwindow->checkForMail(error);
253     
254 }
255
256 OpenInboxCmd::OpenInboxCmd(
257     char *name,
258     char *label,
259     int active,
260     RoamMenuWindow *rmw
261 ) : Cmd (name, label, active)
262 {
263
264     _menuWindow = rmw;
265     
266 }
267
268 void
269 OpenInboxCmd::doit()
270 {
271     RoamMenuWindow *rmw = theRoamApp.inboxWindow();
272
273     if (rmw)
274     {
275         MailSession *ses = theRoamApp.session();
276         ses->activateRMW(rmw);
277         rmw->manage();
278     }
279     else
280     {
281         DtMailEnv       mail_error;
282         char            *mail_file = NULL;
283         DtMailObjectSpace space;
284         DtMail::Session *d_session = theRoamApp.session()->session();
285
286         mail_error.clear();
287         d_session->queryImpl(mail_error,
288                          d_session->getDefaultImpl(mail_error),
289                          DtMailCapabilityInboxName,
290                          &space,
291                          &mail_file);
292
293         // Check for error
294         if (mail_file) _menuWindow->view_mail_file(mail_file, DTM_FALSE);
295     }
296 }
297
298 void
299 OpenInboxCmd::undoit()
300 {
301 }
302
303 // 
304 // OpenContainerCmd methods implementation.
305 // For the most part, we treat container->open() as a benign thing.
306 // The magic, as we see it, deals with converting the container 
307 // if necessary.  
308 // For OpenContainerCmd, if no conversion is necessary bingo! it opens.
309 // If conversion is necessary, it punts the work to ConvertContainerCmd.
310 //
311 //
312
313 OpenContainerCmd::OpenContainerCmd (
314                                     char *name, 
315                                     char *label,
316                                     int active, 
317                                     RoamMenuWindow *window
318                                 ) : RoamInterruptibleCmd (name, label, active)
319 {
320     _menuWindow = window;
321     _open_create_flag = DTM_FALSE;
322     _open_lock_flag = DTM_FALSE;
323 }
324
325 // Parent's execute() ends up calling derived class's doit()
326 void
327 OpenContainerCmd::execute()
328 {
329     RoamInterruptibleCmd::execute();
330 }
331
332 void
333 OpenContainerCmd::execute( 
334                            RoamTaskDoneCallback rtd_callback, 
335                            void *clientData
336                            )
337 {
338     RoamInterruptibleCmd::execute(rtd_callback, clientData);
339 }
340
341 // Tell the RMW to open.  The RMW may end up calling its convert()
342 // which depends on ConvertContainerCmd's doit...
343 // By the time RMW->open() returns, the conversion would have
344 // been done too.
345 // This is the case of a RinterruptibleCmd derived class
346 // getting its work done in its doit() in one call.
347 //
348
349 void
350 OpenContainerCmd::doit()
351 {
352     DtMailEnv error;
353     
354     assert(_menuWindow != NULL);
355     
356     // Initialize the mail_error.
357     error.clear();
358     
359     _menuWindow->open(error, _open_create_flag, _open_lock_flag);
360     if (error.isSet()) {
361         // Post a dialog indicating error and exit?
362         return;         // for now. Should exit instead?
363     }
364     _done = TRUE;
365 }      
366
367 void
368 OpenContainerCmd::undoit()
369 {
370     // Just print a message that allows us to trace the execution
371     
372     DebugPrintf(1, "%s: undoit\n", name());
373 }       
374
375 void
376 OpenContainerCmd::check_if_done()
377 {
378     // Have nothing fancy to do here.  Since we do not want a dialog
379     // in any case, set it to true...
380     
381     _done = TRUE;
382     
383 }
384
385
386 void
387 OpenContainerCmd::post_dialog()
388 {
389     // Empty.  We don't want a dialog on open...
390 }
391
392 void
393 OpenContainerCmd::unpost_dialog()
394 {
395     // Empty.  We don't post, and we don't unpost.
396 }
397 void
398 OpenContainerCmd::updateMessage (char *msg)
399 {
400     RoamInterruptibleCmd::updateMessage(msg);
401 }
402
403 void
404 OpenContainerCmd::set_create_lock_flags(
405                                         DtMailBoolean create,
406                                         DtMailBoolean lock
407                                         )
408 {
409     _open_create_flag = create;
410     _open_lock_flag   = lock;
411 }
412
413
414 // ConvertContainerCmd
415 // Here be dragons!
416
417 ConvertContainerCmd::ConvertContainerCmd(
418                                          char *name, 
419                                          char *label,
420                                          int active, 
421                                          RoamMenuWindow *window
422                                  ) : RoamInterruptibleCmd (name, label, active)
423 {
424     _menuWindow = window;
425     _num_converted = 0;
426     _num_to_be_converted = 0;
427     _dialog = NULL;
428     _criteria = NULL;
429     _conv_cb = NULL;
430     _src = NULL;
431     _dest = NULL;
432 }
433
434 void
435 ConvertContainerCmd::execute()
436 {
437     if (!_dialog) {
438         _dialog = new DtMailWDM("Convert");
439     }
440     
441     RoamInterruptibleCmd::execute();
442 }
443
444 void
445 ConvertContainerCmd::execute ( RoamTaskDoneCallback rtd_callback, 
446                                void *clientData)
447 {
448     if (!_dialog) {
449         _dialog = new DtMailWDM("Convert");
450     }
451     
452     RoamInterruptibleCmd::execute(rtd_callback, clientData);
453 }
454
455 // Here be bigger dragons!
456 // The doit() calls the session->convert().
457 // And returns right away!
458 // the ses->convert() however ends up calling the conv_cb for every
459 // message that it has converted.
460 // So, we now have two loops working in parallel:
461 // 1) the parent()'s execute() class which called this doit() and is now
462 //    calling check_if_done() periodically via its workProc;
463 // 2) the session->convert() which is calling the _conv_cb() for every
464 //    message that it converts.  In the _conv_cb(), we do the following:
465 //    a) force update the dialog and see if it was interrupted;
466 //    b) if not interrupted, set_convert_data() where we set _done if 
467 //       we are really done.
468 //  
469
470 void
471 ConvertContainerCmd::doit()
472 {
473     assert(_menuWindow != NULL);
474     
475     MailSession *ses = theRoamApp.session();
476     DtMailEnv mail_error;
477     
478     // Initialize the mail_error.
479     mail_error.clear();
480     
481 //    ses->convert(mail_error, _src, _dest, _conv_cb, _menuWindow);
482     
483     if (mail_error.isSet()) {
484         _menuWindow->postErrorDialog(mail_error);
485     }
486 }      
487
488 void
489 ConvertContainerCmd::set_convert_data(
490                                       int converted,
491                                       int to_be_converted
492                                       )
493 {
494     _num_converted = converted;
495     _num_to_be_converted = to_be_converted;
496     
497     if ((_num_converted == _num_to_be_converted) && !_interrupted) {
498         _done = TRUE;
499     }
500 }
501
502 int
503 ConvertContainerCmd::get_num_converted()
504 {
505     return(_num_converted);
506 }
507
508
509 void
510 ConvertContainerCmd::check_if_done()
511 {
512     if (_interrupted) {
513         _done = FALSE;
514     }
515     else if (_num_converted == _num_to_be_converted) {
516         _done = TRUE;
517     }
518 }
519
520 void
521 ConvertContainerCmd::updateDialog(
522                                   char *msg
523                                   )
524 {
525     forceUpdate(_dialog->baseWidget());
526     _dialog->updateDialog( msg );  
527 }
528
529 void
530 ConvertContainerCmd::updateAnimation()
531 {
532     forceUpdate(_dialog->baseWidget());
533     _dialog->updateAnimation();
534 }
535
536 void
537 ConvertContainerCmd::post_dialog()
538 {
539     Dimension x, y, wid, ht;
540     
541     char * buf = new char[25];
542     
543     sprintf(buf, "Converted: %3d%%", 0);
544     
545     _dialog->post ("Mailer",
546                    buf,
547                    _menuWindow->baseWidget(),
548                    (void *) this,
549                    NULL, 
550                    &RoamInterruptibleCmd::interruptCallback );
551     
552     XtVaGetValues(_dialog->baseWidget(),
553                   XmNx, &x,
554                   XmNy, &y,
555                   XmNwidth, &wid,
556                   XmNheight, &ht,
557                   NULL);
558     
559 }
560
561 void
562 ConvertContainerCmd::unpost_dialog()
563 {
564     _dialog->unpost();
565 }
566
567 void
568 ConvertContainerCmd::undoit()
569 {
570     // Just print a message that allows us to trace the execution
571     
572     DebugPrintf(1, "%s: undoit\n", name());
573 }       
574
575 void
576 ConvertContainerCmd::set_data(
577                               char *path1,
578                               char *path2,
579                               ConversionStatusCB cb
580                               )
581 {
582     _src = path1;
583     _dest = path2;
584     _conv_cb = cb;
585 }
586
587 char *
588 ConvertContainerCmd::get_destination_name()
589 {
590     return _dest;
591 }
592
593 // Here be sheep!
594 // FindCmd
595
596 FindCmd::FindCmd( 
597                   char *name, 
598                   char *label,
599                   int active,
600                   RoamMenuWindow *window 
601                   ) : RoamCmd ( name, label, active, window )
602 {
603 }
604
605 void
606 FindCmd::doit()
607 {
608     
609     _menuwindow->get_find_dialog();
610     
611 //  SearchCmd::doit();
612     
613 }
614
615
616 ChooseCmd::ChooseCmd( 
617                       char *name, 
618                       char *label,
619                       int active, 
620                       RoamMenuWindow *window
621                       ) :  NoUndoCmd( name, label, active )
622 {
623     _menuwindow = window;
624     _msgno = NULL;
625 }
626
627 void
628 ChooseCmd::doit()
629 {
630     
631 }
632
633 SelectAllCmd::SelectAllCmd(
634                             char *name,
635                             char *label,
636                             int active,
637                             RoamMenuWindow *window
638                             ) : Cmd ( name, label, active )
639 {
640     _menuwindow = window;
641 }
642
643 void
644 SelectAllCmd::doit()
645 {
646     DtMailEnv mail_error;
647
648     _menuwindow->list()->select_all_and_display_last(mail_error);
649 }
650
651 void
652 SelectAllCmd::undoit()
653 {
654 }
655
656
657 DeleteCmd::DeleteCmd( 
658                       char *name, 
659                       char *label,
660                       int active, 
661                       RoamMenuWindow *window
662                       ) :  Cmd ( name, label, active )
663 {
664     _menuwindow = window;
665     _msgno = NULL;
666 }
667
668 void
669 DeleteCmd::doit()
670 {
671     _menuwindow->list()->deleteSelected(FALSE);
672     
673 }
674
675 void
676 DeleteCmd::undoit()
677 {
678     
679 }
680
681 DestroyCmd::DestroyCmd(
682                         char *name, 
683                         char *label, 
684                         int active, 
685                         RoamMenuWindow *window
686                         ) : Cmd(name, label, active)
687 {
688     _menuwindow = window;
689 }
690
691 void
692 DestroyCmd::doit()
693 {
694     // Call Expunge only if there are deleted messages.
695
696     if (_menuwindow->list()->get_num_deleted_messages()) {
697         _menuwindow->expunge();
698     }
699 }
700
701 void
702 DestroyCmd::undoit()
703 {
704 }
705
706 // Unified Select File Cmd stuff
707 int   UnifiedSelectFileCmd::_is_initialized = 0;
708 char *UnifiedSelectFileCmd::_unified_directory = NULL;
709 char *UnifiedSelectFileCmd::_unified_file = NULL;
710 int   UnifiedSelectFileCmd::_unified_hidden = 0;
711 int   UnifiedSelectFileCmd::_unify_selection = 1;
712
713 UnifiedSelectFileCmd::UnifiedSelectFileCmd ( 
714                                         char   *name, 
715                                         char   *label,
716                                         char   *title,
717                                         char   *ok_label,
718                                         int    active, 
719                                         FileCallback
720                                                select_callback,
721                                         void   *client_data,
722                                         Widget parent)
723 :SelectFileCmd (name,
724                 label,
725                 title,
726                 ok_label,
727                 active,
728                 unifiedFileSelectedCB,
729                 this,
730                 unifiedFileCanceledCB,
731                 this,
732                 parent)
733 {
734    if (! _is_initialized)
735    {
736        FORCE_SEGV_DECL(DtMail::Session, m_session);
737        DtMailEnv        error;
738        const char       *dirname = NULL;
739        const char       *expanded_dirname = NULL;
740        const char       *value = NULL;
741        char             *full_dirname = NULL;
742
743        _unified_directory = NULL;
744        _unified_file = NULL;
745        _unified_hidden = 0;
746        _unify_selection = 1;
747        _is_initialized = 1;
748
749        m_session = theRoamApp.session()->session();
750
751        error.clear();
752        m_session->mailRc(error)->getValue(error, "filefolder", &dirname);
753        if (error.isSet()) {
754            dirname = strdup("~");
755            error.clear();
756        }
757        expanded_dirname = m_session->expandPath(error, dirname);
758        _unified_directory = XtNewString(expanded_dirname);
759
760        error.clear();
761        m_session->mailRc(error)->getValue(
762                                         error,
763                                         "dontunifyfileselection",
764                                         &value);
765        if (! error.isSet())
766          _unify_selection = 0;
767
768        free((void*) dirname);
769        free((void*) expanded_dirname);
770        free((void*) value);
771    }
772
773    _select_file_callback = select_callback;
774    _select_file_client_data = client_data;
775    _genDialog = new DtMailGenDialog("Dialog", parent);
776 }
777
778 UnifiedSelectFileCmd::~UnifiedSelectFileCmd()
779 {
780     if (_genDialog) delete _genDialog;
781 }
782
783 void
784 UnifiedSelectFileCmd::doit()
785 {
786     if (NULL == _fileBrowser)
787     {
788         SelectFileCmd::doit();
789         if (NULL != _unified_directory)
790           setDirectory(_unified_directory);
791         if (NULL != _unified_file)
792           setSelected(_unified_file);
793         setHidden(_unified_hidden);
794     }
795     else
796     {
797         if (_unify_selection)
798         {
799             if (NULL != _unified_directory)
800               setDirectory(_unified_directory);
801             if (NULL != _unified_file)
802               setSelected(_unified_file);
803             setHidden(_unified_hidden);
804         }
805         SelectFileCmd::doit();
806     }
807 }
808
809 void
810 UnifiedSelectFileCmd::unifiedFileSelectedCB(void *client_data, char *selection)
811 {
812     UnifiedSelectFileCmd *self = (UnifiedSelectFileCmd *) client_data;
813
814     if (NULL != self)
815     {
816         self->updateUnifiedData();
817         self->unifiedFileSelected(selection);
818     }
819 }
820
821 void
822 UnifiedSelectFileCmd::unifiedFileSelected(char *selection)
823 {
824     DtMailEnv   error;
825
826     SafePathIsAccessible(error, selection);
827     if (error.isSet())
828     {
829         const char *errmsg = NULL;
830         char *err;
831         int answer;
832
833         errmsg = (const char*) error;
834         err = strdup(errmsg);
835
836         _genDialog->setToErrorDialog(GETMSG(DT_catd, 3, 48, "Mailer"), err);
837         answer = _genDialog->post_and_return(DTMAILHELPERROR);
838         if (1 == answer) doit();
839         if (err) free(err);
840         return;
841     }
842
843     if (_select_file_callback)
844       _select_file_callback(_select_file_client_data, selection);
845 }
846
847 void
848 UnifiedSelectFileCmd::unifiedFileCanceledCB(void *client_data, char *)
849 {
850     UnifiedSelectFileCmd *self = (UnifiedSelectFileCmd *) client_data;
851
852     if (NULL != self)
853       self->updateUnifiedData();
854 }
855
856 void
857 UnifiedSelectFileCmd::updateUnifiedData()
858 {
859     if (! _unify_selection)
860       return;
861
862     if (NULL != _unified_file)
863       XtFree(_unified_file);
864     _unified_file = getSelected();
865
866
867     if (NULL != _unified_directory)
868       XtFree(_unified_directory);
869     _unified_directory = getDirectory();
870
871     _unified_hidden = getHidden();
872 }
873
874 // Unified Select Mailbox Cmd stuff
875 int   UnifiedSelectMailboxCmd::_is_initialized = 0;
876 char *UnifiedSelectMailboxCmd::_unified_directory = NULL;
877 char *UnifiedSelectMailboxCmd::_unified_file = NULL;
878 int   UnifiedSelectMailboxCmd::_unified_hidden = 0;
879 int   UnifiedSelectMailboxCmd::_unify_selection = 1;
880
881 UnifiedSelectMailboxCmd::UnifiedSelectMailboxCmd ( 
882                                         char   *name, 
883                                         char   *label,
884                                         char   *title,
885                                         char   *ok_label,
886                                         int    active, 
887                                         FileCallback
888                                                select_callback,
889                                         void   *client_data,
890                                         Widget parent,
891                                         DtMailBoolean only_show_mailboxes)
892 :SelectFileCmd (name,
893                 label,
894                 title,
895                 ok_label,
896                 active,
897                 unifiedMailboxSelectedCB,
898                 this,
899                 unifiedMailboxCanceledCB,
900                 this,
901                 parent)
902 {
903    _only_show_mailboxes = DTM_FALSE;
904
905    if (! _is_initialized)
906    {
907        FORCE_SEGV_DECL(DtMail::Session, m_session);
908        DtMailEnv         error;
909        const char       *dirname = NULL;
910        const char       *expanded_dirname = NULL;
911        const char       *value = NULL;
912        char             *full_dirname = NULL;
913
914        _unified_directory = NULL;
915        _unified_file = NULL;
916        _unified_hidden = 0;
917        _unify_selection = 1;
918        _is_initialized = 1;
919        _only_show_mailboxes = only_show_mailboxes;
920
921        m_session = theRoamApp.session()->session();
922
923        error.clear();
924        m_session->mailRc(error)->getValue(error, "folder", &dirname);
925        if (error.isSet()) {
926            dirname = strdup("~");
927            error.clear();
928        }
929        expanded_dirname = m_session->expandPath(error, dirname);
930        _unified_directory = XtNewString(expanded_dirname);
931
932        error.clear();
933        m_session->mailRc(error)->getValue(
934                                         error,
935                                         "dontunifyfileselection",
936                                         &value);
937        if (! error.isSet())
938          _unify_selection = 0;
939
940        free((void*) dirname);
941        free((void*) expanded_dirname);
942        free((void*) value);
943    }
944
945    _select_file_callback = select_callback;
946    _select_file_client_data = client_data;
947    _genDialog = new DtMailGenDialog("Dialog", parent);
948 }
949
950 UnifiedSelectMailboxCmd::~UnifiedSelectMailboxCmd()
951 {
952     if (_genDialog) delete _genDialog;
953 }
954
955 void
956 UnifiedSelectMailboxCmd::doit()
957 {
958     if (NULL == _fileBrowser)
959     {
960         SelectFileCmd::doit();
961         if (NULL != _unified_directory)
962           setDirectory(_unified_directory);
963         if (NULL != _unified_file)
964           setSelected(_unified_file);
965         setHidden(_unified_hidden);
966
967         if (_fileBrowser)
968           XtVaSetValues(
969                 _fileBrowser,
970                 XmNfileSearchProc,
971                 UnifiedSelectMailboxCmd::unifiedMailboxSearchProc,
972                 NULL);
973     }
974     else
975     {
976         if (_unify_selection)
977         {
978             if (NULL != _unified_directory)
979               setDirectory(_unified_directory);
980             if (NULL != _unified_file)
981               setSelected(_unified_file);
982             setHidden(_unified_hidden);
983         }
984         SelectFileCmd::doit();
985     }
986 }
987
988 extern "C" {
989 extern void     _XmOSBuildFileList(
990                         String dirPath,
991                         String pattern,
992 #if NeedWidePrototypes
993                         unsigned int typeMask,
994 #else
995                         unsigned char typeMask,
996 #endif /* NeedWidePrototypes */
997                         String **pEntries,
998                         unsigned int *pNumEntries,
999                         unsigned int *pNumAlloc);
1000
1001 extern int      _XmOSFileCompare(const void *sp1, const void *sp2);
1002 extern char     *_XmStringGetTextConcat(XmString string);
1003 }
1004
1005 void
1006 UnifiedSelectMailboxCmd::unifiedMailboxSearchProc(
1007                                         Widget w,
1008                                         XtPointer sd)
1009 {   
1010     XmFileSelectionBoxWidget fs =
1011                                 (XmFileSelectionBoxWidget) w;
1012     XmFileSelectionBoxCallbackStruct * searchData =
1013                                 (XmFileSelectionBoxCallbackStruct *) sd;
1014     String          dir;
1015     String          pattern;
1016     Arg             args[3];
1017     int             Index;
1018     String *        fileList;
1019     unsigned int    numFiles;
1020     unsigned int    numItems = 0;
1021     unsigned int    numAlloc;
1022     XmString *      XmStringFileList;
1023     unsigned        dirLen;
1024     XtEnum          fileFilterStyle, pathMode;
1025     unsigned char   fileTypeMask;
1026
1027     if (!(dir = _XmStringGetTextConcat(searchData->dir)))
1028       return ;
1029     
1030     if (!(pattern = _XmStringGetTextConcat(searchData->pattern)))
1031     {
1032         XtFree(dir);
1033         return;
1034     } 
1035     fileList = NULL;
1036
1037     XtVaGetValues(
1038                 w,
1039                 XmNfileTypeMask, &fileTypeMask,
1040                 XmNfileFilterStyle, &fileFilterStyle,
1041                 XmNpathMode, &pathMode,
1042                 NULL);
1043
1044     _XmOSBuildFileList(
1045                 dir, pattern, fileTypeMask,
1046                 &fileList,  &numFiles, &numAlloc);
1047
1048     if (fileList && numFiles)
1049     {
1050         Boolean showDotFiles = (fileFilterStyle == XmFILTER_NONE);
1051
1052         if (numFiles > 1)
1053           qsort((void*) fileList, numFiles, sizeof(char*), _XmOSFileCompare);
1054         
1055         XmStringFileList = (XmString*) XtMalloc(numFiles*sizeof(XmString));
1056         
1057         Index = 0;
1058         dirLen = strlen(dir);
1059
1060         while (Index < numFiles)
1061         {
1062             Boolean     isMailBox = 0;
1063             char        *dataType = NULL;
1064
1065             dataType = DtDtsFileToDataType(fileList[Index]);
1066             if (dataType)
1067               isMailBox = (0 == strcmp(dataType, "DTMAIL_FILE"));
1068             DtDtsFreeDataType(dataType);
1069
1070             if (isMailBox &&
1071                 (showDotFiles || ((fileList[Index])[dirLen] != '.')) )
1072             {   
1073                 if (pathMode ==  XmPATH_MODE_FULL)
1074                   XmStringFileList[numItems++] = 
1075                         XmStringGenerate(fileList[Index],
1076                                          XmFONTLIST_DEFAULT_TAG,
1077                                          XmCHARSET_TEXT, NULL);
1078                 else 
1079                   XmStringFileList[numItems++] = 
1080                         XmStringGenerate(&(fileList[Index])[dirLen],
1081                                          XmFONTLIST_DEFAULT_TAG,
1082                                          XmCHARSET_TEXT, NULL) ;
1083             } 
1084             ++Index ;
1085         } 
1086
1087         /* Update the list.
1088         */
1089         Index = 0 ;
1090         XtVaSetValues(
1091                 w,
1092                 XmNfileListItemCount, numItems,
1093                 XmNfileListItems, XmStringFileList,
1094                 XmNlistUpdated, TRUE,
1095                 NULL);
1096
1097         Index = numFiles;
1098         while(Index--)
1099           XtFree( fileList[Index]);
1100
1101         while(numItems--)
1102           XmStringFree(XmStringFileList[numItems]);
1103
1104         XtFree((char*) XmStringFileList);
1105     }
1106     else
1107     {
1108         XtVaSetValues(
1109                 w,
1110                 XmNfileListItemCount, 0,
1111                 XmNfileListItems, NULL,
1112                 XmNlistUpdated, TRUE,
1113                 NULL);
1114     } 
1115
1116     XtFree((char *) fileList);
1117     XtFree(pattern);
1118     XtFree(dir);
1119     return;
1120 }
1121
1122 void
1123 UnifiedSelectMailboxCmd::unifiedMailboxSelectedCB(
1124                                         void *client_data,
1125                                         char *selection)
1126 {
1127     UnifiedSelectMailboxCmd *self = (UnifiedSelectMailboxCmd *) client_data;
1128
1129     if (NULL != self)
1130     {
1131         self->updateUnifiedData();
1132         self->unifiedMailboxSelected(
1133                                 self->_select_file_callback,
1134                                 self->_select_file_client_data,
1135                                 selection);
1136     }
1137 }
1138
1139 void
1140 UnifiedSelectMailboxCmd::unifiedMailboxSelected(
1141                                                 FileCallback    cb,
1142                                                 void            *client_data,
1143                                                 char            *selection)
1144 {
1145     DtMailEnv   error;
1146
1147     SafePathIsAccessible(error, selection);
1148     if (error.isSet())
1149     {
1150         const char *errmsg = NULL;
1151         char *err = NULL;
1152         int answer;
1153
1154         errmsg = (const char*) error;
1155         err = strdup(errmsg);
1156
1157         _genDialog->setToErrorDialog(GETMSG(DT_catd, 3, 48, "Mailer"), err);
1158         answer = _genDialog->post_and_return(DTMAILHELPERROR);
1159         if (1 == answer) doit();
1160         if (err) free(err);
1161         return;
1162     }
1163
1164     updateUnifiedData();
1165     if (cb) cb(client_data, selection);
1166 }
1167
1168 void
1169 UnifiedSelectMailboxCmd::unifiedMailboxCanceledCB(void *client_data, char *)
1170 {
1171     UnifiedSelectMailboxCmd *self = (UnifiedSelectMailboxCmd *) client_data;
1172
1173     if (NULL != self)
1174       self->updateUnifiedData();
1175 }
1176
1177 void
1178 UnifiedSelectMailboxCmd::updateUnifiedData()
1179 {
1180     if (! _unify_selection)
1181       return;
1182
1183     if (NULL != _unified_file)
1184       XtFree(_unified_file);
1185     _unified_file = getSelected();
1186
1187
1188     if (NULL != _unified_directory)
1189       XtFree(_unified_directory);
1190     _unified_directory = getDirectory();
1191
1192     _unified_hidden = getHidden();
1193 }
1194
1195 ContainerMenuCmd::ContainerMenuCmd(
1196     char *name,
1197     char *label,
1198     int active,
1199     RoamMenuWindow *window,
1200     ContainerOp op
1201 ) : RoamCmd ( name, label, active, window )
1202 {
1203     _menuwindow = window;
1204     _container_name = name;
1205     _operation = op;
1206 }
1207
1208 void
1209 ContainerMenuCmd::doit()
1210 {
1211     DtMailEnv mail_error;
1212
1213     // Initialize mail_error.
1214     mail_error.clear();
1215
1216     theRoamApp.busyAllWindows(GETMSG(DT_catd, 3, 15, "Saving..."));
1217     _menuwindow->mailbox()->save();
1218     theRoamApp.unbusyAllWindows();
1219
1220     switch (_operation)
1221     {
1222         case DTM_NONE:
1223             break;
1224         case DTM_OPEN:
1225             _menuwindow->view_mail_file(_container_name, DTM_FALSE);
1226             break;
1227         case DTM_COPY:
1228             _menuwindow->list()->copySelected(
1229                                         mail_error,
1230                                         _container_name,
1231                                         FALSE, FALSE);
1232             if (mail_error.isSet())
1233             {
1234                 // We had an error in copying the message to a container!
1235             }
1236             break;
1237         case DTM_MOVE:
1238             _menuwindow->list()->copySelected(
1239                                         mail_error,
1240                                         _container_name,
1241                                         TRUE, FALSE);
1242             if (mail_error.isSet())
1243             {
1244                 // We had an error in moving the message to a container!
1245             }
1246             break;
1247     }
1248 }
1249
1250 ContainerMenuCmd::~ContainerMenuCmd()
1251 {
1252 }
1253
1254     
1255 // Move the messages that are selected in the RoamMenuWindow to the Inbox.
1256 MoveToInboxCmd::MoveToInboxCmd(
1257                                char *name,
1258                                char *label,
1259                                int active,
1260                                RoamMenuWindow *window
1261                                ) : RoamCmd (name, label, active, window)
1262 {
1263     _menuwindow = window;
1264 }
1265
1266 void
1267 MoveToInboxCmd::doit()
1268 {
1269     DtMailEnv mail_error;
1270     
1271     // Initialize mail_error.
1272     mail_error.clear();
1273     
1274     // Get a handle to the Inbox.
1275     char * mail_file = NULL;
1276     DtMailObjectSpace space;
1277     DtMail::Session * d_session = theRoamApp.session()->session();
1278     
1279     d_session->queryImpl(mail_error,
1280                          d_session->getDefaultImpl(mail_error),
1281                          DtMailCapabilityInboxName,
1282                          &space,
1283                          &mail_file);
1284     _menuwindow->list()->copySelected(mail_error, mail_file, TRUE, FALSE);
1285     if (mail_error.isSet()) {
1286         // We had an error in moving the messages to the Inbox!
1287     }
1288 }
1289
1290 MoveToInboxCmd::~MoveToInboxCmd()
1291 {
1292 }
1293
1294 // Copy the selected messages to the Inbox.
1295 CopyToInboxCmd::CopyToInboxCmd(
1296                              char *name,
1297                              char *label,
1298                              int active,
1299                              RoamMenuWindow *window
1300                              ) : RoamCmd (name, label, active, window)
1301 {
1302     _menuwindow = window;
1303 }
1304  
1305 void
1306 CopyToInboxCmd::doit()
1307 {
1308     DtMailEnv mail_error;
1309  
1310     // Initialize mail_error.
1311     mail_error.clear();
1312  
1313     // Get a handle to the Inbox.
1314     char * mail_file = NULL;
1315     DtMailObjectSpace space;
1316     DtMail::Session * d_session = theRoamApp.session()->session();
1317  
1318     d_session->queryImpl(mail_error,
1319                          d_session->getDefaultImpl(mail_error),
1320                          DtMailCapabilityInboxName,
1321                          &space,
1322                          &mail_file);
1323     _menuwindow->list()->copySelected(mail_error, mail_file, FALSE, FALSE);
1324     if (mail_error.isSet()) {
1325         // We ad an error in copying the messages to the Inbox!
1326     }
1327 }
1328
1329 CopyToInboxCmd::~CopyToInboxCmd()
1330 {
1331 }
1332
1333
1334 // This is hooked up the Undelete button in the Deleted
1335 // Messages List dialog box.
1336
1337 DoUndeleteCmd::DoUndeleteCmd( 
1338                               char *name, 
1339                               char *label,
1340                               int active, 
1341                               UndelFromListDialog *undelDialog
1342                               ) :  Cmd ( name, label, active )
1343 {
1344     _undelDialog = undelDialog;
1345 }
1346
1347 void
1348 DoUndeleteCmd::doit()
1349 {
1350     // Undelete the selected messages.
1351     _undelDialog->undelSelected();
1352 }
1353
1354 void
1355 DoUndeleteCmd::undoit()
1356 {
1357     // nothing
1358 }
1359
1360 DoUndeleteCmd::~DoUndeleteCmd()
1361 {
1362 }
1363
1364 // This is hooked up to the Close button in the Deleted Messages
1365 // List dialog box.
1366
1367 CloseUndelCmd::CloseUndelCmd( 
1368                               char *name, 
1369                               char *label,
1370                               int active,
1371                               UndelFromListDialog *undelDialog
1372                               ) :  Cmd ( name, label, active )
1373 {
1374     _undelDialog = undelDialog;
1375 }
1376
1377 void
1378 CloseUndelCmd::doit()
1379 {
1380     // Close the dialog.
1381     _undelDialog->popped_down();
1382 }
1383
1384 void
1385 CloseUndelCmd::undoit()
1386 {
1387     // nothing
1388 }
1389
1390
1391 CloseUndelCmd::~CloseUndelCmd()
1392 {
1393 }
1394
1395 UndeleteCmd::UndeleteCmd ( 
1396                            char *name, 
1397                            char *label,
1398                            int active, 
1399                            RoamMenuWindow *window,
1400                            Boolean viaDeleteList
1401                            ) : ChooseCmd  ( name, label, active, window )
1402 {
1403     _menuwindow = window;
1404     _undelFromList = NULL;
1405     _fromList = viaDeleteList;
1406     _clientData = NULL;
1407     _num_deleted = 0;
1408 }
1409
1410 UndeleteCmd::~UndeleteCmd()
1411 {
1412 }
1413
1414 void
1415 UndeleteCmd::doit()
1416 {
1417     FORCE_SEGV_DECL(MsgStruct, tmpMS);
1418     MsgScrollingList *list = _menuwindow->list();
1419     MsgHndArray *deleted_messages;
1420     DtMailEnv mail_error;
1421     
1422     // Initialize the mail_error.
1423     mail_error.clear();
1424     
1425     
1426     if (_fromList) {
1427         // Create the Deleted Messages Dialog
1428         
1429         if (_undelFromList) {
1430             // Hack for user testing.  If the dialog is up, we destroy it.
1431             XtDestroyWidget(_undelFromList->baseWidget());
1432         }
1433 //      if (!_undelFromList) {
1434         _undelFromList = new UndelFromListDialog(
1435                          GETMSG(DT_catd, 1, 227, "Mailer - Deleted Messages"), 
1436                          _menuwindow);  
1437         _undelFromList->initialize();
1438         
1439         // Check for existing list of deleted messages
1440         _num_deleted = list->get_num_deleted_messages();
1441         
1442         // If there are deleted messages, put them in the Deleted
1443         // Messages List.
1444         
1445         if (_num_deleted > 0) {
1446             deleted_messages = list->get_deleted_messages();
1447             _undelFromList->loadMsgs(
1448                                 mail_error, 
1449                                 deleted_messages, 
1450                                 _num_deleted);
1451             if (mail_error.isSet()) {
1452                 // Post an exception here!
1453                 _menuwindow->postErrorDialog(mail_error);
1454             }
1455                 
1456         }
1457         // Display the dialog
1458         
1459         _undelFromList->popped_up();
1460     } else {
1461         // Although we don't display the Deleted Message Dialog here, we
1462         // need to make sure that it gets updated for the next time
1463         // we bring it up.
1464         list->undelete_last_deleted();
1465     }
1466 }
1467
1468
1469 #ifdef DEAD_WOOD
1470 SaveCmd::SaveCmd ( char *name, 
1471                    char *label, 
1472                    int active, 
1473                    RoamMenuWindow *window 
1474                 ) : RoamCmd ( name, label, active, window )
1475 {
1476     
1477 }
1478
1479 void
1480 SaveCmd::doit()
1481 {
1482     
1483     assert(_menuwindow->mailbox() != NULL);
1484 }
1485 #endif /* DEAD_WOOD */
1486
1487
1488
1489 MoveCopyCmd::MoveCopyCmd( char *name, 
1490                           char *label,
1491                           int active, 
1492                           FileCallback move_callback, 
1493                           FileCallback copy_callback, 
1494                           RoamMenuWindow * menu_window,
1495                           Widget parent,
1496                           DtMailBoolean only_show_mailboxes)
1497 : UnifiedSelectMailboxCmd(name,
1498                           label,
1499                           GETMSG(DT_catd, 1, 89, "Mailer - Other Mailboxes"),
1500                           "Move",
1501                           active, 
1502                           move_callback, 
1503                           menu_window,
1504                           parent,
1505                           only_show_mailboxes)
1506 {
1507     _copy_callback = copy_callback;
1508     _menuwindow = menu_window;
1509     _copy_button = NULL;
1510     _move_button = NULL;
1511     _file_list = NULL;
1512     _file_text = NULL;
1513     _default_button = NULL;
1514 }
1515
1516 MoveCopyCmd::~MoveCopyCmd()
1517 {
1518 }
1519
1520 void
1521 MoveCopyCmd::setDefault(Widget button)
1522 {
1523     Arg args[1];
1524
1525     _default_button = button;
1526     XtSetArg( args[0], XmNdefaultButton, _default_button );
1527     XtSetValues( _fileBrowser, args, 1 );
1528 }
1529
1530 void
1531 MoveCopyCmd::doit()
1532 {
1533     XmString move;
1534     Widget filter_button;
1535     Widget unused_button;
1536     Widget action_area;
1537     DtMailEnv error;
1538     
1539     if (!_fileBrowser) {
1540         UnifiedSelectMailboxCmd::doit();
1541         // Customize buttons for MoveCopy dialog
1542         move = XmStringCreateLocalized(GETMSG(DT_catd, 1, 90, "Move"));
1543         
1544         filter_button = XtNameToWidget(_fileBrowser, "*Apply");
1545         _move_button = XtNameToWidget(_fileBrowser, "*OK");
1546         action_area = XtParent(_move_button);
1547         unused_button = XtVaCreateWidget(
1548                         "Unused Button",
1549                         xmPushButtonWidgetClass, _fileBrowser,
1550                         NULL);
1551         _copy_button = XtVaCreateManagedWidget(
1552                         GETMSG(DT_catd, 1, 237, "Copy"),
1553                         /*xmPushButtonWidgetClass, _fileBrowser,*/
1554                         xmPushButtonGadgetClass, _fileBrowser,
1555                         XmNlabelString,
1556                         XmStringCreateLocalized(GETMSG(DT_catd, 1, 43, "Copy")),
1557                         NULL);
1558         printHelpId("Copy", _copy_button);
1559         //
1560         // add help callback
1561         // XtAddCallback(_copy_button, XmNhelpCallback, HelpCB, helpId);
1562         //
1563         XtAddCallback(
1564                 _copy_button,
1565                 XmNhelpCallback, 
1566                 HelpCB,
1567                 (void *)"dtmailViewmainWindowWork-AreapanedWform2RowColumnMoveCopy");
1568         XtAddCallback(
1569                 _copy_button,
1570                 XmNactivateCallback,
1571                 &MoveCopyCmd::fileSelectedCallback2,
1572                 (XtPointer) this );
1573
1574         if (_menuwindow->mailbox()->mailBoxWritable(error) == DTM_FALSE)
1575           XtUnmanageChild(_move_button);
1576         else
1577           XtManageChild(_move_button);
1578
1579 //  XtVaSetValues(_move_button, XmNsensitive, FALSE);
1580
1581         _file_list = XtNameToWidget(_fileBrowser, "*ItemsList");
1582         XtAddCallback(
1583                 _file_list,
1584                 XmNbrowseSelectionCallback, &MoveCopyCmd::setDefaultButtonCB,
1585                 (XtPointer) this);
1586         XtAddCallback(
1587                 _file_list,
1588                 XmNextendedSelectionCallback, &MoveCopyCmd::setDefaultButtonCB,
1589                 (XtPointer) this);
1590         XtAddCallback(
1591                 _file_list,
1592                 XmNmultipleSelectionCallback, &MoveCopyCmd::setDefaultButtonCB,
1593                 (XtPointer) this);
1594         XtAddCallback(
1595                 _file_list,
1596                 XmNsingleSelectionCallback, &MoveCopyCmd::setDefaultButtonCB,
1597                 (XtPointer) this);
1598
1599         _file_text = XtNameToWidget(_fileBrowser, "*Text");
1600         if (NULL != _file_text)
1601           XtAddCallback(
1602                 _file_text,
1603                 XmNfocusCallback, &MoveCopyCmd::setDefaultButtonCB,
1604                 (XtPointer) this);
1605
1606         XmStringFree(move);
1607
1608     } else {
1609         UnifiedSelectMailboxCmd::doit();
1610     }
1611     
1612 }
1613
1614 void
1615 MoveCopyCmd::fileSelectedCallback2 ( 
1616                                      Widget     ,
1617                                      XtPointer  clientData,
1618                                      XtPointer  callData
1619                                      )
1620 {
1621     MoveCopyCmd *obj = (MoveCopyCmd *) clientData;
1622     XmFileSelectionBoxCallbackStruct *cb =
1623                 (XmFileSelectionBoxCallbackStruct *) callData;
1624     char        *name = NULL;
1625     char        *dir_str = NULL;
1626     char        *fname = NULL;
1627     char        *dname = NULL;
1628     int         status = 0;
1629     XmString    xmstr;
1630     
1631     static char selected[MAXPATHLEN+1];
1632
1633     // Bring the file selection dialog down.
1634     XtUnmanageChild ( obj->_fileBrowser );  
1635
1636     //
1637     // Get the file name
1638     //
1639     XtVaGetValues(obj->_fileBrowser, XmNdirectory, &xmstr, NULL);
1640     if (xmstr)
1641       dname = (char*) _XmStringUngenerate(
1642                                         xmstr, NULL,
1643                                         XmMULTIBYTE_TEXT, XmMULTIBYTE_TEXT);
1644     
1645     //
1646     // Get the file name
1647     //
1648     XtVaGetValues(obj->_fileBrowser, XmNdirSpec, &xmstr, NULL);
1649     if (xmstr)
1650     {
1651         // Extract the first character string matching the default
1652         // character set from the compound string
1653         fname = (char *) _XmStringUngenerate(
1654                                         xmstr, NULL,
1655                                         XmMULTIBYTE_TEXT, XmMULTIBYTE_TEXT);
1656           
1657         if (NULL == fname || strlen(fname) == 0)
1658           return;
1659
1660         // If a string was successfully extracted, call
1661         // unifiedMailboxSelected to handle the file.
1662         *selected = '\0';
1663         if (NULL != dname) snprintf(selected, sizeof(selected), "%s", dname);
1664         strcat(selected, fname);
1665         obj->updateUnifiedData();
1666         obj->unifiedMailboxSelected(
1667                                 obj->_copy_callback,
1668                                 obj->_menuwindow,
1669                                 selected);
1670     }
1671 }
1672
1673 void
1674 MoveCopyCmd::setDefaultButtonCB( 
1675                              Widget,
1676                              XtPointer  clientData,
1677                              XtPointer)
1678 {
1679     MoveCopyCmd *thisCmd = (MoveCopyCmd *) clientData;
1680     thisCmd->setDefault(thisCmd->_default_button);
1681 }
1682
1683
1684 CopyCmd::CopyCmd( char *name, 
1685                    char *label, 
1686                    int active, 
1687                    RoamMenuWindow *window,
1688                    MoveCopyCmd *move_copy_cmd
1689                 ) : RoamCmd ( name, label, active, window )
1690 {
1691     _move_copy_cmd = move_copy_cmd;
1692 }
1693
1694 CopyCmd::~CopyCmd()
1695 {
1696 }
1697
1698 void
1699 CopyCmd::doit()
1700 {
1701     _move_copy_cmd->doit();
1702     _move_copy_cmd->setDefault(_move_copy_cmd->getCopyButton());
1703 }
1704
1705
1706 MoveCmd::MoveCmd( char *name, 
1707                    char *label, 
1708                    int active, 
1709                    RoamMenuWindow *window,
1710                    MoveCopyCmd *move_copy_cmd
1711                 ) : RoamCmd ( name, label, active, window )
1712 {
1713     _move_copy_cmd = move_copy_cmd;
1714 }
1715
1716 MoveCmd::~MoveCmd()
1717 {
1718 }
1719
1720 void
1721 MoveCmd::doit()
1722 {
1723     _move_copy_cmd->doit();
1724     _move_copy_cmd->setDefault(_move_copy_cmd->getMoveButton());
1725 }
1726
1727
1728 NextCmd::NextCmd( 
1729                   char *name, 
1730                   char *label,
1731                   int active, 
1732                   RoamMenuWindow *window 
1733                   ) : RoamCmd ( name, label, active, window )
1734 {
1735 }
1736
1737 void
1738 NextCmd::doit()
1739 {
1740     _menuwindow->list()->select_next_item();
1741 }
1742
1743
1744 PrevCmd::PrevCmd( 
1745                   char *name, 
1746                   char *label,
1747                   int active, 
1748                   RoamMenuWindow *window 
1749                   ) : RoamCmd ( name, label, active, window )
1750 {
1751 }
1752
1753 void
1754 PrevCmd::doit()
1755 {
1756     _menuwindow->list()->select_prev_item();
1757 }
1758
1759 #ifdef DEAD_WOOD
1760 MessagesCmd::MessagesCmd( 
1761                           char *name, 
1762                           char *label,
1763                           int active, 
1764                           RoamMenuWindow *window 
1765                           ) : RoamCmd ( name, label, active, window )
1766 {
1767 }
1768
1769
1770 void
1771 MessagesCmd::doit()
1772 {
1773     Boolean old=_menuwindow->fullHeader();
1774     MsgScrollingList *list=_menuwindow->list();
1775     
1776     ( !strcmp( this->name(), "Full Header" ) ? _menuwindow->fullHeader( True ) : _menuwindow->fullHeader( False ) );
1777     
1778     if ( old!=_menuwindow->fullHeader() && _menuwindow->msgView() ) {
1779 //    list->chooseCurrent();
1780     }
1781     
1782 }
1783 #endif /* DEAD_WOOD */
1784
1785 PrintCmd::PrintCmd ( 
1786                      char *name, 
1787                      char *label,
1788                      int active, 
1789                      int silent,
1790                      RoamMenuWindow *window 
1791                  ) : ChooseCmd ( name, label, active, window ), _tmp_files(5)
1792 {
1793     _parent = window;
1794     _silent = silent;
1795 }
1796
1797 void
1798 PrintCmd::doit()
1799 {
1800     // The entire implementation of print was broken. It has
1801     // be removed until a proper implementation can be provided.
1802     // dlp 10/04/93
1803     
1804     printit(_silent);
1805     return;
1806 }
1807
1808 void
1809 PrintCmd::actioncb(
1810                    DtActionInvocationID id,
1811                    XtPointer     clientData,
1812                    DtActionArg *,
1813                    int,
1814                    int           status
1815                    )
1816 {
1817     PrintCmd    *data;
1818     
1819     switch (status) {
1820       case DtACTION_INVOKED:
1821         break;
1822       default:
1823         data = (PrintCmd *)clientData;
1824         data->_parent->message("");
1825         data->_unregister_tmp_file(id);
1826         break;
1827     }
1828     
1829     return;
1830 }
1831
1832 void
1833 PrintCmd::printjobcb( Widget w, XtPointer client_data, XtPointer )
1834 {
1835     char *filename = (char *) client_data;
1836
1837     XtRemoveCallback(w, XtNdestroyCallback, &PrintCmd::printjobcb, filename);
1838
1839     unlink(filename);
1840     free(filename);
1841 }
1842
1843 void
1844 PrintCmd::printit( int silent )
1845 {
1846     char *p;
1847     char *silent_str = "DTPRINTSILENT";
1848     char *tmpdir = new char[MAXPATHLEN+1];
1849     DtMailEnv   mail_error;
1850     MsgScrollingList    *list;
1851     
1852     DebugPrintf(1, "%s: printit\n", name());
1853     
1854     // Create tmp file.
1855     snprintf(tmpdir, MAXPATHLEN+1, "%s/%s", getenv("HOME"), DtPERSONAL_TMP_DIRECTORY);
1856     if ((p = tempnam(tmpdir, "dtmail")) == NULL) {
1857         delete [] tmpdir;
1858         return;
1859     }
1860     delete [] tmpdir;
1861     
1862     mail_error.clear();
1863     list = _parent->list();
1864     
1865     // Copy selected messages to a temp file
1866     int status = list->copySelected(mail_error, p, FALSE, TRUE);
1867     if (mail_error.isSet())
1868     {
1869         _parent->postErrorDialog(mail_error);
1870         free(p);
1871         return;
1872     }
1873     if (0 != status) return;
1874     
1875
1876     DmxPrintJob *pjob = new DmxPrintJob(p,
1877                                         (silent ? DTM_TRUE : DTM_FALSE),
1878                                         _parent);
1879
1880     XtAddCallback(pjob->baseWidget(),
1881                 XtNdestroyCallback,
1882                 &PrintCmd::printjobcb,
1883                 (XtPointer) strdup(p));
1884
1885     pjob->execute();
1886     free(p);
1887     return;
1888 }
1889
1890 int
1891 PrintCmd::_register_tmp_file(
1892                              const char         *name,
1893                              DtActionInvocationID       id
1894                              )
1895 {
1896     struct tmp_file     *f;
1897     
1898     // Allocate struct to hold id and temp file
1899     if ((f = (struct tmp_file *)malloc(sizeof(struct tmp_file))) == NULL) {
1900         return -1;
1901     }
1902     
1903     // Save file name and action id
1904     f->file = strdup(name);
1905     f->id = id;
1906     
1907     // Add to list of temp files
1908     _tmp_files.append(f);
1909     
1910     return 0;
1911 }
1912
1913 void
1914 PrintCmd::_unregister_tmp_file(
1915                                DtActionInvocationID     id
1916                                )
1917 {
1918     int n;
1919     struct tmp_file *f;
1920     
1921     // Find the temp file that was used by the Action specified by id
1922     for (n = _tmp_files.length() - 1; n >= 0; n--) {
1923         f = _tmp_files[n];
1924         if (f->id == id) {
1925             // Found the file.  Unlink and free data structs
1926             unlink(f->file);
1927             free(f->file);
1928             free(f);
1929             // Remove entry from list
1930             _tmp_files.remove(n);
1931             break;
1932         }
1933     }
1934     
1935     return;
1936 }
1937
1938 #ifdef DEAD_WOOD
1939 PopupCmd::PopupCmd ( 
1940                      char *name, 
1941                      char *label,
1942                      int active,
1943                      PopupWindow * (RoamMenuWindow::* member) (void), 
1944                      RoamMenuWindow *myparent 
1945                      ) : NoUndoCmd ( name, label, active )
1946 {
1947     parent=myparent;
1948     pmpopup=member;
1949 }
1950
1951 void
1952 PopupCmd::doit()
1953 {
1954     PopupWindow *popup=(parent->*pmpopup)();
1955 //  popup->manage();
1956 }
1957 #endif /* DEAD_WOOD */
1958
1959 // OnItemCmd brings up the Help On Item help.
1960 OnItemCmd::OnItemCmd ( char * name, 
1961                        char *label, 
1962                        int active, 
1963                        UIComponent *window ) 
1964 : NoUndoCmd (name, label, active)
1965 {
1966     _parent = window;
1967 }
1968
1969 void
1970 OnItemCmd::doit()
1971 {
1972     int status = DtHELP_SELECT_ERROR;
1973     Widget widget = _parent->baseWidget();
1974     Widget selWidget = NULL;
1975     
1976     // Display the appropriate help information for the selected item.
1977     
1978     status = DtHelpReturnSelectedWidgetId(widget, 0, &selWidget);
1979     
1980     switch ((int) status) {
1981       case DtHELP_SELECT_ERROR:
1982         printf("Selection Error, cannot continue\n");
1983         break;
1984       case DtHELP_SELECT_VALID:
1985         while (selWidget != NULL) {
1986             if ((XtHasCallbacks(selWidget, XmNhelpCallback)
1987                  == XtCallbackHasSome)) {
1988                 XtCallCallbacks((Widget) selWidget, XmNhelpCallback, NULL);
1989                 break;
1990             } else {
1991                 selWidget = XtParent(selWidget);
1992             }
1993         }
1994         break;
1995       case DtHELP_SELECT_ABORT:
1996         printf("Selection Aborted by user.\n");
1997         break;
1998       case DtHELP_SELECT_INVALID:
1999         printf("You must select a component within your app.\n");
2000         break;
2001       default:
2002         ;
2003         // Empty
2004     }
2005     
2006 }
2007
2008 OnAppCmd::OnAppCmd ( char * name, 
2009                      char *label,
2010                      int active, 
2011                      UIComponent *window ) 
2012 : NoUndoCmd (name, label, active)
2013 {
2014     _parent = window;
2015 }
2016
2017 void
2018 OnAppCmd::doit()
2019 {
2020     DisplayMain (_parent->baseWidget(), "Mailer", DTMAILWINDOWID);
2021 }
2022
2023 TasksCmd::TasksCmd ( char * name, 
2024                      char *label,
2025                      int active, 
2026                      UIComponent *window )
2027 : NoUndoCmd (name, label, active)
2028 {
2029     _parent = window;
2030 }
2031
2032 void
2033 TasksCmd::doit()
2034 {
2035     DisplayMain (_parent->baseWidget(), "Mailer", HELP_MAILER_TASKS);
2036 }
2037
2038 ReferenceCmd::ReferenceCmd ( char * name, 
2039                              char *label,
2040                              int active, 
2041                              UIComponent *window )
2042 : NoUndoCmd (name, label, active)
2043 {
2044     _parent = window;
2045 }
2046
2047 void
2048 ReferenceCmd::doit()
2049 {
2050     DisplayMain (_parent->baseWidget(), "Mailer", HELP_MAILER_REFERENCE);
2051 }
2052
2053 UsingHelpCmd::UsingHelpCmd ( char * name, 
2054                              char *label,
2055                              int active, 
2056                              UIComponent *window )
2057 : NoUndoCmd (name, label, active)
2058 {
2059     _parent = window;
2060 }
2061
2062 void
2063 UsingHelpCmd::doit()
2064 {
2065     DisplayMain (_parent->baseWidget(), "Help4Help", "_HOMETOPIC");
2066 }
2067
2068 RelNoteCmd::RelNoteCmd ( char * name, 
2069                          char *label,
2070                          int active, 
2071                          UIComponent *window 
2072                      ) : NoUndoCmd (name, label, active )
2073 {
2074     _parent = window;
2075     _genDialog = NULL;
2076 }
2077
2078 void
2079 RelNoteCmd::doit()
2080 {
2081     // int answer;
2082
2083     // if (!_genDialog)
2084     //   _genDialog = new DtMailGenDialog("AboutBox", _parent->baseWidget());
2085     
2086     // _genDialog->setToAboutDialog();
2087     // answer = _genDialog->post_and_return(GETMSG(DT_catd, 1, 92, "OK"), NULL);
2088
2089     DisplayMain(_parent->baseWidget(), "Mailer", "_copyright");
2090 }
2091
2092 RelNoteCmd::~RelNoteCmd()
2093 {
2094     delete _genDialog;
2095 }
2096
2097 #ifdef DEAD_WOOD
2098 ClearCmd::ClearCmd ( 
2099                      char * name, 
2100                      char *label,
2101                      int active, 
2102                      RoamMenuWindow *window 
2103                      ) : NoUndoCmd (name, label, active )
2104 {
2105     parent=window;
2106 }
2107
2108 void
2109 ClearCmd::doit()
2110 {
2111 //  ((FindPopup *) parent->find_popup())->clear_text_values();
2112 }
2113
2114 StartCmd::StartCmd( char *name, 
2115                     char *label,
2116                     int active ) : Cmd ( name, label, active )
2117 {
2118 }
2119
2120 void 
2121 StartCmd::doit()
2122 {
2123     char *forward= ".forward";
2124     
2125     struct passwd pwd;
2126     GetPasswordEntry(pwd);
2127     
2128     char *forward_filename=new char[strlen(pwd.pw_dir)+1+strlen(forward)+1];
2129     sprintf( forward_filename, "%s/%s", pwd.pw_dir, forward );
2130 }
2131
2132
2133 void 
2134 StartCmd::undoit()
2135 {
2136 }
2137
2138
2139 ChangeCmd::ChangeCmd( 
2140                       char *name, 
2141                       char *label,
2142                       int active 
2143                       ) : Cmd (name, label, active )
2144 {
2145 }
2146
2147 void 
2148 ChangeCmd::doit()
2149 {
2150     struct passwd pwd;
2151     GetPasswordEntry(pwd);
2152     
2153     char *user_name=new char[strlen(pwd.pw_name)+1];
2154     strcpy(user_name,pwd.pw_name);
2155     
2156 }
2157
2158
2159 void 
2160 ChangeCmd::undoit()
2161 {
2162 }
2163
2164
2165 StopCmd::StopCmd( 
2166                   char *name, 
2167                   char *label,
2168                   int active, 
2169                   RoamMenuWindow *window 
2170                   ) : Cmd (name, label, active )
2171 {
2172     parent=window;
2173 }
2174
2175 void
2176 StopCmd::doit()
2177 {
2178     unlink( parent->forwardFilename() );
2179     parent->title( NULL );
2180 }
2181
2182
2183 void
2184 StopCmd::undoit()
2185 {
2186     
2187 }
2188 #endif /* DEAD_WOOD */
2189
2190
2191
2192 SendCmd::SendCmd(
2193                  char *name, 
2194                  char *label,
2195                  int active, 
2196                  SendMsgDialog *parent,
2197                  int trans_type) 
2198 : NoUndoCmd( name, label, active )
2199 {
2200     _parent=parent;
2201     _default_trans = trans_type;
2202 }
2203
2204 void
2205 SendCmd::doit()
2206 {
2207     if (!_parent->isMsgValid())
2208         return;
2209     else
2210         _parent->send_message( this->name(), _default_trans );
2211 }
2212
2213 // JT - Added methods below
2214
2215 OpenMsgCmd::OpenMsgCmd(
2216                        char *name,
2217                        char *label,
2218                        int active,
2219                        RoamMenuWindow *window) 
2220 : RoamCmd (name, label, active, window)
2221 {
2222 }
2223
2224 void
2225 OpenMsgCmd::doit()
2226 {
2227     DtMailEnv mail_error;
2228
2229     // Initialize the mail_error.
2230     mail_error.clear();
2231
2232     _menuwindow->list()->viewInSeparateWindow(mail_error);
2233     if (mail_error.isSet()) {
2234         _menuwindow->postErrorDialog(mail_error);
2235     }
2236
2237 }
2238
2239 // Attachment Cmds stuff
2240
2241 SaveAttachCmd::SaveAttachCmd ( char *name, 
2242                                char *label,
2243                                char * title,
2244                                int active, 
2245                                FileCallback save_callback,
2246                                RoamMenuWindow *clientData,
2247                                Widget parent)
2248 :UnifiedSelectFileCmd (name,
2249                        label,
2250                        title,
2251                        GETMSG(DT_catd, 1, 93, "Save"),
2252                        active,
2253                        save_callback,
2254                        clientData,
2255                        parent)
2256 {
2257    _parent = clientData;
2258    _name = NULL;
2259 }
2260
2261 SaveAttachCmd::SaveAttachCmd ( 
2262                                char *name, 
2263                                char *label,
2264                                char * title,
2265                                int active, 
2266                                FileCallback save_callback,
2267                                ViewMsgDialog *clientData,
2268                                Widget parent
2269                                )
2270 :UnifiedSelectFileCmd (name,
2271                        label,
2272                        title,
2273                        GETMSG(DT_catd, 1, 93, "Save"),
2274                        active,
2275                        save_callback,
2276                        clientData,
2277                        parent )
2278 {
2279    _parent = clientData;
2280    _name = NULL;
2281 }
2282
2283 SaveAttachCmd::SaveAttachCmd ( 
2284                                char *name, 
2285                                char *label,
2286                                char * title,
2287                                int active, 
2288                                FileCallback save_callback,
2289                                SendMsgDialog *clientData,
2290                                Widget parent
2291                                )
2292 :UnifiedSelectFileCmd (name,
2293                        label,
2294                        title,
2295                        GETMSG(DT_catd, 1, 93, "Save"),
2296                        active,
2297                        save_callback,
2298                        clientData,
2299                        parent )
2300 {
2301     _parent = clientData;
2302     _name = NULL;
2303 }
2304
2305 void
2306 SaveAttachCmd::doit()
2307 {
2308     UnifiedSelectFileCmd::doit();
2309
2310     DtMailEditor *editor = _parent->get_editor();
2311     AttachArea *aa = editor->attachArea();
2312     XmString attachmentName = aa->getSelectedAttachName();
2313     XtVaSetValues(_fileBrowser, XmNtextString, attachmentName, NULL);
2314     XtAddCallback ( _fileBrowser, XmNapplyCallback,
2315                     &SaveAttachCmd::updateCallback,
2316                     (XtPointer) this);
2317
2318     _name = XmStringCopy(attachmentName);
2319     XmStringFree(attachmentName);
2320 }
2321
2322 // Attachment Cmds stuff
2323
2324
2325 void SaveAttachCmd::updateCallback(Widget, XtPointer clientData, XtPointer )
2326 {
2327     SaveAttachCmd *obj = (SaveAttachCmd *)clientData;
2328     
2329     XtVaSetValues(obj->_fileBrowser, XmNtextString, obj->_name, NULL);
2330 }
2331
2332 SaveAsTextCmd::SaveAsTextCmd ( 
2333                                char *name, 
2334                                char *label,
2335                                char *title,
2336                                int active, 
2337                                Editor * editor,
2338                                RoamMenuWindow *parent_roam_menu_window,
2339                                Widget parent
2340                                ) 
2341 :UnifiedSelectFileCmd (name,
2342                        label,
2343                        title,
2344                        GETMSG(DT_catd, 1, 95, "Save"),
2345                        active,
2346                        fileCB,
2347                        this,
2348                        parent )
2349 {
2350     _text_editor = editor;
2351     _roam_menu_window = parent_roam_menu_window;
2352 }
2353
2354 SaveAsTextCmd::SaveAsTextCmd ( 
2355                                char *name, 
2356                                char *label,
2357                                char *title,
2358                                int active, 
2359                                Editor * editor,
2360                                void *,
2361                                Widget parent
2362                                ) 
2363 :UnifiedSelectFileCmd (name,
2364                        label,
2365                        title,
2366                        GETMSG(DT_catd, 1, 95, "Save"),
2367                        active,
2368                        fileCB,
2369                        this,
2370                        parent )
2371 {
2372     _text_editor = editor;
2373     _roam_menu_window = NULL;
2374 }
2375
2376 void
2377 SaveAsTextCmd::fileCB(void * client_data, char * selection)
2378 {
2379     SaveAsTextCmd * self = (SaveAsTextCmd *)client_data;
2380     self->saveText(selection);
2381 }
2382
2383 void
2384 SaveAsTextCmd::saveText(const char * filename)
2385 {
2386     int answer, status;
2387     char *buf = new char[2048];
2388     char * helpId;
2389
2390     // Is it already there?
2391     status = SafeAccess(filename, F_OK);
2392     if (0 == status)
2393     {
2394         sprintf(buf,
2395                 GETMSG(DT_catd, 3, 47, "%s already exists.\nOverwrite?"),
2396                 filename);
2397         
2398         _genDialog->setToQuestionDialog(GETMSG(DT_catd, 3, 48, "Mailer"), buf);
2399         helpId = DTMAILHELPERROR;
2400         answer = _genDialog->post_and_return(helpId);
2401         if (answer==2) {
2402             delete [] buf;
2403             return;
2404         }
2405
2406         if (unlink(filename) < 0)
2407         {
2408             sprintf(buf, 
2409                     GETMSG(DT_catd, 3, 49, "Unable to overwrite %s.\n\
2410 Check file permissions and retry."), 
2411                     filename);
2412             _genDialog->setToErrorDialog(GETMSG(DT_catd, 3, 50, "Mailer"), buf);
2413             helpId = DTMAILHELPNOOVERWRITE;
2414             _genDialog->post_and_return(helpId);
2415             delete [] buf;
2416             return;
2417         }
2418     }
2419
2420     // Create or truncate, and then write the bits.
2421     int fd = SafeOpen(filename, O_RDWR | O_CREAT | O_TRUNC, 0600);
2422     if (fd < 0)
2423     {
2424         sprintf(buf, GETMSG(DT_catd, 3, 51, "Unable to create %s."), filename);
2425         _genDialog->setToErrorDialog(GETMSG(DT_catd, 3, 52, "Mailer"), buf);
2426         helpId = DTMAILHELPNOCREATE;        
2427         _genDialog->post_and_return(helpId);
2428         delete [] buf;
2429         return;
2430     }
2431     
2432     if (SafeWrite(fd, "\n", 1) < 1)
2433     {
2434         sprintf(buf, 
2435                 GETMSG(DT_catd, 3, 53, "Unable to write to %s."), 
2436                 filename);
2437         _genDialog->setToErrorDialog(GETMSG(DT_catd, 3, 54, "Mailer"), buf);
2438         helpId = DTMAILHELPNOWRITE;
2439         _genDialog->post_and_return(helpId);
2440         SafeClose(fd);
2441         unlink(filename);
2442         delete [] buf;
2443         return;
2444     }
2445     
2446     if (NULL == _roam_menu_window)
2447     {
2448         char    *text_buf = _text_editor->get_contents();
2449         writeText((XtPointer) (intptr_t) fd, text_buf);
2450         XtFree((char*) text_buf);
2451     }
2452     else
2453       writeTextFromScrolledList(fd);
2454     
2455     SafeClose(fd);
2456     delete [] buf;
2457 }
2458
2459 void
2460 SaveAsTextCmd::writeTextFromScrolledList(int fd)
2461 {
2462     static char buf[2048];
2463     char        *helpId;
2464     char        *tmppath;
2465     DtMailEnv   mail_error;
2466     MsgScrollingList *list;
2467     DmxMailbox  *mailbox;
2468     DmxMsg      *next_msg;
2469
2470     //
2471     // Create temp file.
2472     //
2473     char *tmpdir = new char[MAXPATHLEN+1];
2474     snprintf(tmpdir, MAXPATHLEN+1, "%s/%s", getenv("HOME"), DtPERSONAL_TMP_DIRECTORY);
2475     if ((tmppath = tempnam(tmpdir, "dtmail")) == NULL) {
2476         snprintf(buf, sizeof(buf), GETMSG(DT_catd, 3, 51, "Unable to create %s."), tmpdir);
2477         _genDialog->setToErrorDialog(GETMSG(DT_catd, 3, 52, "Mailer"), buf);
2478         helpId = DTMAILHELPNOCREATE;        
2479         _genDialog->post_and_return(helpId);
2480         delete [] tmpdir;
2481         return;
2482     }
2483     delete [] tmpdir;
2484
2485     mail_error.clear();
2486     list = _roam_menu_window->list();
2487
2488     //
2489     // Copy the selected messages to a temp file.
2490     //
2491     int status = list->copySelected(mail_error, tmppath, FALSE, TRUE);
2492     if (mail_error.isSet()) {
2493         _roam_menu_window->postErrorDialog(mail_error);
2494         free(tmppath);
2495         return;
2496     }
2497     if (0 != status) return;
2498
2499     mailbox = new DmxMailbox(tmppath);
2500     mailbox->loadMessages();
2501     next_msg = mailbox->firstMessage();
2502     do
2503     {
2504         DmxPrintHeadersEnum     visible_headers;
2505
2506         if (_roam_menu_window->fullHeader())
2507           visible_headers = DMX_PRINT_HEADERS_ALL;
2508         else
2509           visible_headers = DMX_PRINT_HEADERS_ABBREV;
2510
2511         next_msg->display(
2512                         visible_headers,
2513                         &SaveAsTextCmd::writeText,
2514                         (XtPointer) (intptr_t) fd);
2515         writeText((XtPointer) (intptr_t) fd, "\n\n");
2516     } while ((next_msg = mailbox->nextMessage()) != (DmxMsg *) NULL);
2517     delete mailbox;
2518
2519     //
2520     // Clean up the temporary file.
2521     //
2522     unlink(tmppath);
2523     free(tmppath);
2524 }
2525
2526 void
2527 SaveAsTextCmd::writeText(XtPointer filedes, char *text_buf)
2528 {
2529     long        fdl = (long) filedes;
2530     int         fd = (int) fdl;
2531     int         len = strlen(text_buf);
2532     
2533     if (SafeWrite(fd, text_buf, len) < len) {
2534 #if 0
2535         char    buf[2048];
2536         char    *helpId;
2537
2538         sprintf(
2539                 buf,
2540                 GETMSG(DT_catd, 3, 53, "Unable to write to %s."), 
2541                 filename);
2542         helpId = DTMAILHELPNOWRITE;
2543         _genDialog->setToErrorDialog(GETMSG(DT_catd, 3, 56, "Mailer"), buf);
2544         _genDialog->post_and_return(helpId);
2545 #endif
2546     }
2547 }
2548
2549 void
2550 SaveAsTextCmd::doit()
2551 {
2552     MsgScrollingList    *list;
2553     Widget              listW;
2554     int                 *pos_list = NULL;
2555     int                 pos_count = 0;
2556
2557     if (_roam_menu_window &&
2558         (list = _roam_menu_window->list()) &&
2559         (listW = list->get_scrolling_list()))
2560     {
2561         if (!XmListGetSelectedPos(listW, &pos_list, &pos_count))
2562           return;
2563
2564         if (0 == pos_count)
2565         {
2566             DtMailGenDialog *dialog = _roam_menu_window->genDialog();
2567
2568             dialog->setToErrorDialog(
2569                             GETMSG(DT_catd, 3, 50, "Mailer"),
2570                             GETMSG(DT_catd, 2, 16, "No message selected."));
2571             dialog->post_and_return(NULL);
2572
2573             return;
2574         }
2575     }
2576
2577     UnifiedSelectFileCmd::doit();
2578
2579     if (1 == pos_count)
2580     {
2581         int                     pos_selected, last_space;
2582         DtMailEnv               error;
2583         DtMailHeaderLine        header;
2584         DtMailMessageHandle     msg_handle;
2585         DtMailHeaderRequest     request;
2586         DtMail::MailBox         *mbox;
2587
2588         pos_selected = list->get_selected_item();
2589         msg_handle = list->msgno(pos_selected);
2590
2591         request.number_of_names = 1;
2592         request.header_name = (char**) malloc(sizeof(char*));
2593         request.header_name[0] = strdup(DtMailMessageSubject);
2594
2595         mbox = _roam_menu_window->mailbox();
2596         mbox->getMessageSummary(error, msg_handle, request, header);
2597
2598         if (0 != header.header_values[0].length())
2599         {
2600             const char  *orig_subject = *((header.header_values[0])[0]);
2601             int         i,j;
2602             int         orig_len = strlen(orig_subject);
2603             char        *subject = (char*) malloc(orig_len + 1);
2604             XmString    xms;
2605
2606             for (i=0,j=0,last_space=0; i<orig_len; i++)
2607             {
2608                 if (isspace(orig_subject[i]))
2609                 {
2610                     if (last_space < i-1)
2611                       subject[j++] = ' ';
2612
2613                     last_space = i;
2614                 }
2615                 else if (orig_subject[i] == '/')
2616                   subject[j++] = '\\';
2617                 else
2618                   subject[j++] = orig_subject[i];
2619             }
2620             subject[j] = '\0';
2621
2622             xms = XmStringCreateLocalized(subject);
2623             XtVaSetValues(_fileBrowser, XmNtextString, xms, NULL);
2624
2625             XmStringFree(xms);
2626             free(subject);
2627         }
2628
2629         if (NULL != request.header_name)
2630         {
2631           if (NULL != request.header_name[0])
2632             free(request.header_name[0]);
2633           free(request.header_name);
2634         }
2635
2636         mbox->clearMessageSummary(header);
2637     }
2638 }
2639
2640
2641 DeleteAttachCmd::DeleteAttachCmd( 
2642                                   char *name, 
2643                                   char *label,
2644                                   int active,
2645                                   SendMsgDialog *smd
2646                                   
2647                                   ) : Cmd ( name, label, active )
2648 {
2649     _parent = smd;
2650 }
2651
2652 void
2653 DeleteAttachCmd::doit()
2654 {
2655     _parent->delete_selected_attachments();
2656 }
2657
2658 void
2659 DeleteAttachCmd::undoit()
2660 {
2661 }
2662
2663 UndeleteAttachCmd::UndeleteAttachCmd( 
2664                                       char *name, 
2665                                       char *label,
2666                                       int active,
2667                                       SendMsgDialog *smd
2668                                       
2669                                       ) : Cmd ( name, label, active )
2670 {
2671     _parent = smd;
2672 }
2673
2674 void
2675 UndeleteAttachCmd::doit()
2676 {
2677     _parent->undelete_last_deleted_attachment();
2678     
2679 }
2680
2681 void
2682 UndeleteAttachCmd::undoit()
2683 {
2684 }
2685
2686 RenameAttachCmd::RenameAttachCmd ( 
2687                                    char *name, 
2688                                    char *label,
2689                                    int active,
2690                                    SendMsgDialog *smd
2691                                    ) : Cmd ( name, label, active )
2692 {
2693     Widget renameDialog;
2694     XmString message;
2695     
2696     _parent = smd;
2697     renameDialog = XmCreatePromptDialog(
2698                                         smd->baseWidget(), 
2699                                         "renameDialog", 
2700                                         NULL, 
2701                                         0
2702                                         );
2703     
2704     message = XmStringCreateLocalized(GETMSG(DT_catd, 1, 96, "Empty"));
2705     XtVaSetValues(renameDialog, XmNselectionLabelString, message, NULL);
2706     XmStringFree(message);
2707     XmString ok_str = XmStringCreateLocalized(GETMSG(DT_catd, 1, 97, "Rename"));
2708     XtVaSetValues(XtParent(renameDialog),
2709                   XmNtitle, GETMSG(DT_catd, 1, 98, "Mailer - Rename"),
2710                   NULL);
2711     XtVaSetValues(renameDialog,
2712                   XmNokLabelString, ok_str,
2713                   NULL);
2714
2715     XmStringFree(ok_str);
2716     XtUnmanageChild(XmSelectionBoxGetChild(renameDialog, XmDIALOG_HELP_BUTTON));
2717
2718     _parent->get_editor()->attachArea()->setRenameDialog(renameDialog);
2719     XtAddCallback(renameDialog, XmNcancelCallback, 
2720                   &RenameAttachCmd::cancelCallback,
2721                   (XtPointer) this );
2722     XtAddCallback(renameDialog, XmNokCallback, 
2723                   &RenameAttachCmd::okCallback,
2724                   (XtPointer) this );
2725 }
2726
2727 void RenameAttachCmd::doit()
2728 {
2729     Widget renameDialog;
2730     XmString oldAttachName = NULL;
2731     XmString message;
2732     char        buf[512];
2733     AttachArea *aa;
2734     
2735     if (!_parent->renameAttachmentOK()) {
2736         return;
2737     }
2738     
2739     aa = _parent->get_editor()->attachArea();
2740     
2741     oldAttachName = aa->getSelectedAttachName();
2742     
2743     if (oldAttachName == NULL) return;
2744     
2745     renameDialog = aa->getRenameDialog();
2746     
2747     sprintf(buf, "%s", GETMSG(DT_catd, 3, 57, "Rename attachment as"));
2748     
2749     message = XmStringCreateLocalized(buf);
2750     
2751     XtVaSetValues(renameDialog, 
2752                   XmNselectionLabelString, message,
2753                   XmNtextString, oldAttachName,
2754                   NULL);
2755     
2756 //     XtFree(buf);
2757     XmStringFree(message);
2758     XmStringFree(oldAttachName);
2759     
2760     XtManageChild(renameDialog);
2761     XtPopup(XtParent(renameDialog), XtGrabNone);
2762 }      
2763
2764 void RenameAttachCmd::undoit()
2765 {
2766     // Just print a message that allows us to trace the execution
2767     
2768 }       
2769
2770 void RenameAttachCmd::cancelCallback ( 
2771                                        Widget, 
2772                                        XtPointer clientData, 
2773                                        XtPointer callData 
2774                                        )
2775 {
2776     RenameAttachCmd *obj = (RenameAttachCmd *) clientData;
2777     
2778     obj->cancel( callData );
2779 }
2780
2781 void RenameAttachCmd::cancel( XtPointer )
2782 {
2783     AttachArea* aa;
2784     
2785     aa = _parent->get_editor()->attachArea();
2786     
2787     Widget renameDialog = aa->getRenameDialog();
2788     
2789     XtUnmanageChild(renameDialog);
2790 }
2791
2792 void RenameAttachCmd::okCallback ( 
2793                                    Widget, 
2794                                    XtPointer clientData, 
2795                                    XtPointer callData 
2796                                    )
2797 {
2798     RenameAttachCmd *obj = (RenameAttachCmd *) clientData;
2799     obj->ok( callData );
2800 }
2801
2802 void RenameAttachCmd::ok( XtPointer callData )
2803 {
2804     XmSelectionBoxCallbackStruct *cbs = 
2805         (XmSelectionBoxCallbackStruct *)callData;
2806     AttachArea *aa;
2807     
2808     aa = _parent->get_editor()->attachArea();
2809     
2810     Widget renameDialog = aa->getRenameDialog();
2811     
2812     XtUnmanageChild(renameDialog);
2813     
2814     aa->setSelectedAttachName(cbs->value);
2815     
2816 }
2817
2818 AttachmentActionCmd::AttachmentActionCmd(
2819                                          char *name,
2820                                          char *label,
2821                                          RoamMenuWindow *rmw,
2822                                          int indx
2823                                          ) : Cmd (name, label, TRUE)
2824 {
2825     _index = indx;
2826     
2827     _parent = rmw;
2828 }
2829
2830 AttachmentActionCmd::AttachmentActionCmd(
2831                                          char *name,
2832                                          char *label,
2833                                          ViewMsgDialog *vmd,
2834                                          int indx
2835                                          ) : Cmd (name, label, TRUE)
2836 {
2837     _index = indx;
2838     
2839     _parent = vmd;
2840 }
2841
2842 AttachmentActionCmd::AttachmentActionCmd(
2843                                          char *name,
2844                                          char *label,
2845                                          SendMsgDialog *smd,
2846                                          int indx
2847                                          ) : Cmd (name, label, TRUE)
2848 {
2849     _index = indx;
2850     
2851     _parent = smd;
2852 }
2853
2854
2855 void
2856 AttachmentActionCmd::doit()
2857 {
2858     _parent->invokeAttachmentAction(_index);
2859 }
2860
2861 void
2862 AttachmentActionCmd::undoit()
2863 {
2864 }
2865
2866 SelectAllAttachsCmd::SelectAllAttachsCmd(
2867                                          char *name,
2868                                          char *label,
2869                                          RoamMenuWindow *rmw
2870                                          ) : Cmd(name, label, TRUE)
2871 {
2872     _parent = rmw;
2873 }
2874
2875 SelectAllAttachsCmd::SelectAllAttachsCmd(
2876                                          char *name,
2877                                          char *label,
2878                                          ViewMsgDialog *vmd
2879                                          ) : Cmd(name, label, TRUE)
2880 {
2881     _parent = vmd;
2882 }
2883
2884 SelectAllAttachsCmd::SelectAllAttachsCmd(
2885                                          char *name,
2886                                          char *label,
2887                                          SendMsgDialog *smd
2888                                          ) : Cmd(name, label, FALSE)
2889 {
2890     _parent = smd;
2891 }
2892
2893 void
2894 SelectAllAttachsCmd::doit()
2895 {
2896     _parent->selectAllAttachments();
2897 }
2898
2899 void
2900 SelectAllAttachsCmd::undoit()
2901 {
2902     // 
2903 }
2904
2905 ShowAttachPaneCmd::ShowAttachPaneCmd(
2906                                      char *name,
2907                                      char *label,
2908                                      AbstractEditorParent *aep
2909                                      ) : ToggleButtonCmd(name, label, TRUE)
2910 {
2911     _parent = aep;
2912 }
2913
2914 void
2915 ShowAttachPaneCmd::doit()
2916 {
2917     // If button is OFF
2918     if (!this->getButtonState()) {
2919         _parent->hideAttachArea();
2920     }
2921     else {  // button is ON
2922         _parent->showAttachArea();
2923     }
2924 }
2925
2926 void
2927 ShowAttachPaneCmd::undoit()
2928 {
2929     // 
2930 }
2931
2932 AbbrevHeadersCmd::AbbrevHeadersCmd(
2933                                    char *name,
2934                                    char *label,
2935                                    RoamMenuWindow *rmw
2936                                    ) : ToggleButtonCmd(name, label, TRUE)
2937 {
2938     _parent = rmw;
2939 }
2940
2941 void
2942 AbbrevHeadersCmd::doit()
2943 {
2944     // If button is OFF
2945     if (!this->getButtonState()) {
2946         _parent->fullHeader(TRUE);
2947     }
2948     else {  // button is ON
2949         _parent->fullHeader(FALSE);
2950     }
2951 }
2952
2953 void
2954 AbbrevHeadersCmd::undoit()
2955 {
2956     // 
2957 }
2958
2959 CloseCmd::CloseCmd( 
2960     char *name, 
2961     char *label,
2962     int active, 
2963     Widget w, 
2964     SendMsgDialog *s ) 
2965     : NoUndoCmd(name, label, active)
2966 {
2967     _compose_dialog = s;
2968     menubar_w = w;
2969 }
2970
2971 void
2972 CloseCmd::doit()
2973 {
2974     // Call the goAway() method on the SMD.  Argument TRUE requests it
2975     // to check if the SMD is dirty.  Let it handle the 
2976     // case where text may be present in the compose window.
2977     if (!_compose_dialog->isMsgValid())
2978         return;
2979     else
2980         _compose_dialog->goAway(TRUE);
2981
2982 }
2983
2984 EditUndoCmd::EditUndoCmd( 
2985     char *name, 
2986     char *label,
2987     int active, 
2988     AbstractEditorParent *w ) 
2989     : NoUndoCmd( name, label, active )
2990 {
2991     editor = w->get_editor()->textEditor();
2992 }
2993
2994 void
2995 EditUndoCmd::doit()
2996 {
2997         editor->undo_edit();
2998 }
2999
3000 EditCutCmd::EditCutCmd( 
3001     char *name, 
3002     char *label,
3003     int active, 
3004     AbstractEditorParent *w
3005
3006     : NoUndoCmd( name, label, active )
3007 {
3008     editor = w->get_editor()->textEditor();
3009
3010     // className() is a virtual method
3011     if (w->className() == "SendMsgDialog") {
3012         _compose_dialog = (SendMsgDialog *)w;
3013     }
3014     else {
3015         _compose_dialog = NULL;
3016     }
3017 }
3018
3019 void
3020 EditCutCmd::doit()
3021 {
3022     editor->cut_selection();
3023         
3024     if (_compose_dialog) {
3025         // Turn Paste on
3026         _compose_dialog->activate_edit_paste();
3027         _compose_dialog->activate_edit_paste_indented();
3028         _compose_dialog->activate_edit_paste_bracketed();
3029     }
3030 }
3031
3032 EditCopyCmd::EditCopyCmd( 
3033     char *name, 
3034     char *label,
3035     int active, 
3036     AbstractEditorParent *w ) 
3037     : NoUndoCmd( name, label, active )
3038 {
3039     editor = w->get_editor()->textEditor();
3040     
3041     // className() is a virtual method
3042     if (w->className() == "SendMsgDialog") {
3043         _compose_dialog = (SendMsgDialog *)w;
3044     }
3045     else {
3046         _compose_dialog = NULL;
3047     }
3048 }
3049
3050 void
3051 EditCopyCmd::doit()
3052 {
3053     editor->copy_selection();
3054     if (_compose_dialog) {
3055         // Turn Paste on
3056         _compose_dialog->activate_edit_paste();
3057         _compose_dialog->activate_edit_paste_indented();
3058         _compose_dialog->activate_edit_paste_bracketed();
3059     }
3060 }
3061
3062 EditPasteCmd::EditPasteCmd( 
3063     char *name, 
3064     char *label,
3065     int active, 
3066     AbstractEditorParent *w ) 
3067     : NoUndoCmd( name, label, active )
3068 {
3069     editor = w->get_editor()->textEditor();
3070 }
3071
3072 void
3073 EditPasteCmd::doit()
3074 {
3075         editor->paste_from_clipboard();
3076 }
3077
3078 EditPasteSpecialCmd::EditPasteSpecialCmd( 
3079     char *name, 
3080     char *label,
3081     int active, 
3082     AbstractEditorParent *w,
3083     Editor::InsertFormat format) 
3084     : NoUndoCmd( name, label, active )
3085 {
3086     editor = w->get_editor()->textEditor();
3087     insert_format = format;
3088 }
3089
3090 void
3091 EditPasteSpecialCmd::doit()
3092 {
3093         editor->paste_special_from_clipboard(insert_format);
3094 }
3095
3096
3097 EditClearCmd::EditClearCmd( 
3098     char *name, 
3099     char *label,
3100     int active, 
3101     AbstractEditorParent *w ) 
3102     : NoUndoCmd( name, label, active )
3103 {
3104         editor = w->get_editor()->textEditor();
3105     // this->deactivate();
3106 }
3107
3108 void
3109 EditClearCmd::doit()
3110 {
3111     editor->clear_selection();
3112         // Turn Paste on
3113         // _edit_paste->activate();
3114 }
3115
3116 EditDeleteCmd::EditDeleteCmd( 
3117     char *name, 
3118     char *label,
3119     int active, 
3120     AbstractEditorParent *w ) 
3121     : NoUndoCmd( name, label, active )
3122 {
3123     editor = w->get_editor()->textEditor();
3124         // this->deactivate();
3125 }
3126
3127 void
3128 EditDeleteCmd::doit()
3129 {
3130     editor->delete_selection();
3131         // Turn Paste off
3132         // _edit_paste->deactivate();
3133 }
3134
3135 EditSelectAllCmd::EditSelectAllCmd( 
3136     char *name, 
3137     char *label,
3138     int active, 
3139     AbstractEditorParent *w ) 
3140     : NoUndoCmd( name, label, active )
3141 {
3142     editor = w->get_editor()->textEditor();
3143 }
3144
3145 void
3146 EditSelectAllCmd::doit()
3147 {
3148         editor->select_all();
3149 }
3150
3151
3152
3153 WordWrapCmd::WordWrapCmd( 
3154     char *name, 
3155     char *label,
3156     int active, 
3157     AbstractEditorParent *w 
3158 ) : ToggleButtonCmd( name, label, active )
3159 {
3160     editor = w->get_editor()->textEditor();
3161     /*
3162      * allow the app-defaults setting for WordWrap
3163      */
3164
3165     Widget _w = editor->get_text_widget();
3166     Arg args[1];
3167
3168     XtSetArg( args[0], XmNwordWrap, &cur_setting );
3169     XtGetValues( _w, args, 1 );
3170     editor->set_word_wrap(cur_setting);         
3171 }
3172
3173 void
3174 WordWrapCmd::doit()
3175 {
3176     cur_setting = ((ToggleButtonCmd *)this)->getButtonState();
3177     editor->set_word_wrap(cur_setting);         
3178 }
3179
3180 Boolean
3181 WordWrapCmd::wordWrap()
3182 {
3183     return(cur_setting);
3184 }
3185
3186 FindChangeCmd::FindChangeCmd( 
3187     char *name, 
3188     char *label,
3189     int active, 
3190     AbstractEditorParent *w ) 
3191     : NoUndoCmd( name, label, active )
3192 {
3193     editor = w->get_editor()->textEditor();
3194 }
3195
3196 void
3197 FindChangeCmd::doit()
3198 {
3199         editor->find_change();
3200 }
3201
3202 SpellCmd::SpellCmd( 
3203     char *name, 
3204     char *label,
3205     int active, 
3206     AbstractEditorParent *w ) 
3207     : NoUndoCmd( name, label, active )
3208 {
3209     editor = w->get_editor()->textEditor();
3210 }
3211
3212 void
3213 SpellCmd::doit()
3214 {
3215         editor->spell();
3216 }
3217
3218 AliasCmd::AliasCmd(
3219     char *name,
3220     char *label,
3221     int active,
3222     Widget header)
3223     : NoUndoCmd (name, label, active)
3224 {
3225     _header = header;
3226     _alias = strdup(name);
3227 }
3228
3229 void
3230 AliasCmd::doit()
3231 {
3232     char        *value;
3233
3234     XtVaGetValues(_header, XmNvalue, &value, NULL);
3235
3236     if (strlen(value))
3237     {
3238         char    *newvalue = (char *) malloc(strlen(value) + strlen(_alias) + 3);
3239         sprintf(newvalue, "%s, %s", value, _alias);
3240         XtVaSetValues(_header, XmNvalue, newvalue, NULL);
3241         free(newvalue);
3242     }
3243     else
3244       XtVaSetValues(_header, XmNvalue, _alias, NULL);
3245     
3246     XtFree(value);
3247 }
3248
3249 AliasCmd::~AliasCmd()
3250 {
3251     free((void*) _alias);
3252 }
3253
3254
3255 OtherAliasesCmd::OtherAliasesCmd(
3256     char *name,
3257     char *label,
3258     int active)
3259     : NoUndoCmd (name, label, active)
3260 {
3261         _header = NULL;
3262 }
3263
3264 void
3265 OtherAliasesCmd::doit()
3266 {
3267     OptCmd      *optCmd = (OptCmd *) theRoamApp.mailOptions();
3268     optCmd->displayAliasesOptionsPane();
3269 }
3270
3271 OtherAliasesCmd::~OtherAliasesCmd()
3272 {
3273 }
3274
3275
3276 FormatCmd::FormatCmd( 
3277     char *name, 
3278     char *label,
3279     int active, 
3280     AbstractEditorParent *w ) 
3281     : NoUndoCmd( name, label, active )
3282 {
3283     editor = w->get_editor()->textEditor();
3284 }
3285
3286 void
3287 FormatCmd::doit()
3288 {
3289         editor->format();
3290 }
3291
3292 LogMsgCmd::LogMsgCmd( 
3293     char *name, 
3294     char *label,
3295     int active, 
3296     SendMsgDialog * send 
3297 ) : ToggleButtonCmd( name, label, active )
3298 {
3299   // Go to props and find out the default, ie. to log or not to log.
3300   // But for now, just look in .mailrc to see if "record" is set.
3301
3302   DtMailEnv error;
3303   const char *logfile = NULL;
3304
3305   _send = send;
3306
3307 }
3308
3309 void
3310 LogMsgCmd::doit()
3311 {
3312     if (!((ToggleButtonCmd *)this)->getButtonState()) {
3313         // turn off logging for this message
3314         _send->setLogState(DTM_FALSE);
3315     }
3316     else {
3317         // turn on logging for this message
3318         _send->setLogState(DTM_TRUE);
3319     }
3320
3321 }
3322
3323
3324 VacationCmd::VacationCmd(
3325     char *name,
3326     char *label
3327 ) : Cmd (name, label, TRUE)
3328 {
3329
3330     _forwardFile = ".forward";
3331     _backupSuffix = "..BACKUP";
3332     _subject = NULL;
3333     _body = NULL;
3334     _msg = NULL;
3335     _dialog = NULL;
3336
3337     // Check if a .forward file exists.  
3338
3339     _priorVacationRunning = this->priorVacationRunning();
3340
3341     // parse the .vacation.msg file and retain the subject
3342     // and body.
3343     // They need to be retrieved for display in the dialog.
3344
3345     this->parseVacationMessage();
3346 }
3347
3348
3349 VacationCmd::~VacationCmd()
3350 {
3351     if (NULL != _subject)
3352       free((void*) _subject);
3353     
3354     if (NULL != _msg)
3355       delete _msg;
3356 }
3357
3358 void
3359 VacationCmd::doit()
3360 {
3361 }
3362
3363 static unsigned long
3364 writeToFileDesc(const char * buf, int len, va_list args)
3365 {
3366     int fd = va_arg(args, int);
3367     int cnt = va_arg(args, int);
3368     int status = 0;
3369
3370     do {
3371         status = SafeWrite(fd, buf, len);
3372     } while (status < 0 && errno == EAGAIN);
3373         
3374     return(0);
3375 }
3376
3377 int
3378 VacationCmd::startVacation(
3379     char *subj,
3380     char *text
3381 )
3382 {
3383     int i = this->handleMessageFile(subj, text);
3384     if (i == 0) {
3385         i = this->handleForwardFile();
3386     }
3387
3388     return (i);
3389 }
3390
3391 void
3392 VacationCmd::stopVacation()
3393 {
3394     char *forwardfile = new char[MAXPATHLEN+1];
3395     
3396     snprintf(forwardfile, MAXPATHLEN+1, "%s/%s", getenv("HOME"), _forwardFile);
3397
3398     // Remove the current .forward file (it has vacation in it)
3399     // Recover and replace the original backup forward file, if 
3400     // one exists.
3401
3402     unlink(forwardfile);
3403
3404     this->recoverForwardFile(forwardfile);
3405     delete [] forwardfile;
3406 }
3407
3408 Boolean
3409 VacationCmd::priorVacationRunning()
3410
3411 {
3412     char        buf[256];
3413     int fd;
3414     Boolean     retval = FALSE;
3415     char *forwardfile = new char[MAXPATHLEN+1];
3416
3417     snprintf(forwardfile, MAXPATHLEN+1, "%s/%s", getenv("HOME"), _forwardFile);
3418
3419     if (SafeAccess(forwardfile, F_OK) != 0) {
3420         delete [] forwardfile;
3421         return(FALSE);
3422     }
3423         
3424     fd = SafeOpen(forwardfile, O_RDONLY);
3425         
3426     buf[sizeof buf -1] = '\0';
3427     int len;
3428     while ((len = SafeRead(fd, buf, (sizeof buf) - 1)) > 0) {
3429         buf[len] = 0;
3430         if ((strstr(buf, "/usr/bin/vacation")) ||
3431             (strstr(buf, "/usr/ucb/vacation"))) {
3432             retval = TRUE;
3433             break;
3434         }
3435     }
3436
3437     SafeClose(fd);
3438
3439     delete [] forwardfile;
3440     return(retval);
3441 }
3442
3443 int
3444 VacationCmd::handleForwardFile()
3445 {
3446     int         fwd_fd;
3447     int         bkup_fd;
3448     int         fsize;
3449     int         answer;
3450     int         forwarding;
3451     int         lastchar;
3452     caddr_t     fwdptr;
3453     char        *helpId;
3454     Boolean     forwardExists;
3455     DtMailGenDialog     *dialog;
3456
3457     int error_bufLen = 10000;
3458     char *error_buf = new char[error_bufLen];
3459     char *forwardfile = new char[MAXPATHLEN+1];
3460     char *messagefile = new char[256];
3461     char *buf = new char[2048];
3462
3463     // initialize the error_buf
3464     memset(error_buf, 0, error_bufLen);
3465     memset(buf, 0, 2048);
3466
3467     answer = FALSE;
3468     forwarding = FALSE;
3469     forwardExists = FALSE;
3470
3471     passwd pw;
3472     GetPasswordEntry(pw);
3473
3474     sprintf(forwardfile, "%s/%s", pw.pw_dir, _forwardFile);
3475     
3476     if (SafeAccess(forwardfile, F_OK) == 0 ) {
3477         forwardExists = TRUE;
3478         }
3479     else {
3480         forwardExists = FALSE;
3481     }
3482     
3483     if (forwardExists && !_priorVacationRunning) {
3484
3485         /* STRING_EXTRACTION -
3486          *
3487          * This confirmation window is brought up when the user
3488          * tries to update the vacation status when the user is
3489          * already using a .forward file.
3490          */
3491         if (NULL != _dialog)
3492           dialog = _dialog;
3493         else
3494           dialog = theRoamApp.genDialog();
3495
3496         sprintf(error_buf, "%s", GETMSG(DT_catd, 1, 102, "You are already using the forwarding facility for\nsomething other than Vacation.  While Vacation is\nrunning, Vacation will be appended to this other\nforwarding activity. Is it still OK to start Vacation?\0"));
3497
3498         dialog->setToQuestionDialog(GETMSG(DT_catd, 1, 103, "Mailer"), 
3499                                     error_buf);
3500
3501         helpId = DTMAILHELPOKSTARTVACATION;
3502         answer = dialog->post_and_return(helpId);
3503
3504         if (answer == 2) {// Cancel chosen
3505             delete [] buf;
3506             delete [] messagefile;
3507             delete [] error_buf;
3508             delete [] forwardfile;
3509             return 1;
3510         }
3511         
3512         if (this->backupFile(forwardfile) < 0) {
3513             delete [] buf;
3514             delete [] messagefile;
3515             delete [] error_buf;
3516             delete [] forwardfile;
3517             return 1;
3518         }
3519
3520         /* A .forward file is currently in use. Merge vacation
3521          * into this file, rather than overwrite it. To do so,
3522          * set the appropriate variable to indicate mode.
3523          */
3524
3525         _priorVacationRunning = TRUE;
3526         
3527         // Turn on the bit to indicate we are currently using a .forward
3528         forwarding = TRUE;
3529     }
3530     else if (forwardExists && _priorVacationRunning) {
3531
3532         /* STRING_EXTRACTION -
3533          *
3534          * This confirmation window is brought up when the user
3535          * tries to update the vacation status when the user is
3536          * already using a .forward file.
3537          */
3538
3539         if (NULL != _dialog)
3540           dialog = _dialog;
3541         else
3542           dialog = theRoamApp.genDialog();
3543
3544         sprintf(error_buf, "%s", GETMSG(DT_catd, 1, 104, "You are already running the vacation program in your .forward file.\nConsult documentation on how to stop it and remove it from your .forward file.\nTry this command after fixing that problem.\0"));
3545         
3546         dialog->setToErrorDialog("Error", error_buf);
3547         helpId = DTMAILHELPREMOVEVACATION;
3548         answer = dialog->post_and_return(helpId);
3549
3550         delete [] buf;
3551         delete [] messagefile;
3552         delete [] error_buf;
3553         delete [] forwardfile;
3554         return 1;
3555
3556     }   
3557
3558     // Re-initialize the error_buf
3559     memset(error_buf, 0, error_bufLen);
3560
3561     sprintf(messagefile, "%s/.vacation.msg", pw.pw_dir);
3562
3563     if (forwardExists) {
3564         fwd_fd = SafeOpen(forwardfile, O_WRONLY | O_APPEND | O_CREAT);
3565     }
3566     else {
3567         fwd_fd = SafeOpen(forwardfile, O_WRONLY | O_CREAT);
3568     }
3569
3570     if (fwd_fd < 0 ) {// If fwdfile is not writable/appendable
3571         
3572         // Put up error dialog indicating fwdfile not writable
3573         /* restore the original .forward file */
3574         
3575         this->recoverForwardFile(forwardfile);
3576         delete [] buf;
3577         delete [] messagefile;
3578         delete [] error_buf;
3579         delete [] forwardfile;
3580         return 1;
3581     }
3582
3583     SafeFChmod(fwd_fd, 0644);
3584
3585     // Make buf be forwardfile._backupSuffix.
3586     // Then create a backup file of name buf
3587     
3588     strcpy(buf, forwardfile);
3589     strcat(buf, _backupSuffix);
3590
3591     // If we are currently using a .forward then we need to append/prepend
3592     // the vacation command
3593
3594     if (forwarding) {
3595
3596         /* CREATE NEW .forward FILE
3597          *
3598          * The original .forward file has been renamed to the
3599          * backup file name. We need to open the backup .forward
3600          * file so we can copy from it.
3601          */
3602
3603         if ((bkup_fd = SafeOpen(buf, O_RDONLY)) < 0) {
3604             /* restore the original .forward file */
3605             if (answer)
3606                 this->recoverForwardFile(forwardfile);
3607             delete [] buf;
3608             delete [] messagefile;
3609             delete [] error_buf;
3610             delete [] forwardfile;
3611             return 1;
3612         }
3613
3614         /* COPY OLD .forward TO NEW .forward
3615          *
3616          * Using mmap is quite fast, so rather than do a while
3617          * loop to copy line by line, we'll use mmap followed by
3618          * a write.
3619          */
3620         
3621         fsize= (int)lseek(bkup_fd, 0, SEEK_END);
3622         if (fsize > 0)
3623         {
3624             fwdptr =
3625               (caddr_t) mmap(0, fsize, PROT_READ, MAP_PRIVATE, bkup_fd, 0);
3626
3627             // If map failed
3628             if (fwdptr == (char *)-1) {
3629                 // error
3630                 delete [] buf;
3631                 delete [] messagefile;
3632                 delete [] error_buf;
3633                 delete [] forwardfile;
3634                 SafeClose(bkup_fd);
3635                 return 1;
3636             }
3637
3638             // If write failed
3639             if (SafeWrite(fwd_fd, fwdptr, fsize) < fsize) {
3640                 // error
3641                 delete [] buf;
3642                 delete [] messagefile;
3643                 delete [] error_buf;
3644                 delete [] forwardfile;
3645                 SafeClose(bkup_fd);
3646                 return 1;
3647             }
3648         
3649             /* RELEASE .forward FILE
3650              *
3651              * Un-mmap the new .forward file
3652              */
3653
3654             lastchar = fwdptr[fsize-1];
3655             munmap(fwdptr, fsize);
3656         }
3657         else
3658           lastchar = '\n';
3659
3660         /* APPEND VACATION LINE
3661          *
3662          * The new .forward file is still open, so append the
3663          * new line below as the last line of the .forward file.
3664          * Check to make sure last character in the file is a
3665          * newline. If it's not, add one so our work goes on
3666          * a separate line.
3667          */
3668
3669         if (lastchar != '\n') {
3670             lseek(fwd_fd, 0, SEEK_END);
3671             char *txt = "\n";
3672             if (SafeWrite(fwd_fd, txt, strlen(txt)) < strlen(txt)) {
3673                 // error
3674                 delete [] buf;
3675                 delete [] messagefile;
3676                 delete [] error_buf;
3677                 delete [] forwardfile;
3678                 SafeClose(bkup_fd);
3679                 return 1;
3680             }
3681         }
3682
3683         /*
3684          * Now, add the vacation line to the next line.
3685          */
3686         char *append_buf1 = new char[1024*2];
3687         sprintf(append_buf1, "|\" /usr/bin/vacation %s\"\n", pw.pw_name);
3688
3689         if (SafeWrite(fwd_fd, append_buf1, strlen(append_buf1)) < 
3690             strlen(append_buf1)) {
3691             // error
3692             delete [] buf;
3693             delete [] messagefile;
3694             delete [] error_buf;
3695             delete [] forwardfile;
3696             delete [] append_buf1;
3697             SafeClose(bkup_fd);
3698             return 1;
3699         }
3700         delete [] append_buf1;
3701
3702         SafeClose(bkup_fd);
3703     }
3704
3705         /* Create known backup file. The known backup
3706          * file allows mailtool to differentiate between
3707          * vacation being started from mailtool, and vacation
3708          * being invoked (the Unix program as opposed to the
3709          * MailTool Vacation menu item) via tty session.
3710          */
3711
3712     if (!forwardExists) {
3713
3714         if ((bkup_fd = SafeOpen(buf, O_WRONLY | O_APPEND | O_CREAT)) < 0) {
3715             /* restore the original .forward file */
3716             if (answer)
3717                 this->recoverForwardFile(forwardfile);
3718             delete [] buf;
3719             delete [] messagefile;
3720             delete [] error_buf;
3721             delete [] forwardfile;
3722             SafeClose(fwd_fd);
3723             return 1;
3724         }
3725
3726         char *end_text = "User not using forward file\n";
3727
3728         if (SafeWrite(bkup_fd, end_text, strlen(end_text)) < 
3729             strlen(end_text)) {
3730             // error
3731             delete [] buf;
3732             delete [] messagefile;
3733             delete [] error_buf;
3734             delete [] forwardfile;
3735             SafeClose(bkup_fd);
3736             SafeClose(fwd_fd);
3737             return 1;
3738         }
3739     }
3740
3741     if (!forwardExists) {
3742
3743         /* WRITE NEW .forward FILE
3744          *
3745          * There was no .forward file, so no appending
3746          * must be done. Simply write the standard
3747          * vacation line into the new .forward file.
3748          */
3749
3750         char *append_buf2 = new char[1024*2];
3751
3752         sprintf(append_buf2, "\\%s, |\" /usr/bin/vacation %s\"\n", 
3753                 pw.pw_name, pw.pw_name);
3754         if (SafeWrite(fwd_fd, append_buf2, strlen(append_buf2)) <
3755             strlen(append_buf2)) {
3756             // error
3757             SafeClose(bkup_fd);
3758             SafeClose(fwd_fd);
3759             delete [] buf;
3760             delete [] messagefile;
3761             delete [] error_buf;
3762             delete [] forwardfile;
3763             delete [] append_buf2;
3764             return 1;
3765         }
3766         delete [] append_buf2;
3767     }
3768
3769     SafeClose(bkup_fd);
3770     SafeClose(fwd_fd);
3771
3772     system("/usr/bin/vacation -I");
3773
3774     delete [] buf;
3775     delete [] messagefile;
3776     delete [] error_buf;
3777     delete [] forwardfile;
3778     return 0;
3779 }
3780
3781 int
3782 VacationCmd::backupFile(
3783     char *file
3784 )
3785 {
3786         char *buf = new char[MAXPATHLEN+1];
3787
3788         strcpy(buf, file);
3789         strcat(buf, _backupSuffix);
3790
3791         if (rename(file, buf) < 0) {
3792                 /* STRING_EXTRACTION -
3793                  *
3794                  * We tried to make a backup copy of your .forward file, but
3795                  * it failed.  The first %s is the name of the rename
3796                  * target; the second %s is the system error string.
3797                  */
3798         
3799             // Put up error dialog 
3800             delete [] buf;
3801             return(-1);
3802         }
3803
3804         delete [] buf;
3805         return(0);
3806 }
3807
3808 int
3809 VacationCmd::recoverForwardFile(
3810     char        *file
3811 )
3812 {
3813         char *buf = new char[BUFSIZ+1];
3814         int  fd;
3815
3816         sprintf(buf, "%s", file);
3817         strcat(buf, _backupSuffix);
3818
3819         if (rename(buf, file) < 0) {
3820
3821             /* STRING_EXTRACTION -
3822              *
3823              * We tried to restore your original .forward file, but could
3824              * not.  The first %s is the name of the original .forward file,
3825              * the second %s is the the system error string.
3826              */
3827
3828             // Handle dialog indicating error in recovering .forward file.
3829             // Error usually caused by starting /usr/bin/vacation outside
3830             // of dtmail
3831
3832             delete [] buf;
3833             return(-1);
3834         }       
3835
3836         if ((fd = SafeOpen(file, O_RDONLY)) == -1) {
3837             delete [] buf;
3838             return(-1);
3839         }
3840         
3841         buf[sizeof file -1] = '\0';
3842         while (SafeRead(fd, buf, BUFSIZ) != 0) {
3843                 if (strstr(buf, "User not using forward file")) {
3844                         unlink(file);
3845                         break;
3846                 }
3847         }
3848
3849         SafeClose(fd);
3850
3851         delete [] buf;
3852         return(0);
3853 }
3854
3855 char *
3856 VacationCmd::subject()
3857 {
3858     return(_subject);
3859 }
3860
3861
3862 char *
3863 VacationCmd::body()
3864 {
3865     if (_body) {
3866         return((char *)_body);
3867     }
3868     else {
3869         return(NULL);
3870     }
3871 }
3872
3873 void
3874 VacationCmd::parseVacationMessage()
3875 {
3876     passwd pw;
3877     int         fd;
3878
3879     DtMailGenDialog     *dialog;
3880     char * helpId;
3881     int answer;
3882     char dialog_text[1024*4];
3883     DtMailEnv error;
3884     DtMail::Session * d_session = theRoamApp.session()->session();
3885     DtMailBuffer mbuf;
3886
3887     if (NULL != _dialog)
3888       dialog = _dialog;
3889     else
3890       dialog = theRoamApp.genDialog();
3891
3892     GetPasswordEntry(pw);
3893
3894     char *messagefile = new char[MAXPATHLEN+1];
3895     sprintf(messagefile, "%s/.vacation.msg", pw.pw_dir);
3896
3897     // See if the messagefile exists.
3898     // If it doesn't create one and throw in the text found in the
3899     // properties sheet.  If no text found, use default template.
3900
3901     char * fullpath = d_session->expandPath(error, messagefile);
3902     delete [] messagefile;
3903     messagefile = NULL;
3904
3905     // Map the file and try to parse it as a message. If it is a message,
3906     // then load it with headers. Otherwise, throw everything into the
3907     // editor.
3908     //
3909
3910     fd = SafeOpen(fullpath, O_RDONLY);
3911     free(fullpath);
3912
3913     if (fd < 0) {// File doesn't exist
3914         
3915         _subject = NULL;
3916         _body = NULL;
3917         return;
3918     }
3919
3920     struct stat buf;
3921     if (SafeFStat(fd, &buf) < 0) {
3922
3923         sprintf(dialog_text, "%s",
3924                 GETMSG(DT_catd, 1, 105, "Cannot open .vacation.msg file -- No write permission."));
3925         dialog->setToQuestionDialog("Mailer", dialog_text);
3926         helpId = DTMAILHELPNOWRITEVACATION;
3927         answer = dialog->post_and_return(helpId);
3928             
3929         _subject = NULL;
3930         _body = NULL;
3931
3932         SafeClose(fd);
3933         return;
3934     }           
3935
3936     int page_size = (int)sysconf(_SC_PAGESIZE);
3937     size_t map_size = (int) (buf.st_size + 
3938                             (page_size - (buf.st_size % page_size)));
3939
3940     if (buf.st_size == 0) {
3941       SafeClose(fd);
3942       return;
3943    }
3944
3945     int free_buf = 0;
3946     mbuf.size = buf.st_size;
3947 #ifdef __osf__
3948     mbuf.buffer = (char *)mmap(0, map_size, PROT_READ, MAP_PRIVATE, fd, 0);
3949 #else
3950     mbuf.buffer = mmap(0, map_size, PROT_READ, MAP_PRIVATE, fd, 0);
3951 #endif
3952     if (mbuf.buffer == (char *)-1) {
3953         free_buf = 1;
3954         mbuf.buffer = new char[mbuf.size];
3955         if (mbuf.buffer == NULL) {
3956             dialog->setToErrorDialog(GETMSG(DT_catd, 3, 59, "No Memory"),
3957                                      GETMSG(DT_catd, 3, 60, "There is not enough memory to load the existing .vacation.msg file."));
3958             helpId = DTMAILHELPNOLOADVACATION;
3959             answer = dialog->post_and_return(helpId);
3960             SafeClose(fd);
3961
3962             _subject = NULL;
3963             _body = NULL;
3964
3965             return;
3966         }
3967
3968         if (SafeRead(fd, mbuf.buffer, (unsigned int)mbuf.size) < mbuf.size) {
3969             dialog->setToErrorDialog(GETMSG(DT_catd, 3, 61, "Mailer"),
3970                                      GETMSG(DT_catd, 3, 62, "The existing .vacation.msg file appears to be corrupt."));
3971             helpId = DTMAILHELPCORRUPTVACATION;
3972             answer = dialog->post_and_return(helpId);
3973             SafeClose(fd);
3974             delete [] mbuf.buffer;
3975             _subject = NULL;
3976             _body = NULL;
3977
3978             return;
3979         }
3980     }
3981
3982     // Now we ask the library to parse it. If this fails for any reason, this
3983     // is not a message, so we give up.
3984     //
3985     DtMail::Message * msg = d_session->messageConstruct(error,
3986                                                         DtMailBufferObject,
3987                                                         &mbuf,
3988                                                         NULL,
3989                                                         NULL,
3990                                                         NULL);
3991     SafeClose(fd);
3992
3993     if (error.isSet()) {
3994         _subject = NULL;
3995         _body = NULL;
3996         _msg = NULL;
3997         return;
3998     }
3999     else {
4000         DtMail::Envelope * env = msg->getEnvelope(error);
4001         DtMailHeaderHandle hnd;
4002
4003         int hcount = 0;
4004         char * name;
4005         DtMailValueSeq value;
4006
4007         for (hnd = env->getFirstHeader(error, &name, value);
4008             error.isNotSet() && hnd;
4009             hnd = env->getNextHeader(error, hnd, &name, value)) {
4010             
4011             if (!strcmp(name, "Subject") == 0) {
4012                 continue;
4013             }
4014             else {
4015
4016                 int max_len = 0;
4017                 for (int slen = 0; slen < value.length(); slen++) {
4018                     max_len += strlen(*(value[slen]));
4019                 }
4020
4021                 char * new_str = new char[max_len + (value.length() * 3)];
4022
4023                 strcpy(new_str, "");
4024                 for (int copy = 0; copy < value.length(); copy++) {
4025                     if (copy != 0) {
4026                         strcat(new_str, " ");
4027                     }
4028
4029                     strcat(new_str, *(value[copy]));
4030                 }
4031
4032                 _subject = strdup(new_str);
4033                 value.clear();
4034                 free(name);
4035                 delete [] new_str;
4036                 break;
4037             }
4038         }
4039
4040         DtMail::BodyPart * bp = msg->getFirstBodyPart(error);
4041         if (error.isNotSet()) {
4042             unsigned long length;
4043
4044             bp->getContents(error,
4045                             &_body,
4046                             &length,
4047                             NULL,
4048                             NULL,
4049                             NULL,
4050                             NULL);
4051         }
4052
4053         //
4054         // Avoid a memory leak.
4055         //
4056         _msg = msg;
4057     }
4058
4059 }
4060
4061 int
4062 VacationCmd::handleMessageFile(
4063     char *subj,
4064     char *text
4065 )
4066 {
4067     int         fd;
4068
4069     DtMailGenDialog     *dialog;
4070     char * helpId;
4071     int answer;
4072     char dialog_text[1024*4];
4073     Boolean text_changed = FALSE;
4074     char *messagefile = new char[256];
4075
4076     BufferMemory buf(4096);
4077
4078     if (NULL != _dialog)
4079       dialog = _dialog;
4080     else
4081       dialog = theRoamApp.genDialog();
4082
4083     // Check if a .forward file exists.  
4084     passwd pw;
4085     GetPasswordEntry(pw);
4086
4087     sprintf(messagefile, "%s/.vacation.msg", pw.pw_dir);
4088
4089     // See if the messagefile exists.
4090     // If it doesn't create one and throw in the text found in the
4091     // properties sheet.  If no text found, use default template.
4092
4093     answer = 0;
4094
4095     int msg_file_exists = SafeAccess(messagefile, F_OK);
4096     if (subj != NULL) {
4097          if (_subject == NULL || strcmp(_subject, subj) != 0)
4098                 text_changed = TRUE;
4099     }
4100     else if (_subject != NULL)
4101         text_changed = TRUE;
4102
4103     if (!text_changed) {
4104         if (text != NULL) {
4105                 if (_body == NULL || strcmp((char*)_body, text) != 0)
4106                         text_changed = TRUE;
4107         }
4108         else if (_body != NULL)
4109                 text_changed = TRUE;
4110     }
4111
4112     if (msg_file_exists >= 0 &&  text_changed) {
4113         sprintf(dialog_text, "%s",
4114                 GETMSG(DT_catd, 1, 106, ".vacation.msg file exists.  Replace with new text?"));
4115         dialog->setToQuestionDialog("Mailer", dialog_text);
4116         helpId = DTMAILHELPEXISTSVACATION;
4117         answer = dialog->post_and_return(helpId);
4118
4119         if (answer == 1) {
4120                 // backup the messageFile
4121                 this->backupFile(messagefile);
4122         }
4123     }
4124     
4125     // If the file doesn't exist or if the user has okayed creation
4126
4127     if ((msg_file_exists < 0) || (answer == 1)) {
4128
4129         fd = SafeOpen(messagefile, O_WRONLY | O_CREAT);
4130         if (fd < 0) {
4131             sprintf(dialog_text, "%s",
4132                 GETMSG(DT_catd, 1, 107, "Cannot open .vacation.msg file -- No write permission."));
4133             dialog->setToQuestionDialog("Mailer", dialog_text);
4134             helpId = DTMAILHELPERROR;
4135             answer = dialog->post_and_return(helpId);
4136             
4137             // Handle dialog indicating file not writable
4138             delete [] messagefile;
4139             return (-1);        
4140         }               
4141         SafeFChmod (fd, 0644);
4142
4143         if (!subj) { 
4144             /* NL_COMMENT
4145              * This is the default value of the subject field in the
4146              * message that gets returned to the sender when vacation
4147              * is turned on.
4148              */
4149             subj = GETMSG(DT_catd, 1, 108, "I am on vacation");
4150         } else {
4151             buf.appendData("Subject: ", 9);
4152             buf.appendData(subj, strlen(subj));
4153             buf.appendData("\nPrecedence: junk\n\n", 19);
4154         }
4155         if (_subject)
4156             free (_subject);
4157         _subject = strdup(subj);
4158         
4159         if (!text) {
4160             text = GETMSG(DT_catd, 1, 109,
4161                             "I'm on vacation.\nYour mail regarding \"$SUBJECT\" will be read when I return.\n");
4162         }
4163         buf.appendData(text, strlen(text));
4164         if (strlen(text) > 0 && text[strlen(text) - 1] != '\n') {
4165             buf.appendData("\n", 1);
4166         }
4167         _body = strdup(text);
4168
4169         buf.iterate(writeToFileDesc, fd);
4170         
4171         SafeClose(fd);
4172     }
4173     delete [] messagefile;
4174     return(0);
4175 }