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