Even more spelling fixed
[oweals/cde.git] / cde / programs / dtmail / dtmail / ComposeCmds.C
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these libraries and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /*
24  *+SNOTICE
25  *
26  *      $TOG: ComposeCmds.C /main/11 1998/10/21 17:23:13 mgreess $
27  *
28  *      RESTRICTED CONFIDENTIAL INFORMATION:
29  *      
30  *      The information in this document is subject to special
31  *      restrictions in a confidential disclosure agreement between
32  *      HP, IBM, Sun, USL, SCO and Univel.  Do not distribute this
33  *      document outside HP, IBM, Sun, USL, SCO, or Univel without
34  *      Sun's specific written approval.  This document and all copies
35  *      and derivative works thereof must be returned or destroyed at
36  *      Sun's request.
37  *
38  *      Copyright 1993 Sun Microsystems, Inc.  All rights reserved.
39  *
40  *+ENOTICE
41  */
42
43 #include <EUSCompat.h>
44 #include <unistd.h>
45 #include <sys/types.h>
46
47 #if defined(NEED_MMAP_WRAPPER)
48 extern "C" {
49 #endif
50 #include <sys/mman.h>
51 #if defined(NEED_MMAP_WRAPPER)
52 }
53 #endif
54
55 #include <pwd.h>
56 #include <Xm/Text.h>
57 #include <Xm/FileSBP.h>
58 #include <Xm/PushB.h>
59 #include <Xm/ToggleB.h>
60 #include <Xm/PushBG.h>
61 #include <Xm/PanedW.h>
62 #include <Xm/Form.h>
63 #include <Dt/Dts.h>
64 #include <Dt/Action.h>
65 #include <DtMail/IO.hh>
66 #include "RoamMenuWindow.h"
67 #include "SendMsgDialog.h"
68 #include "Undelete.hh"
69 #include "RoamCmds.h"
70 #include "ComposeCmds.hh"
71 #include "Application.h"
72 #include "RoamApp.h"
73 #include "DtMailWDM.hh"
74 #include "FindDialog.h"
75 #include "MsgScrollingList.hh"
76 #include "MsgHndArray.hh"
77 #include "MemUtils.hh"
78 #include "MailMsg.h"
79 #include "EUSDebug.hh"
80 #include "DtMailGenDialog.hh"
81 #include "DtMailHelp.hh"
82 #include <DtMail/DtMailError.hh>
83 #include "Help.hh"
84 #include <Dt/Help.h>
85 #include "Attachment.h"
86 #include "str_utils.h"
87
88 ComposeFamily::ComposeFamily(char *name,
89                              char *label,
90                              int active,
91                              RoamMenuWindow *window)
92 : RoamCmd(name, label, active, window)
93 {
94     _parent = window;
95 }
96
97 #ifndef CAN_INLINE_VIRTUALS
98 ComposeFamily::~ComposeFamily( void )
99 {
100 }
101 #endif /* ! CAN_INLINE_VIRTUALS */
102
103 // Append a formatted message to Compose's Text area.
104 // This routine is essentially the same as MsgScollingList::display_message()
105 // except for two major differences:
106 // 1. No RoamMenuWindow reference (so that Compose can be standalone).
107 // 2. Indent string can be used for "include" and "forward".
108 void
109 ComposeFamily::Display_entire_msg(DtMailMessageHandle msgno,
110                                   SendMsgDialog *compose, 
111                                   char *format 
112                                   )
113 {
114     DtMailEnv error;
115     
116     int num_bodyParts;
117     DtMail::MailBox *mbox = _menuwindow->mailbox();
118     DtMail::Message *msg = mbox->getMessage(error, msgno);
119     DtMail::Envelope *env = msg->getEnvelope(error);
120     DtMail::BodyPart *tmpBP = NULL;
121     DtMailBuffer tmpBuffer;
122     void *buffer = NULL;
123     unsigned long size = 0;
124     
125     Editor::InsertFormat ins_format = Editor::IF_NONE;
126     Editor::BracketFormat brackets = Editor::BF_NONE;
127     
128     // Do not need to wrap "include", "forward", and "indent" with
129     // catgets().
130     if ( strcmp(format, "include") == 0 ) {
131         ins_format = Editor::IF_BRACKETED;
132         brackets = Editor::BF_INCLUDE;
133     } else if ( strcmp(format, "forward") == 0 ) {
134         ins_format = Editor::IF_BRACKETED;
135         brackets = Editor::BF_FORWARD;
136     } else if ( strcmp(format, "indent") == 0 ) {
137         ins_format = Editor::IF_INDENTED;
138     }
139     
140     // Get the editor to display the body of message with the appropriate
141     // insert/bracket formatting.
142     // We only include the first body part of the message. Attachments, 
143     // etc. are "FORWARD"-ed but not "INCLUDE"-ed
144     
145     char * status_string;
146     DtMailBoolean firstBPHandled =
147         compose->get_editor()->textEditor()->set_message(
148                                          msg, 
149                                          &status_string, 
150                                          Editor::HF_ABBREV,
151                                          ins_format, 
152                                          brackets);
153
154     // Now need to handle the unhandled body parts of the message.
155     
156     num_bodyParts = msg->getBodyCount(error);
157     if (error.isSet()) {
158         // do something
159     }
160     
161     if (strcmp(format, "forward") == 0) {
162         // If the message has attachments, then let the attach pane
163         // handle attachments but not the first bodyPart (which has
164         // already been handled here).
165         
166         if ((num_bodyParts > 1) || (!firstBPHandled)) {
167
168             tmpBP = msg->getFirstBodyPart(error);
169             if (firstBPHandled) {
170                 //  The first bodyPart has already been handled.
171                 // The others, beginning from the second, need to be parsed 
172                 // and put into the attachPane.
173
174                 compose->setInclMsgHnd(msg, TRUE);
175                 tmpBP = msg->getNextBodyPart(error, tmpBP);
176
177             } else {
178                 // The first bodyPart was not handled.
179                 // It may not have been of type text.
180                 // The attachment pane needs to handle all the bodyParts
181                 // beginning with the first.
182             
183                 compose->setInclMsgHnd(msg, FALSE);
184             }
185             
186             char *name;
187             while (tmpBP != NULL) {
188                 tmpBP->getContents(
189                                     error, (const void **) &tmpBuffer.buffer,
190                                     &tmpBuffer.size,
191                                     NULL,
192                                     &name,
193                                     NULL,
194                                     NULL);
195                 if (error.isSet()) {
196                     // Do something
197                 }
198                 // It's possible for an attachment to not have a name.
199                 if (!name) {
200                     name = "NoName";
201                 }
202
203                 compose->add_att(name, tmpBuffer);
204                 tmpBP = msg->getNextBodyPart(error, tmpBP);
205                 if (error.isSet()) {
206                     // do something
207                 }
208
209                 if (strcmp(name, "NoName") != 0) {
210                     free(name);
211                 }
212             }
213             if (error.isSet()) {
214                 
215                 // do something
216             }
217         
218             // Need to call this after calling parseAttachments().
219
220             compose->get_editor()->manageAttachArea();
221         
222             // This message has attachment and is being included/forwarded,
223             // so need to fill the Compose Message Handle with attachment 
224             // BodyParts.
225             // See function for further details.
226
227             // compose->updateMsgHndAtt();
228         }
229     } 
230     else
231     {
232         // If the message has attachments, then let the attach pane
233         // handle attachments but not the first bodyPart (which has
234         // already been handled here).
235         
236         if ((num_bodyParts > 1) || (!firstBPHandled))
237         {
238             char        *att;
239             Editor      *editor = compose->get_editor()->textEditor();
240             
241             att = GETMSG(
242                         DT_catd, 1, 255,
243                         "------------------ Attachments ------------------\n");
244
245             tmpBP = msg->getFirstBodyPart(error);
246             if (firstBPHandled)
247               tmpBP = msg->getNextBodyPart(error, tmpBP);
248             
249             editor->append_to_contents(att, strlen(att));
250             while (tmpBP != NULL)
251             {
252                 editor->set_attachment(tmpBP, ins_format, brackets);
253                 tmpBP = msg->getNextBodyPart(error, tmpBP);
254                 if (error.isSet()) {
255                     // do something
256                 }
257             }
258         }
259     } 
260     
261     // Leave it up to check point routine for update or do it now???
262     compose->updateMsgHnd();
263 }
264
265 void
266 ComposeFamily::appendSignature(SendMsgDialog * compose)
267 {
268     DtMailEnv error;
269     DtMail::Session * d_session = theRoamApp.session()->session();
270     DtMail::MailRc * mail_rc = d_session->mailRc(error);
271
272     const char * value = NULL;
273     mail_rc->getValue(error, "signature", &value);
274     if (error.isSet()) {
275         return;
276     }
277
278     char * fullpath = d_session->expandPath(error, value);
279     compose->get_editor()->textEditor()->append_to_contents(fullpath);
280     if (NULL != fullpath)
281       free((void*) fullpath);
282     if (NULL != value)
283       free((void*) value);
284
285     compose->get_editor()->textEditor()->set_to_top();
286 }
287
288 char *
289 ComposeFamily::valueToAddrString(DtMailValueSeq & value)
290 {
291     int max_len = 0;
292     int count;
293
294     for (count = 0; count < value.length(); count++) {
295         max_len += strlen(*(value[count]));
296     }
297
298     char * str = new char[max_len + count + 1];
299     str[0] = 0;
300
301     DtMailBoolean need_comma = DTM_FALSE;
302
303     for (int cat = 0; cat < value.length(); cat++)
304     {
305         DtMailValue * val = value[cat];
306         DtMailAddressSeq *addr_seq = val->toAddress();
307
308         for (int ad = 0; ad < addr_seq->length(); ad++)
309         {
310             DtMailValueAddress * addr = (*addr_seq)[ad];
311
312             // Deal with mail address parser shortcomings
313             if ( strcmp(addr->dtm_address, ",") == 0 )
314                 continue ;
315
316             if (need_comma) {
317                 strcat(str, ", ");
318             }
319
320             need_comma = DTM_TRUE;
321
322             strcat(str, addr->dtm_address);
323         }
324
325         delete addr_seq;
326     }
327
328     return(str);
329 }
330
331
332 // Container menu "Compose==>New Message"
333 ComposeCmd::ComposeCmd( 
334                         char *name,
335                         char *label,
336                         int active,
337                         RoamMenuWindow *window
338                         ) : ComposeFamily( name, label, active, window )
339 {
340     _parent = NULL;
341 }
342
343 // Put up a blank compose window.
344 void
345 ComposeCmd::doit()
346 {
347     SendMsgDialog * newsend = theCompose.getWin();
348     if (newsend == NULL) {
349         DtMailGenDialog * dialog = _parent->genDialog();
350         
351         dialog->setToErrorDialog(GETMSG(DT_catd, 1, 203, "Mailer"),
352                                  GETMSG(DT_catd, 1, 204, "Unable to create a compose window."));
353         char * helpId = DTMAILHELPNOCOMPOSE;
354         int answer = dialog->post_and_return(helpId);
355     }
356
357     appendSignature(newsend);
358 }
359
360 // Container menu "Compose==>New, Include All" and "Compose==>Forward Message"
361 // The last parameter is a switch for "include" or "forward" format.
362 ForwardCmd::ForwardCmd( 
363                         char *name,
364                         char *label,
365                         int active,
366                         RoamMenuWindow *window, 
367                         int forward
368                         ) : ComposeFamily(name, label, active, window)
369 {
370     _forward = forward;
371     _parent = NULL;
372 }
373
374 // Forward or Include selected messages.
375 // For Include message(s), all Compose window header fields are left blank.
376 // For Forward message(s), the Compose window "Subject" header field is filled
377 // with the subject of the last selected message.
378 void
379 ForwardCmd::doit()
380 {
381     FORCE_SEGV_DECL(MsgHndArray, msgList);
382     FORCE_SEGV_DECL(MsgStruct, tmpMS);
383     DtMailMessageHandle msgno;
384     
385     // Get a Compose window.
386     SendMsgDialog *newsend = theCompose.getWin();
387     if ( newsend == NULL ) {
388         DtMailGenDialog * dialog = _parent->genDialog();
389         
390         dialog->setToErrorDialog(GETMSG(DT_catd, 1, 205, "Mailer"),
391                                  GETMSG(DT_catd, 1, 206, "Unable to create a compose window."));
392         char * helpId = DTMAILHELPNOCOMPOSE;
393         int answer = dialog->post_and_return(helpId);
394     }
395
396     // Put the signature above the message.
397     //
398     appendSignature(newsend);
399
400     // For Forwarding subject
401     DtMail::MailBox * mbox = _menuwindow->mailbox();
402     DtMail::Message * msg;
403     DtMail::Envelope * env;
404     DtMailValueSeq      value;
405     DtMailEnv error;
406     
407     // For each selected message, put it in the Compose window.
408     if ( msgList = _menuwindow->list()->selected() ) {
409         for ( int k = 0;  k < msgList->length();  k++ ) {
410             tmpMS = msgList->at(k);
411             msgno = tmpMS->message_handle;
412             if ( _forward ) {
413                 msg = mbox->getMessage(error, msgno);
414                 env = msg->getEnvelope(error);
415                 value.clear();
416                 env->getHeader(error, DtMailMessageSubject, DTM_TRUE, value);
417                 if (!error.isSet()) {
418                     const char *subject = *(value[0]);
419                     newsend->setHeader("Subject", subject);
420                     newsend->setTitle((char*) subject);
421                     newsend->setIconTitle((char*) subject);
422                 }
423                 Display_entire_msg(msgno, newsend, "forward");
424             } else {
425                 Display_entire_msg(msgno, newsend, "indent");
426             }
427         }
428     }
429     newsend->get_editor()->textEditor()->set_to_top();
430 }
431
432 // Container menu "Compose==>Reply to Semder" and
433 // "Compose==>Reply to Sender, Include"
434 // The last parameter is a switch for including the selected message or not.
435 ReplyCmd::ReplyCmd ( 
436                      char *name, 
437                      char *label,
438                      int active, 
439                      RoamMenuWindow *window, 
440                      int include 
441                      ) : ComposeFamily ( name, label, active, window )
442 {
443     _include = include;
444     _parent = NULL;
445 }
446
447 // For each message selected, reply to sender.
448 void
449 ReplyCmd::doit()
450 {
451     FORCE_SEGV_DECL(MsgHndArray, msgList);
452     FORCE_SEGV_DECL(MsgStruct, tmpMS);
453     DtMailMessageHandle msgno;
454     FORCE_SEGV_DECL(char, from);
455     FORCE_SEGV_DECL(char, subject);
456     FORCE_SEGV_DECL(char, cc);
457     DtMailEnv error;
458     DtMail::MailBox * mbox = _menuwindow->mailbox();
459     
460     // Initialize the error.
461     error.clear();
462     
463     if (msgList = _menuwindow->list()->selected())
464     {
465         for ( int i=0; i < msgList->length(); i++ ) {
466             tmpMS = msgList->at(i);
467             msgno = tmpMS->message_handle;
468             SendMsgDialog *newsend = theCompose.getWin();
469             if ( newsend == NULL ) {
470                 DtMailGenDialog * dialog = _parent->genDialog();
471                 
472                 dialog->setToErrorDialog(GETMSG(DT_catd, 1, 207, "Mailer"),
473                                          GETMSG(DT_catd, 1, 208, "Unable to create a compose window."));
474                 char * helpId = DTMAILHELPNOCOMPOSE;
475                 int answer = dialog->post_and_return(helpId);
476             }
477             XmUpdateDisplay( newsend->baseWidget() );
478             
479             DtMail::Message * msg = mbox->getMessage(error, msgno);
480             DtMail::Envelope * env = msg->getEnvelope(error);
481             
482             DtMailValueSeq      value;
483             
484             env->getHeader(error, DtMailMessageSender, DTM_TRUE, value);
485             if (error.isSet()) {
486                 newsend->setHeader("To", "nobody@nowhere");
487             }
488             else {
489                 char * addr_str = valueToAddrString(value);
490                 newsend->setHeader("To", addr_str);
491                 delete [] addr_str;
492             }
493             
494             value.clear();
495             env->getHeader(error, DtMailMessageSubject, DTM_TRUE, value);
496             if (error.isSet()) {
497                 subject = new char[200];
498                 strcpy(subject, "Re: ");
499                 DtMailValueSeq sent;
500                 env->getHeader(error,
501                                DtMailMessageSentTime,
502                                DTM_TRUE,
503                                sent);
504                 if (error.isSet()) {
505                     strcat(subject, "Your Message");
506                 }
507                 else {
508                     strcat(subject, "Your Message Sent on ");
509                     strcat(subject, *(sent[0]));
510                 }
511                 newsend->setHeader("Subject", subject);
512             }
513             else {
514                 // Get the BE store of header.  It may contain newlines or 
515                 // tab chars which can munge the scrolling list's display!
516
517                 const char * orig = *(value[0]);
518
519                 int fc;
520                 int orig_length;
521                 char *tmp_subj;
522
523                 // Check if BE store contains the funky chars.
524
525                 for (fc = 0, orig_length = strlen(orig), 
526                       tmp_subj = (char *) orig; 
527                     fc < orig_length; 
528                     fc++, tmp_subj++) {
529
530                     char c = *tmp_subj;
531                     if ((c == '\n') 
532                      || (c == '\t') 
533                      || (c == '\r')) {
534
535                         break;
536                     }
537                 }
538
539                 subject = new char[fc+6];
540                 
541                 if (strncasecmp(orig, "Re:", 3)) {
542                     strcpy(subject, "Re: ");
543                 }
544                 else {
545                     *subject = 0;
546                 }
547                 
548                 strncat((char *)subject, orig, fc);
549
550                 newsend->setHeader("Subject", subject);
551             }
552             
553             newsend->setTitle(subject);
554             newsend->setIconTitle(subject);
555             delete [] subject;
556
557             if ( _include ) {
558                 Display_entire_msg(msgno, newsend, "indent");
559                 newsend->get_editor()->textEditor()->set_to_top();
560             }
561             appendSignature(newsend);
562                 newsend->setInputFocus(1);
563         }
564
565         delete msgList;
566     }
567 }
568
569 // Container menu "Compose==>Reply to All" and "Compose==>Reply to All, Include"
570 // The last parameter is a switch for including the selected message or not.
571 ReplyAllCmd::ReplyAllCmd( 
572                           char *name,
573                           char *label,
574                           int active,
575                           RoamMenuWindow *window, 
576                           int include 
577                           ) : ComposeFamily( name, label, active, window )
578 {
579     _include = include;
580     _parent = NULL;
581 }
582
583 // For each message selected, reply to everybody.
584 void
585 ReplyAllCmd::doit()
586 {
587     FORCE_SEGV_DECL(MsgHndArray, msgList);
588     FORCE_SEGV_DECL(MsgStruct, tmpMS);
589     FORCE_SEGV_DECL(char, subject);
590     FORCE_SEGV_DECL(char, to);
591     FORCE_SEGV_DECL(char, buffer);
592     DtMailMessageHandle msgno;
593     DtMail::MailBox *mbox = _menuwindow->mailbox();
594     DtMailEnv error;
595     char *currentCcValue;
596     SendMsgDialog *newsend;
597     DtMailGenDialog * dialog;
598     DtMail::Message *msg;
599     DtMail::Envelope *env;
600
601
602     // Initialize the mail_error.
603     error.clear();
604     
605     
606     if ( msgList = _menuwindow->list()->selected() )
607         for ( int k = 0;  k < msgList->length();  k++ ) {
608             DtMailValueSeq      value ;
609             
610             tmpMS = msgList->at(k);
611             msgno = tmpMS->message_handle;
612             newsend = theCompose.getWin();
613             if ( newsend == NULL ) {
614                 dialog = _parent->genDialog();
615                 
616                 dialog->setToErrorDialog(GETMSG(DT_catd, 1, 209, "Mailer"),
617                                          GETMSG(DT_catd, 1, 210, "Unable to create a compose window."));
618                 char * helpId = DTMAILHELPNOCOMPOSE;
619                 int answer = dialog->post_and_return(helpId);
620             }
621             msg = mbox->getMessage(error, msgno);
622             env = msg->getEnvelope(error);
623             
624             env->getHeader(
625                            error, 
626                            DtMailMessageToReply,
627                            DTM_TRUE, 
628                            value);
629             
630             env->getHeader(
631                            error, 
632                            DtMailMessageSender, 
633                            DTM_TRUE, 
634                            value);
635
636             char * addr_str = valueToAddrString(value);
637             newsend->setHeader("To", addr_str);
638             delete [] addr_str;
639             value.clear();
640             env->getHeader(
641                            error, 
642                            DtMailMessageSubject, 
643                            DTM_TRUE, 
644                            value);
645             if ( error.isSet() ) {
646                 subject = new char[200];
647                 strcpy(subject, "Re: ");
648                 DtMailValueSeq sent;
649                 env->getHeader(error,
650                                DtMailMessageSentTime,
651                                DTM_TRUE,
652                                sent);
653                 if (error.isSet()) {
654                     strcat(subject, "Your Message");
655                 }
656                 else {
657                     strcat(subject, "Your Message Sent on ");
658                     strcat(subject, *(sent[0]));
659                 }
660                 newsend->setHeader("Subject", subject);
661             } else {
662                 // Get the BE store of header.  It may contain newlines or 
663                 // tab chars which can munge the scrolling list's display!
664
665                 const char * orig = *(value[0]);
666
667
668                 int fc = 0;
669                 int orig_length;
670                 char *tmp_subj;
671
672                 // Check if BE store contains the funky chars.
673
674                 for (fc = 0, orig_length = strlen(orig), 
675                       tmp_subj = (char *)orig; 
676                      fc < orig_length; 
677                      fc++, tmp_subj++) {
678
679                     char c = *tmp_subj;
680                     if ((c == '\n') 
681                      || (c == '\t') 
682                      || (c == '\r')) {
683
684                         break;
685                     }
686                 }
687
688                 subject = new char[fc+6];
689                 
690                 if (strncasecmp(orig, "Re:", 3)) {
691                     strcpy(subject, "Re: ");
692                 }
693                 else {
694                     *subject = 0;
695                 }
696                 
697                 strncat((char *)subject, orig, fc);
698
699                 newsend->setHeader("Subject", subject);
700             }
701             value.clear();
702             env->getHeader(
703                            error, 
704                            DtMailMessageCcReply, 
705                            DTM_TRUE, 
706                            value);
707             if (!error.isSet()) {
708                 // Strip out newlines from the cc line.  They *may* be 
709                 // present.
710                 currentCcValue = valueToAddrString(value);
711
712                 newsend->setHeader("Cc", currentCcValue);
713                 delete [] currentCcValue ;
714             }
715
716             newsend->setTitle(subject);
717             newsend->setIconTitle(subject);
718             delete [] subject;
719
720             if ( _include ) {
721                 Display_entire_msg(msgno, newsend, "indent");
722                 newsend->get_editor()->textEditor()->set_to_top();
723             }
724             appendSignature(newsend);
725                 newsend->setInputFocus(1);
726         }
727 }
728
729 TemplateCmd::TemplateCmd(char *name,
730                          char *label,
731                          int active,
732                          SendMsgDialog * compose,
733                          const char * file)
734 : NoUndoCmd(name, label, active)
735 {
736     _compose = compose;
737
738     if (*file != '/' && *file != '~') {
739         // Relative path.  Should be relative to home directory
740         _file = (char *)malloc(strlen(file) + 4);
741         if (_file != NULL) {
742                 strcpy(_file, "~/");
743                 strcat(_file, file);
744         }
745     } else {
746         _file = strdup(file);
747     }
748 }
749
750 TemplateCmd::~TemplateCmd(void)
751 {
752     free(_file);
753 }
754
755 void
756 TemplateCmd::doit()
757 {
758     DtMailEnv error;
759     DtMail::Session * d_session = theRoamApp.session()->session();
760     DtMailGenDialog * dialog = _compose->genDialog();
761     DtMailBuffer mbuf;
762
763     char * fullpath = d_session->expandPath(error, _file);
764
765     // Map the file and try to parse it as a message. If it is a message,
766     // then load it with headers. Otherwise, throw everything into the
767     // editor.
768     //
769     int fd = SafeOpen(fullpath, O_RDONLY);
770     if (fd < 0) {
771         dialog->setToErrorDialog(GETMSG(DT_catd, 1, 211, "Mailer"),
772                                  GETMSG(DT_catd, 1, 212, "The template does not exist."));
773         char * helpId = DTMAILHELPNOTEMPLATE;
774         int answer = dialog->post_and_return(helpId);
775         free(fullpath);
776         return;
777     }
778
779     struct stat buf;
780     if (SafeFStat(fd, &buf) < 0) {
781         dialog->setToErrorDialog(GETMSG(DT_catd, 1, 213, "Mailer"),
782                                  GETMSG(DT_catd, 1, 214, "The template appears to be corrupt."));
783         char * helpId = DTMAILHELPCORRUPTTEMPLATE;
784         int answer = dialog->post_and_return(helpId);
785         SafeClose(fd);
786         free(fullpath);
787         return;
788     }
789
790     int page_size = (int)sysconf(_SC_PAGESIZE);
791     size_t map_size = (size_t) (buf.st_size + 
792                                 (page_size - (buf.st_size % page_size)));
793
794     int free_buf = 0;
795     mbuf.size = buf.st_size;
796 #ifdef __osf__
797     // This version of mmap does NOT allow requested length to be
798     // greater than the file size ...  in contradiction to the
799     // documentation (don't round up).
800     mbuf.buffer = mmap(0, buf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
801 #else
802     mbuf.buffer = mmap(0, map_size, PROT_READ, MAP_PRIVATE, fd, 0);
803 #endif
804     if (mbuf.buffer == (char *)-1) {
805         free_buf = 1;
806         mbuf.buffer = new char[mbuf.size];
807         if (mbuf.buffer == NULL) {
808             dialog->setToErrorDialog(GETMSG(DT_catd, 1, 215, "Mailer"),
809                                      GETMSG(DT_catd, 1, 216, "There is not enough memory to load the template."));
810             char * helpId = DTMAILHELPNOMEMTEMPLATE;
811             int answer = dialog->post_and_return(helpId);
812             SafeClose(fd);
813             free(fullpath);
814             return;
815         }
816
817         if (SafeRead(fd, mbuf.buffer, (unsigned int)mbuf.size) < mbuf.size) {
818             dialog->setToErrorDialog(GETMSG(DT_catd, 1, 217, "Mailer"),
819                                      GETMSG(DT_catd, 1, 218, "The template appears to be corrupt."));
820             char * helpId = DTMAILHELPERROR;
821             int answer = dialog->post_and_return(helpId);
822             SafeClose(fd);
823             delete [] mbuf.buffer;
824             free(fullpath);
825             return;
826         }
827     }
828
829     // Now we ask the library to parse it. If this fails for any reason, this
830     // is not a message, so we give up.
831     //
832     DtMail::Message * msg = d_session->messageConstruct(error,
833                                                         DtMailBufferObject,
834                                                         &mbuf,
835                                                         NULL,
836                                                         NULL,
837                                                         NULL);
838     if (error.isSet()) {
839         _compose->get_editor()->textEditor()->append_to_contents((char *)mbuf.buffer,
840                                                                mbuf.size);
841     }
842     else {
843         _compose->loadHeaders(msg, DTM_TRUE);
844
845         DtMail::BodyPart * bp = msg->getFirstBodyPart(error);
846         if (error.isNotSet()) {
847             const void * contents;
848             unsigned long length;
849
850             bp->getContents(error,
851                             &contents,
852                             &length,
853                             NULL,
854                             NULL,
855                             NULL,
856                             NULL);
857
858             _compose->get_editor()->textEditor()->append_to_contents(
859                                                 (char *)contents, length);
860         }
861     }
862
863     free(fullpath);
864
865     if (free_buf) {
866         free(mbuf.buffer);
867     }
868     else {
869         munmap((char *)mbuf.buffer, map_size);
870     }
871
872     SafeClose(fd);
873 }
874
875 HideShowCmd::HideShowCmd(char *name,
876                          char *widgetlabel,
877                          int active,
878                          SendMsgDialog * compose,
879                          const char * label)
880 : NoUndoCmd(name, (char *)widgetlabel, active)
881 {
882     _compose = compose;
883     _header = strdup(label);
884 }
885
886 HideShowCmd::~HideShowCmd(void)
887 {
888     if (_header) {
889         free(_header);
890     }
891 }
892
893 void
894 HideShowCmd::doit(void)
895 {
896     _compose->changeHeaderState(_header);
897 }