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