Remove Unixware and openserver support
[oweals/cde.git] / cde / programs / dtmail / dtmail / AttachArea.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: AttachArea.C /main/18 1999/03/25 14:16:24 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 #ifndef I_HAVE_NO_IDENT
44 #endif
45
46 #include <EUSCompat.h>
47 #include <unistd.h>
48 #include <fcntl.h>
49 #include <sys/stat.h>
50 #include <stdio.h>
51 #include <Dt/Editor.h>
52 #include <Xm/ColorObjP.h>
53
54 #include "EUSDebug.hh"
55
56 #if defined(NEED_MMAP_WRAPPER)
57 extern "C" {
58 #endif
59
60 #include <sys/mman.h>
61
62 #if defined(NEED_MMAP_WRAPPER)
63 }
64 #endif
65
66
67 extern "C" {
68 extern XtPointer _XmStringUngenerate (
69                                 XmString string,
70                                 XmStringTag tag,
71                                 XmTextType tag_type,
72                                 XmTextType output_type);
73 }
74
75
76 #include <stdio.h>
77 #include <ctype.h>
78 #include <sys/stat.h>
79 #include <sys/types.h>
80
81
82 #include <Xm/BulletinB.h>
83 #include <Xm/Form.h>
84 #include <Xm/RowColumn.h>
85 #include <Xm/ScrolledW.h>
86 #include <Xm/DrawingA.h>
87 #include <Xm/ScrollBar.h>
88 #include <Xm/PushBG.h>
89 #include <Xm/FileSB.h>
90 #include <Xm/SelectioB.h>
91 #include <Xm/Label.h>
92 #include <Xm/LabelG.h>
93 #include <Xm/AtomMgr.h>
94 #include <Xm/Xm.h>
95 #include <Xm/Screen.h>
96 #include <Xm/ToggleB.h>
97 #include <X11/IntrinsicP.h>
98 #include <X11/Xatom.h>
99
100 #include "Attachment.h"
101 #include "AttachArea.h"
102 #include "Icon.h"
103 #include "MenuBar.h"
104 #include "RoamApp.h"
105 #include "RoamMenuWindow.h"
106
107 #include "MsgScrollingList.hh"
108 #include "ViewMsgDialog.h"
109 #include "SendMsgDialog.h"
110 #include "MailMsg.h"            // DT_catd defined here
111 #include <DtMail/DtMail.hh>    // time_t defined here
112 #include <DtMail/IO.hh>                    // SafeAccess...
113
114 #include "Help.hh"
115 #include "DtMailHelp.hh"
116
117 extern nl_catd  DtMailMsgCat;
118
119 #define equal(a, b) (!strcmp(a,b))
120 #define HSPACE 10
121 #define VSPACE 10
122 #define MAXATOM 2048    // ?????
123
124 // This is the new one
125 AttachArea::AttachArea ( 
126         Widget parent, 
127         DtMailEditor *owner,
128         char *name
129 ) : UIComponent (name)
130 {
131     // Unique stuff
132
133     _myOwner = owner;
134     _parent  = parent;
135
136     _attachmentList=NULL;
137
138     _w = NULL;
139     _iconCount = 0;
140     _iconSelectedCount = 0;
141     _deleteCount = 0;
142
143     _fsDialog = NULL;
144     _fsState = NOTSET;
145     _lastRow = 0;
146     _currentRow = 0;
147     _attachmentsSize = 0;
148     _selectedAttachmentsSize = 0;
149     _clientData = NULL;
150     _renameDialog = NULL;
151
152     _myRMW = NULL;
153     _myVMD = NULL;
154     _mySMD = NULL;
155     
156     _pendingAction = FALSE;
157     _numPendingActions = 0;
158
159     _attach_area_selection_state = AA_SEL_NONE;
160     _cache_single_attachment = NULL;
161
162     _no_selected_label = NULL;
163     _selected_label = NULL;
164     rowOfAttachmentsStatus = NULL;
165     _attachments_status = NULL;
166     _attachments_summary = NULL;
167     _mailbox = NULL;
168     _attachAreaWidth = 0;
169     _attachAreaHeight = 0;
170     _rc = NULL;
171     _sw = NULL;
172     _vsb = NULL;
173     _message = NULL;
174     _clipWindow = NULL;
175     _open = NULL;
176     _saveas = NULL;
177     _selectall = NULL;
178     _unselectall = NULL;
179     _menuBar = NULL;
180     _background = 0;
181     _foreground = 0;
182     _appBackground = 0;
183     _appForeground = 0;
184     _fileCmdList = NULL;
185     _editCmdList = NULL;
186     _size_selected_label = NULL;
187     _format_button = NULL;
188     _descriptionDialog = NULL;
189     _no_attachments_label = NULL;
190     _attachments_label = NULL;
191     _size_attachments_label = NULL;
192     
193     
194 }
195
196 void
197 AttachArea::initialize()
198 {
199
200     // We're making the assumption here that this widget's parent`
201     // is also a form
202
203     XtWidgetGeometry size;
204     Dimension parWid, parHeight;
205     Dimension txt_w, txt_h;
206     XmFontList fl;
207     XmString xms;
208
209     int         colorUse;
210     short       act, inact, prim, second, text;
211     XmPixelSet  pixels[XmCO_NUM_COLORS];
212
213
214     _w = XtVaCreateManagedWidget (
215                         "AttachPane",
216                         xmFormWidgetClass, _parent, 
217                         NULL);
218
219     // Get pixel data.
220     XmeGetColorObjData(XtScreen(_parent), &colorUse, pixels, XmCO_NUM_COLORS,
221                        &act, &inact, &prim, &second, &text);
222     _foreground = pixels[text].fg;
223     _background = pixels[text].sc;
224
225     parWid = _myOwner->textEditor()->get_text_width();
226
227     fl = _myOwner->textEditor()->get_text_fontList();
228     xms = XmStringCreateLocalized("Xyb");
229     XmStringExtent(fl, xms, &txt_w, &txt_h);
230     parHeight = txt_h + Icon::maxIconHeight() + (2*VSPACE);
231
232     _appBackground = _background;
233     _appForeground = _foreground;
234
235     _sw = XtVaCreateManagedWidget ( 
236                                     "AttachPane_ScrolledWindow", 
237                                     xmScrolledWindowWidgetClass, _w, 
238                                     XmNscrollingPolicy,  XmAPPLICATION_DEFINED,
239                                     XmNrightAttachment,  XmATTACH_FORM,
240                                     XmNleftAttachment,   XmATTACH_FORM,
241                                     XmNtopAttachment,    XmATTACH_FORM,
242                                     XmNshadowThickness, (Dimension)1,
243                                     XmNspacing, 2,
244                                     XmNwidth,        parWid,
245                                     XmNheight,       parHeight,
246                                     NULL);
247
248     rowOfAttachmentsStatus = XtCreateManagedWidget("Attachments_Status",
249                                 xmFormWidgetClass,
250                                 _w, NULL, 0);
251
252      XtVaSetValues(rowOfAttachmentsStatus,
253         XmNrightAttachment,     XmATTACH_FORM, 
254         XmNleftAttachment,      XmATTACH_FORM, 
255         XmNtopAttachment,       XmATTACH_WIDGET,
256         XmNtopWidget,           _sw,
257         XmNtopOffset,           5,
258         XmNbottomOffset,        5,
259         NULL );
260
261     this->addToRowOfAttachmentsStatus();
262
263     size.request_mode = CWHeight;
264     XtQueryGeometry(rowOfAttachmentsStatus, NULL, &size);
265
266     XtVaSetValues(
267         rowOfAttachmentsStatus,
268         XmNpaneMaximum, size.height,
269         XmNpaneMinimum, size.height,
270         NULL
271     );
272
273     _vsb = XtVaCreateManagedWidget("vsb", xmScrollBarWidgetClass, _sw,
274                     XmNorientation, XmVERTICAL,
275                     XmNsliderSize, 1,
276                     XmNmaximum, 1,
277                     XmNpageIncrement, 1,
278                     NULL);
279
280     XtAddCallback(
281         _vsb, 
282         XmNvalueChangedCallback,&AttachArea::valueChangedCallback,
283         (XtPointer) this 
284     );
285
286     XtAddCallback(
287         _vsb, 
288         XmNdragCallback, &AttachArea::dragCallback,
289         (XtPointer) this 
290     );
291
292     _clipWindow = XtVaCreateManagedWidget("AttachArea_clipWindow", 
293                     xmDrawingAreaWidgetClass, _sw,
294                     XmNresizePolicy, XmRESIZE_NONE,
295                     XmNbackground, _background,
296                     XmNwidth,        parWid,
297                     XmNheight,       parHeight,
298                     NULL);
299     XmScrolledWindowSetAreas(_sw, NULL, _vsb, _clipWindow);
300
301     XtManageChild(_clipWindow);
302     XtManageChild(_vsb);
303     XtManageChild(_sw);
304
305     
306     // Set RowCol to NULL here.
307     // It gets set in the expose_all_attachments.
308
309     _rc = NULL;
310
311     CalcSizeOfAttachPane();
312
313     installDestroyHandler();
314 }
315
316 AttachArea::~AttachArea()
317 {
318 }
319
320 void AttachArea::addToList( Attachment *attachment )
321 {
322     Attachment **newList;
323     int i;
324
325     newList = new Attachment*[ _iconCount + 1 ];
326     for(i=0; i < _iconCount; i++)
327         newList[i] = _attachmentList[i];
328  
329     if (_attachmentList)
330         delete []_attachmentList;
331
332     _attachmentList = newList;
333
334     _attachmentList[ _iconCount ] = attachment;
335
336     _iconCount++;
337     
338 //    setAttachmentsLabel();
339 }
340
341 #ifdef DEAD_WOOD
342 void AttachArea::setAttachmentsLabel( )
343 {
344     char *c = new char[256];
345     XmString xmstr;
346     String str;
347     unsigned int last_displayCount, last_selectedCount;
348     unsigned int displayCount = _iconCount - _deleteCount;
349     unsigned int attachmentsSize;
350
351     if((displayCount) == 0) {
352         XtUnmanageChild(_no_attachments_label);
353         XtUnmanageChild(_attachments_label);
354         XtUnmanageChild(_size_attachments_label);
355         XtUnmanageChild(_no_selected_label);
356         XtUnmanageChild(_selected_label);
357         XtUnmanageChild(_size_selected_label);
358     } else {
359         CalcAttachmentsSize();
360         attachmentsSize = getAttachmentsSize();
361
362         // Number of Attachments
363         XtVaGetValues(_no_attachments_label,
364                 XmNlabelString, &xmstr,
365                 NULL);
366         str = NULL;
367         str = (char *) _XmStringUngenerate(
368                                         xmstr, NULL,
369                                         XmMULTIBYTE_TEXT, XmMULTIBYTE_TEXT);
370         if (NULL == str) return; // internal error
371         last_displayCount = (unsigned int)strtol(str, NULL, 10);
372         XtFree(str);
373
374         // Number of Attachments Selected
375         XtVaGetValues(_no_selected_label,
376                 XmNlabelString, &xmstr,
377                 NULL);
378         str = NULL;
379         str = (char *) _XmStringUngenerate(
380                                         xmstr, NULL,
381                                         XmMULTIBYTE_TEXT, XmMULTIBYTE_TEXT);
382         if (NULL == str) return; // internal error
383         last_selectedCount = (unsigned int)strtol(str, NULL, 10);
384         XtFree(str);
385
386         if((last_displayCount == 0 && displayCount == 1) ||
387            (last_displayCount == 2 && displayCount == 1)) {
388             sprintf(c, GETMSG(DT_catd, 12, 1, "Attachment"));
389             XtVaSetValues(_attachments_label,
390                 XtVaTypedArg, XmNlabelString, XtRString, c, strlen(c)+1,
391                 NULL);
392         } else if(last_displayCount == 1 && displayCount == 2) {
393             sprintf(c, GETMSG(DT_catd, 12, 2, "Attachments"));
394             XtVaSetValues(_attachments_label,
395                 XtVaTypedArg, XmNlabelString, XtRString, c, strlen(c)+1,
396                 NULL);
397         }
398         if(last_displayCount != displayCount) {
399             sprintf(c, GETMSG(DT_catd, 12, 3, "displayCount"));
400             XtVaSetValues(_no_attachments_label,
401                 XtVaTypedArg, XmNlabelString, XtRString, c, strlen(c)+1,
402                 NULL);
403         }
404         sprintf(c, "(%s),", calcKbytes(attachmentsSize));
405         XtVaSetValues(_size_attachments_label,
406             XtVaTypedArg, XmNlabelString, XtRString, c, strlen(c)+1,
407             NULL);
408
409         if(last_selectedCount != _iconSelectedCount) {
410             sprintf(c, "%d", _iconSelectedCount); 
411             XtVaSetValues(_no_selected_label,
412                 XtVaTypedArg, XmNlabelString, XtRString, c, strlen(c)+1,
413                 NULL);
414             sprintf(c, "(%s)", calcKbytes(getSelectedAttachmentsSize())); 
415             XtVaSetValues(_size_selected_label,
416                 XtVaTypedArg, XmNlabelString, XtRString, c, strlen(c)+1,
417                 NULL);
418         }
419         if(!XtIsManaged(_no_attachments_label)) {
420             XtManageChild(_no_attachments_label);
421             XtManageChild(_attachments_label);
422             XtManageChild(_size_attachments_label);
423             XtManageChild(_no_selected_label);
424             XtManageChild(_selected_label);
425             XtManageChild(_size_selected_label);
426         }
427     }
428     delete [] c;
429 }
430 #endif /* DEAD_WOOD */
431
432 int AttachArea::getSelectedIconCount()
433 {
434     Attachment **list = getList();
435     int num_selected = 0;
436
437     for (int i = 0; i < getIconCount(); i++) {
438         if (!list[i]->isDeleted() && list[i]->isSelected())
439             num_selected++;
440     }
441     return (num_selected);
442 }
443
444 #ifdef DEAD_WOOD
445 void AttachArea::CalcAttachmentsSize( )
446 {
447      Attachment **list = getList();
448      unsigned int total = 0;
449      int i;
450
451      int num_icons = getIconCount();
452
453  
454      for(i=0;i<num_icons;i++)
455         if(!list[i]->isDeleted())
456             total += (unsigned int)list[i]->getContentsSize();
457      
458      setAttachmentsSize(total);
459 }
460 #endif /* DEAD_WOOD */
461
462 Attachment *
463 AttachArea::getSelectedAttachment()
464 {
465     return _cache_single_attachment;
466 }
467
468
469 void
470 AttachArea::MenuButtonHandler(
471     Widget ,
472     XtPointer cd,
473     XEvent *event,
474     Boolean *)
475 {
476         AttachArea *obj = (AttachArea *)cd;
477
478         if(event->xany.type != ButtonPress)
479                 return;
480
481         XButtonEvent *be = (XButtonEvent *)event;
482
483         if(be->button == theApplication->bMenuButton())
484                 obj->_myOwner->owner()->postAttachmentPopup(event);
485 }
486
487 void 
488 AttachArea::inputCallback(Widget, XtPointer client_data, XtPointer call_data)
489 {
490     AttachArea *obj = (AttachArea *) client_data;
491     XmDrawingAreaCallbackStruct *cb = (XmDrawingAreaCallbackStruct *)call_data;
492
493     if(cb->reason != XmCR_INPUT         ||
494         cb->event->xany.type != ButtonPress)
495         return;
496
497     if(((XButtonEvent *)cb->event)->button == Button1)
498         obj->unselectOtherSelectedAttachments(NULL);
499 }
500
501 void AttachArea::resizeCallback ( 
502                                   Widget w, 
503                                   XtPointer clientData, 
504                                   XtPointer //callData
505                                   )
506 {
507     XtArgVal wid;
508
509     AttachArea *obj = (AttachArea *) clientData;
510     XtVaGetValues(
511         w,
512         XmNwidth, &wid,
513         NULL
514     );
515
516     obj->resize((Dimension)wid);
517 }
518
519 void AttachArea::resize(
520     Dimension wid
521 )
522 {
523     int i;
524     Attachment **list = getList();
525
526     _attachAreaWidth = wid;
527     XtVaSetValues(_clipWindow, XmNwidth, _attachAreaWidth, NULL);
528
529     for (i=0; i<getIconCount(); i++)
530       list[i]->unmanageIconWidget();
531
532     CalcAllAttachmentPositions();
533     CalcLastRow();
534     AdjustCurrentRow();
535     SetScrollBarSize(getLastRow()+1);
536     DisplayAttachmentsInRow(_currentRow);
537 }
538
539 void AttachArea::CalcSizeOfAttachPane( )
540 {
541     _attachAreaWidth = _myOwner->textEditor()->get_text_width();
542     XtVaSetValues(_clipWindow, XmNwidth, _attachAreaWidth, NULL);
543 }
544
545 void AttachArea::activateDeactivate()
546 {
547     //
548     // If exactly one icon is selected then activate the open command 
549     //
550
551     if(getIconSelectedCount() == 1) {
552         openCmd()->activate();
553     } else {
554         openCmd()->deactivate();
555     }
556
557     // If no icons are selected then deactivate the OK button on the FS Dialog
558
559     if(getIconSelectedCount() > 0) {
560         if(getFsDialog())
561             XtSetSensitive(
562                 XmSelectionBoxGetChild( 
563                     getFsDialog(), XmDIALOG_OK_BUTTON), TRUE
564                 );
565     } else {
566         if(getFsDialog())
567             XtSetSensitive(
568                 XmSelectionBoxGetChild( 
569                     getFsDialog(), XmDIALOG_OK_BUTTON
570                 ), 
571                 (getFsState() == SAVEAS) ? FALSE : TRUE
572             );
573     }
574 }
575
576 // Used by Compose window (SMD)
577 // Given a filename, add it to message and to attachArea.
578
579 Attachment*
580 AttachArea::addAttachment(
581                           DtMail::Message* msg,
582                           DtMail::BodyPart *lastAttBP,
583                           char *filename,
584                           char *name
585                           )
586 {
587     int fd;
588     struct stat s;
589     Boolean validtype = TRUE;
590     DtMail::BodyPart * bp = NULL;
591     DtMailEnv mail_error;
592     int answer;
593     char *helpId = NULL;
594
595     mail_error.clear();
596
597     char *errormsg = new char[512];
598     char *buf = new char[2048];
599     char *buffer = NULL, *lbl;
600     char *fname_start;
601
602     for (fname_start = filename + strlen(filename) - 1;
603          fname_start >= filename && *fname_start != '/'; fname_start--) {
604         continue;
605     }
606     if (*fname_start == '/') {
607         fname_start += 1;
608     }
609
610     bp = msg->newBodyPart(mail_error, lastAttBP);       
611
612     if (SafeAccess(filename, F_OK) != 0) {
613         sprintf(buf, GETMSG(DT_catd, 3, 34, "%s does not exist."),
614                 filename);
615         answer = this->handleErrorDialog(GETMSG(DT_catd, 1, 81, "Mailer"), 
616                                          buf);
617         delete [] buf;
618         delete [] errormsg;
619         return(NULL);
620     }
621
622     SafeStat(filename, &s);
623
624     if(S_ISFIFO(s.st_mode)) {
625         sprintf(errormsg,
626                 GETMSG(DT_catd, 12, 4, "Cannot attach FIFO files: %s"), filename);
627         validtype = FALSE;
628     } else if(S_ISCHR(s.st_mode)) {
629         sprintf(
630             errormsg,
631             GETMSG(DT_catd, 12, 5, "Cannot attach character special files: %s"), filename
632         );
633         validtype = FALSE;
634     } else if(S_ISDIR(s.st_mode)) {
635         sprintf(
636             errormsg,
637             GETMSG(DT_catd, 12, 6, "Cannot attach directories: %s"), filename
638         );
639         validtype = FALSE;
640     } else if(S_ISBLK(s.st_mode)) {
641         sprintf(errormsg,
642                 GETMSG(DT_catd, 12, 7, "Cannot attach block special files: %s"), filename
643         );
644         validtype = FALSE;
645     } else if(S_ISSOCK(s.st_mode)) {
646         sprintf(errormsg,
647                 GETMSG(DT_catd, 12, 8, "Cannot attach socket files: %s"), filename
648         );
649         validtype = FALSE;
650     }
651     if(validtype == FALSE) {
652         answer = this->handleErrorDialog(GETMSG(DT_catd, 1, 81, "Mailer"), 
653                                          errormsg,
654                                          NULL);
655         delete [] buf;
656         delete [] errormsg;
657         return(NULL);
658     }
659
660     fd = SafeOpen(filename, O_RDONLY);
661         
662     if (fd < 0) {
663         sprintf(buf, GETMSG(DT_catd, 3, 35, "Unable to open %s."), filename);
664         helpId = DTMAILHELPNOOPEN;
665         answer = this->handleErrorDialog(GETMSG(DT_catd, 1, 82, "Mailer"), 
666                                          buf,
667                                          helpId);
668         delete [] buf;
669         delete [] errormsg;
670         return(NULL);
671     }
672
673     int page_size = (int)sysconf(_SC_PAGESIZE);
674     size_t map_size = (size_t) (s.st_size + 
675                                     (page_size - (s.st_size % page_size)));
676     char * map;
677
678 #if defined(__osf__)
679     // This version of mmap does NOT allow requested length to be
680     // greater than the file size ...  in contradiction to the
681     // documentation (don't round up).
682     map = (char *) mmap(0, s.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
683 #else
684     map = (char *) mmap(0, map_size, PROT_READ, MAP_PRIVATE, fd, 0);
685 #endif
686
687     if (map == (char *)-1) {
688         // We could not map it for some reason. Let's just read it into
689         // buffer and pass it to XmText.
690         //
691
692         buffer = new char[s.st_size + 1];
693
694         if (!buffer) {
695             sprintf(buf, "%s",
696                     GETMSG(DT_catd, 3, 36, "Unable to allocate memory."));
697             helpId = DTMAILHELPNOALLOCMEM;
698             answer = this->handleErrorDialog(GETMSG(DT_catd, 1, 83, "Mailer"), 
699                                              buf,
700                                              helpId);
701             return(NULL);
702         }
703
704         if (read(fd, buffer, (unsigned int) s.st_size) < 0) {
705             SafeClose(fd);
706             delete [] buf;
707             delete [] buffer;
708             delete [] errormsg;
709             return(NULL);
710         }
711         buffer[s.st_size] = 0;
712         bp->setContents(
713                 mail_error, buffer, s.st_size, NULL, fname_start, 0, NULL
714                 );
715     }
716     else {
717         // We now have a mapped file. XmText wants a zero terminated
718         // buffer. We get luck with mmap because unless the file is
719         // an even page size, we will have some zero fill bytes that
720         // are legal to access.
721         //
722         // Of course in the case of an even page size file we must
723         // copy the buffer, terminate it and then give it to XmText.
724         //
725         bp->setContents(
726             mail_error, map, s.st_size, NULL, fname_start, 0, NULL
727         );
728         munmap(map, map_size);
729     }
730     SafeClose(fd);
731
732
733     // _iconCount + 1 because iconCount starts at 0 and we want 
734     // attachmentCount to begin at 1.  attachmentCount is set to be
735     // in the widget's userData.  
736
737
738     if(name)
739         lbl = strdup(name);
740     else {
741         if(strchr(filename, '/') == NULL) // The name does not include a slash
742             lbl = strdup(filename);
743         else                       // The name does include a slash
744             lbl = strdup(strrchr(filename, '/')+1);
745     }    
746     Attachment *attachment = new Attachment(this, lbl, bp, _iconCount + 1);
747     attachment->setAttachArea(this);
748     attachment->initialize();
749     addToList( attachment );
750
751     // Update the display.  The Compose Window needs immediate update.
752
753     this->manageList();
754
755     delete [] buf;
756     delete [] errormsg;
757     return(attachment);
758 }
759
760 Attachment*
761 AttachArea::addAttachment(
762     DtMail::Message *msg,
763     DtMail::BodyPart *lastAttBP,
764     String name,
765     DtMailBuffer buf
766 )
767 {
768     DtMailEnv mail_error;
769     DtMail::BodyPart * bp = NULL;
770
771     if (!name)
772         name = "noname";
773
774     mail_error.clear();
775
776     bp = msg->newBodyPart(mail_error, lastAttBP);
777     bp->setContents(mail_error, buf.buffer, buf.size, NULL, name, 0, NULL);
778
779     Attachment *attachment = new Attachment(this,
780                                             name,
781                                             bp,
782                                             _iconCount + 1);
783     attachment->setAttachArea(this);
784     attachment->initialize();
785     addToList(attachment);
786
787     // Update the display.  The Compose Window needs immediate update.
788
789     this->manageList();
790
791     return(attachment);
792 }
793
794 Attachment* 
795 AttachArea::addAttachment( 
796     String name,
797     DtMail::BodyPart *body_part
798 )
799 {
800     // _iconCount + 1 because iconCount starts at 0 and we want 
801     //  attachmentCount to begin at 1.  attachmentCount is set to be
802     // in the widget's userData.  
803
804     Attachment *attachment = new Attachment(
805                                         this, 
806                                         name, 
807                                         body_part, 
808                                         _iconCount + 1
809                                 );
810     attachment->setAttachArea(this);
811     attachment->initialize();
812     addToList( attachment );
813
814     return(attachment);
815 }
816
817 #ifdef DEAD_WOOD
818 void
819 AttachArea::add_attachment(
820     Attachment *attachment
821 )
822 {
823     
824      attachment->setAttachArea(this);
825      attachment->initialize();
826      addToList( attachment );
827 }
828
829 //
830 // This function truly deletes all the attachments in the AttachArea
831 // The widgets are unmanaged and the attachment classes are deleted.
832 //
833
834 void AttachArea::deleteAttachments( )
835 {
836     int i;
837     WidgetList deleteList;
838     int count;
839
840     Attachment **list = getList();
841  
842      // First, unmanaged all the attachment at once so there is no
843      // flickering when we delete them
844
845      deleteList = (WidgetList)XtMalloc(sizeof(Widget) * getIconCount());
846
847      for(i=0;i<getIconCount();i++)
848         deleteList[i] = list[i]->baseWidget();
849      XtUnmanageChildren(deleteList, i);
850
851      delete deleteList;
852      XtFree((char *)deleteList);
853  
854     // Delete each attachment in the list
855     count = getIconCount();
856     for(i=count-1;i>=0;i--) {
857         delete list[i];
858         decIconCount();
859     }
860
861      _iconCount = 0;
862      _iconSelectedCount = 0;
863      _deleteCount = 0;
864      CalcLastRow();
865      AdjustCurrentRow();
866      SetScrollBarSize(getLastRow()+1);
867      activateDeactivate();
868      _attachmentList=NULL;
869      _attachmentsSize = 0;
870      _selectedAttachmentsSize = 0;
871 }
872 #endif /* DEAD_WOOD */
873
874 void AttachArea::manageList( )
875 {
876     int i;
877     Attachment **list = getList();
878
879     for (i=0; i<getIconCount(); i++)
880       list[i]->unmanageIconWidget();
881
882     CalcAllAttachmentPositions();
883     CalcLastRow();
884     AdjustCurrentRow();
885     SetScrollBarSize(getLastRow()+1);
886     DisplayAttachmentsInRow(_currentRow);
887 }
888
889 #ifdef DEAD_WOOD
890 //
891 // Find the x and y position for a newly created attachment
892 //
893
894 void AttachArea::CalcAttachmentPosition(Attachment *item)
895 {
896     int i, j;
897     Boolean found_managed = FALSE;
898
899      Attachment **list = getList();
900      for(i=0, j=0;i<getIconCount();i++)
901         if(!list[i]->isDeleted()) {
902             j = i;
903             found_managed = TRUE;
904         }
905     calculate_attachment_position(
906        found_managed ? list[j] : (Attachment *)NULL, item
907        );
908
909 }      
910 #endif /* DEAD_WOOD */
911
912 //
913 // Display the attachments in row X
914 //
915
916 void AttachArea::DisplayAttachmentsInRow(unsigned int X)
917 {
918     int i;
919     int managecount, unmanagecount;
920
921     Attachment **list = getList();
922     WidgetList manageIconList, unmanageIconList;
923
924     if (getIconCount())
925     {
926         manageIconList = (WidgetList) XtMalloc(sizeof(Widget)*getIconCount());
927         unmanageIconList = (WidgetList) XtMalloc(sizeof(Widget)*getIconCount());
928      
929         managecount = unmanagecount = 0;
930         for(i=0;i<getIconCount();i++) {
931             if(!list[i]->isDeleted()) {
932                 if(list[i]->getRow() == X) {
933                     if(!list[i]->isManaged()) {
934                         manageIconList[managecount] = list[i]->baseWidget();
935                         managecount++;
936                     } 
937                 }
938                 else { // if deleted
939                     if(list[i]->isManaged()) {
940                         unmanageIconList[unmanagecount] = list[i]->baseWidget();
941                         unmanagecount++;
942                     }
943                 }
944             }
945         }
946
947         XtUnmanageChildren(unmanageIconList, unmanagecount);
948         XtManageChildren(manageIconList, managecount);
949
950
951         XtFree((char *)manageIconList);
952         XtFree((char *)unmanageIconList);
953     }
954
955     this->attachment_summary(_iconCount - _deleteCount, _deleteCount);
956 }
957
958 //
959 // Calculate the position of every non-deleted Attachment
960 //
961
962 void AttachArea::CalcAllAttachmentPositions()
963 {
964     int i, j;
965     Attachment **list = getList();
966  
967     j = -1;
968     for(i=0;i<getIconCount();i++) {
969         if(!list[i]->isDeleted()) {
970             calculate_attachment_position(
971                         (j == -1) ? (Attachment *)NULL : list[j],
972                         list[i]);
973             j = i;
974         }
975     }
976 }
977
978 //
979 // Determine the position of attachment "item" given reference
980 // attachment "ref"
981 //
982
983 void AttachArea::calculate_attachment_position(
984     Attachment *ref,
985     Attachment *item
986 )
987 {
988     if(ref == NULL) {
989         item->setX(HSPACE);
990         item->setY(VSPACE);
991         item->setRow(0);
992         return;
993     }
994     if(((Dimension)(ref->getX() + 
995                     ref->getWidth() + 
996                     HSPACE + 
997                     item->getWidth()))  > getAAWidth() ) {
998         item->setX(HSPACE);
999         item->setY(VSPACE);
1000         item->setRow(ref->getRow() + 1);
1001     } else {
1002         item->setX(ref->getX() + ref->getWidth() + HSPACE);
1003         item->setRow(ref->getRow());
1004         item->setY(VSPACE);
1005     }
1006 }
1007
1008 //
1009 // Invoked when the user moves the slider by any method
1010 // If the user is dragging the slider then this callback
1011 // is only invoked when the user releases the mouse button
1012 //
1013
1014 void AttachArea::valueChangedCallback ( 
1015     Widget, 
1016     XtPointer clientData, 
1017     XtPointer callData 
1018 )
1019 {
1020     AttachArea *obj = (AttachArea *) clientData;
1021
1022     obj->valueChanged( callData );
1023 }
1024
1025 void AttachArea::valueChanged( XtPointer callData )
1026 {
1027     XmScrollBarCallbackStruct *cbs = (XmScrollBarCallbackStruct *)callData;
1028
1029     _currentRow = cbs->value;
1030     DisplayAttachmentsInRow(_currentRow);
1031 }
1032
1033 //
1034 // Invoked when the user drags the slider
1035 //
1036
1037 void AttachArea::dragCallback ( 
1038     Widget, 
1039     XtPointer clientData, 
1040     XtPointer callData 
1041 )
1042 {
1043     AttachArea *obj = (AttachArea *) clientData;
1044
1045     obj->dragSlider( callData );
1046 }
1047
1048 void AttachArea::dragSlider( XtPointer callData )
1049 {
1050     XmScrollBarCallbackStruct *cbs = (XmScrollBarCallbackStruct *)callData;
1051
1052     if(cbs->value == _currentRow)
1053         return;
1054     _currentRow = cbs->value;
1055     DisplayAttachmentsInRow(_currentRow);
1056 }
1057
1058 //
1059 // Calculate the number of rows
1060 //
1061
1062 void AttachArea::CalcLastRow()
1063 {
1064     int i;
1065     unsigned row = 0;
1066      Attachment **list = getList();
1067  
1068      for(i=0;i<getIconCount();i++) {
1069         if(!list[i]->isDeleted()) {
1070             row = list[i]->getRow();
1071         }
1072      }
1073     _lastRow = row;
1074 }
1075
1076 //
1077 // Set the XmmNmaximum resource to size
1078 //
1079
1080 void AttachArea::SetScrollBarSize(unsigned int size)
1081 {
1082     XtVaSetValues(_vsb, 
1083         XmNmaximum, size,
1084         NULL);
1085 }
1086
1087 //
1088 // If the current row is greater than the last row, adjust the
1089 // current row to be equal to the last row.
1090 //
1091
1092 void AttachArea::AdjustCurrentRow()
1093 {
1094     if(_currentRow > _lastRow) {
1095         _currentRow = _lastRow;
1096         XtVaSetValues(_vsb, XmNvalue, _currentRow, NULL);
1097     }
1098 }
1099
1100 XmString
1101 AttachArea::getSelectedAttachName()
1102 {
1103     XmString str = (XmString)NULL;
1104
1105     if(_cache_single_attachment)
1106         str = _cache_single_attachment->getLabel();
1107
1108     return(str);
1109 }
1110
1111 void
1112 AttachArea::setSelectedAttachName(
1113     XmString new_name
1114 )
1115 {
1116     int i;
1117     Boolean set = FALSE;
1118     Attachment **list = this->getList();
1119
1120     XmString nn = XmStringCopy(new_name);
1121
1122     // Set name of first selected attachment to new_name
1123     for(i=0;i<this->getIconCount() && !set;i++)
1124         if(list[i]->isSelected()) {
1125             list[i]->rename(nn);
1126             set = TRUE;
1127         }
1128     this->manageList();
1129 }
1130
1131
1132 void
1133 AttachArea::attachmentSelected(
1134     Attachment *attachment
1135
1136 {
1137     // First deselect other selected attachments
1138     this->unselectOtherSelectedAttachments(attachment);
1139     
1140     // Enable the menu item at the toplevel shell's menubar.
1141     if(_cache_single_attachment == NULL)
1142         _myOwner->owner()->attachment_selected();
1143
1144     // Cache the single selected attachment
1145     _cache_single_attachment = attachment;
1146     _attach_area_selection_state = AA_SEL_SINGLE;
1147 }
1148
1149 void
1150 AttachArea::attachmentFeedback(
1151     Boolean value
1152 )
1153 {
1154     _myOwner->owner()->attachmentFeedback(value);
1155 }
1156     
1157 char *
1158 AttachArea::calcKbytes(unsigned int bytes)
1159 {
1160     static char kstring[64];
1161
1162     if(bytes < 103)
1163         sprintf(kstring, "%d bytes",bytes);
1164     else if(bytes < 1024)
1165         sprintf(kstring, " .%dk", bytes/103);
1166     else
1167         sprintf(kstring, "%dk", bytes/1024);
1168
1169     return kstring;
1170 }
1171
1172 void
1173 AttachArea::addToRowOfAttachmentsStatus()
1174 {
1175     XmString labelStr2;
1176
1177     // Size of first label
1178     
1179     labelStr2 = XmStringCreateLocalized(
1180                         GETMSG(DT_catd, 3, 37, "Summary of attachments"));
1181
1182
1183     _attachments_summary = XtCreateManagedWidget("Attachments_Summary", 
1184                                                  xmLabelWidgetClass,
1185                                                  rowOfAttachmentsStatus, NULL, 0);
1186
1187     XtVaSetValues(_attachments_summary,
1188                   XmNalignment, XmALIGNMENT_END,
1189                   XmNlabelString, labelStr2,
1190                   XmNrightAttachment, XmATTACH_FORM,
1191                   NULL );
1192
1193      XmStringFree(labelStr2);
1194 }
1195
1196 void
1197 AttachArea::parseAttachments(
1198     DtMailEnv &mail_error,
1199     DtMail::Message* msg,
1200     Boolean empty,
1201     int startBP
1202 )
1203 {
1204     DtMail::BodyPart * tmpBP;
1205     int index = 1;
1206     int num_attachments = 0;
1207     char * name;
1208
1209
1210     // First unmanage and empty out the current contents.
1211
1212     // SMD sets this boolean to FALSE so that previous message's attachments
1213     // are not cleared.  E.g. Including/forwarding multiple messages each
1214     // with attachments.
1215     // RMW sets this boolean to TRUE so that all attachments are cleared in
1216     // the attachment pane everytime a new message is displayed.
1217
1218     if ( empty ) {
1219
1220         // First unmanage the clipWindow.
1221         // Unmanaging the attachment pane is visually ugly
1222
1223         XtUnmanageChild(_clipWindow);
1224         this->clearAttachArea();
1225     }
1226
1227     _deleteCount = 0;
1228
1229     // Now fill list with new attachments.
1230
1231     tmpBP = msg->getFirstBodyPart(mail_error);
1232     if (mail_error.isSet()) {
1233         // do something
1234     }
1235
1236     // Sync up the index with the bodyPart from which to begin
1237     // adding attachments into attachPane.
1238     // 
1239     while (startBP > index) {
1240         tmpBP = msg->getNextBodyPart(mail_error, tmpBP);
1241         index++;
1242     }
1243     
1244     while (tmpBP != NULL) {
1245         num_attachments++;
1246         tmpBP->getContents(
1247                         mail_error,
1248                         NULL,
1249                         NULL,
1250                         NULL,
1251                         &name,
1252                         NULL,
1253                         NULL);
1254         
1255         if (mail_error.isSet()) {
1256             // do something
1257         }
1258
1259         // It is possible for an attachment to not have a name.
1260         if (!name) {
1261             name = "NoName";
1262         }
1263
1264         this->addAttachment(name, tmpBP);
1265         tmpBP = msg->getNextBodyPart(mail_error, tmpBP);
1266         if (mail_error.isSet()) {
1267             // do something
1268         }
1269
1270         free(name);
1271     }
1272 }
1273
1274 void
1275 AttachArea::attachment_summary(
1276     int live,
1277     int dead
1278 )
1279 {
1280
1281     char *buf = NULL;
1282     char * tmp1;
1283     char * tmp2;
1284
1285     if ((live == 1) && (dead == 0)) {
1286         tmp1 = GETMSG(DT_catd, 3, 38, "attachment");
1287         buf = new char[strlen(tmp1) + 64];
1288         sprintf(buf, "%d %s", live, tmp1);
1289     }
1290     else if ((live >= 0) && (dead == 0)) {
1291         /* NL_COMMENT
1292          * "attachments" is the plural form of "attachment".
1293          */
1294         tmp1 = GETMSG(DT_catd, 3, 39, "attachments");
1295         buf = new char[strlen(tmp1) + 64];
1296         sprintf(buf, "%d %s", live, tmp1);
1297     }
1298     else if ((live >= 0) && (dead > 0)) {
1299         tmp1 = GETMSG(DT_catd, 3, 40, "attachments");
1300         tmp2 = GETMSG(DT_catd, 3, 41, "deleted");
1301         buf = new char[strlen(tmp1) + strlen(tmp2) + 64];
1302         sprintf(buf, "%d %s, %d %s", live, tmp1, dead, tmp2);
1303     }
1304     
1305     if (buf) {
1306         XmString buf_str = XmStringCreateLocalized(buf);
1307         XtVaSetValues(_attachments_summary,
1308             XmNlabelString, buf_str,
1309             NULL );
1310     
1311         delete [] buf;
1312         XmStringFree(buf_str);
1313     }
1314 }
1315
1316 void
1317 AttachArea::manage()
1318 {
1319     XtArgVal /* Dimension */ ht;
1320     XtArgVal /* Dimension */ pht;
1321     Widget sww;
1322
1323     // Update the display
1324     sww = getSWWindow();
1325     this->manageList();
1326
1327     XtAddCallback(
1328                 _clipWindow, 
1329                 XmNresizeCallback, &AttachArea::resizeCallback,
1330                 (XtPointer) this );
1331
1332     XtAddCallback(
1333                 _clipWindow, 
1334                 XmNinputCallback, &AttachArea::inputCallback,
1335                 (XtPointer) this);
1336
1337     XtAddEventHandler(
1338                 _clipWindow, ButtonPressMask,
1339                 FALSE, MenuButtonHandler,
1340                 (XtPointer) this);
1341
1342     // hack
1343     XtVaGetValues(sww, XmNheight, &ht, NULL);
1344     XtVaGetValues(_w, XmNheight, &pht, NULL);
1345     // Manage the clipWindow back
1346     if (!XtIsManaged(_clipWindow)) XtManageChild(_clipWindow);
1347
1348     // hack
1349     XtVaSetValues(sww, XmNheight, ht, NULL);
1350     UIComponent::manage();
1351     XtVaSetValues(_w, XmNheight, pht, NULL);
1352 }
1353
1354 void
1355 AttachArea::unmanage()
1356 {
1357     int i;
1358     Attachment **list = getList();
1359
1360     // Unmanage the widgets it currently has
1361     for (i=0; i<getIconCount(); i++)
1362       list[i]->unmanageIconWidget();
1363
1364     XtRemoveCallback(
1365         _clipWindow, 
1366         XmNresizeCallback, &AttachArea::resizeCallback,
1367         (XtPointer) this );
1368
1369     XtRemoveCallback(
1370         _clipWindow, 
1371         XmNinputCallback, &AttachArea::inputCallback,
1372         (XtPointer) this );
1373
1374     XtRemoveEventHandler(
1375         _clipWindow, ButtonPressMask,
1376         FALSE, MenuButtonHandler,
1377         (XtPointer) this);
1378
1379     UIComponent::unmanage();
1380 }
1381
1382 void
1383 AttachArea::removeCurrentAttachments()
1384 {
1385
1386     Attachment **list = getList();
1387     int i;
1388
1389     // Unmanage the widgets it currently has
1390
1391     for (i=0; i<getIconCount(); i++) {
1392
1393         list[i]->unmanageIconWidget();
1394         list[i]->deleteIt();
1395     }
1396
1397     // Reset
1398     if (_attachmentList)
1399         delete []_attachmentList;
1400     _attachmentList = NULL;
1401     _iconCount = 0;
1402     _deleteCount = 0;
1403     _attach_area_selection_state = AA_SEL_NONE;
1404     _cache_single_attachment = NULL;
1405
1406     this->attachment_summary(_iconCount, _deleteCount);
1407 }
1408
1409 // Similar to removeCurrentAttachments().
1410 // Except we don't display a summary that there are no attachments.
1411 // Plus has potential for other (different) usage.
1412
1413 void
1414 AttachArea::clearAttachArea()
1415 {
1416
1417     Attachment **list = getList();
1418     int i;
1419
1420     // Unmanage the widgets it currently has
1421
1422     for (i=0; i<getIconCount(); i++) {
1423
1424         list[i]->unmanageIconWidget();
1425         delete list[i];
1426     }
1427
1428     // Reset
1429     if (_attachmentList)
1430         delete []_attachmentList;
1431     _attachmentList = NULL;
1432     _iconCount = 0;
1433     _deleteCount = 0;
1434     _attach_area_selection_state = AA_SEL_NONE;
1435     _cache_single_attachment = NULL;
1436 }
1437
1438 #ifdef DEAD_WOOD
1439 void
1440 AttachArea::saveAttachmentToFile(
1441     DtMailEnv &mail_error,
1442     char *save_path
1443 )
1444 {
1445
1446     Attachment *attachment = this->getSelectedAttachment();
1447
1448     if(attachment != NULL)
1449         attachment->saveToFile(mail_error, save_path);
1450
1451 }
1452 #endif /* DEAD_WOOD */
1453
1454 void
1455 AttachArea::deleteSelectedAttachments(
1456     DtMailEnv &         //mail_error
1457 )
1458 {
1459     Attachment **list = getList();
1460     int i;
1461     
1462     for (i = 0; i<getIconCount(); i++) {
1463         if (list[i]->isSelected() && !list[i]->isDeleted()) {
1464
1465             // unselect it first.  Else, when undeleted it comes
1466             // off selected
1467             
1468             list[i]->unselect();
1469             list[i]->deleteIt();
1470             _deleteCount++;
1471         }
1472     }
1473     
1474     // Unmanage all.
1475     // Their positions need to get recomputed and the undeleted
1476     // ones get remanaged in manageList().
1477
1478     for (i=0; i<getIconCount(); i++) {
1479         list[i]->unmanageIconWidget();
1480     }
1481
1482     _cache_single_attachment = NULL;
1483     _attach_area_selection_state = AA_SEL_NONE;
1484
1485     this->manageList();
1486 }
1487
1488
1489 #ifdef DEAD_WOOD
1490 void
1491 AttachArea::undeleteAllDeletedAttachments(
1492     DtMailEnv &         //mail_error
1493 )
1494 {
1495 }
1496 #endif /* DEAD_WOOD */
1497
1498 void
1499 AttachArea::undeleteLastDeletedAttachment(
1500     DtMailEnv &mail_error
1501 )
1502 {
1503
1504     Attachment *tmpAttachment;
1505     Attachment **list;
1506     time_t time_deleted = 0, tmpTime = 0;
1507     int i;
1508
1509     if (_deleteCount == 0) {
1510         return;
1511     }
1512
1513     list = getList();
1514
1515     tmpAttachment = list[0];
1516     time_deleted = tmpAttachment->getBodyPart()->getDeleteTime(mail_error);
1517     if (mail_error.isSet()) {
1518         // do something
1519     }
1520
1521     for (i=1; i<getIconCount(); i++) {
1522         if (list[i]->isDeleted()) {
1523             tmpTime = list[i]->getBodyPart()->getDeleteTime(mail_error);
1524             if (mail_error.isSet()) {
1525                 // do something
1526             }
1527             if ( tmpTime > time_deleted) {
1528                 time_deleted = tmpTime;
1529                 tmpAttachment = list[i];
1530             }
1531         }
1532     }
1533
1534     tmpAttachment->undeleteIt();
1535     _deleteCount--;
1536
1537     // Unmanage all.
1538     // Their positions need to get recomputed and the deleted
1539     // ones get remanaged in manageList().
1540
1541     for (i=0; i<getIconCount(); i++) {
1542         list[i]->unmanageIconWidget();
1543     }
1544
1545
1546     this->manageList();
1547
1548 }
1549
1550     
1551 void
1552 AttachArea::unselectOtherSelectedAttachments(
1553     Attachment *attachment
1554 )
1555 {
1556     if(_attach_area_selection_state == AA_SEL_NONE)
1557         return;
1558
1559     if(_attach_area_selection_state == AA_SEL_ALL) {
1560         int i;
1561         Attachment **list;
1562
1563         list = getList(); 
1564
1565         for (i=0; i < getIconCount(); i++) 
1566             if (list[i]->isSelected() && list[i] != attachment) 
1567                 list[i]->unselect();
1568     } 
1569     else if (_cache_single_attachment && 
1570             (attachment != _cache_single_attachment)) {
1571         _cache_single_attachment->unselect();
1572         _cache_single_attachment = NULL;
1573     }
1574
1575    if(attachment == NULL) {
1576         // Grey out the appropriate menu items in the RMW...
1577         _myOwner->owner()->all_attachments_deselected();
1578         _attach_area_selection_state = AA_SEL_NONE;
1579         _cache_single_attachment = NULL;
1580    }
1581 }
1582
1583 void
1584 AttachArea::addAttachmentActions(
1585     char **actions,
1586     int indx
1587 )
1588 {
1589
1590     _myOwner->owner()->addAttachmentActions(
1591                                 actions,
1592                                 indx
1593                         );
1594
1595 }
1596
1597 void
1598 AttachArea::setOwnerShell(
1599     RoamMenuWindow *rmw
1600 )
1601 {
1602     _myRMW = rmw;
1603 }
1604
1605 void
1606 AttachArea::setOwnerShell(
1607     ViewMsgDialog *vmd
1608 )
1609 {
1610     _myVMD = vmd;
1611 }
1612
1613 void
1614 AttachArea::setOwnerShell(
1615     SendMsgDialog *smd
1616 )
1617 {
1618     _mySMD = smd;
1619 }
1620
1621 Widget
1622 AttachArea::ownerShellWidget()
1623 {
1624     if (_myRMW) {
1625         return(_myRMW->baseWidget());
1626     }
1627     else if (_myVMD) {
1628         return(_myVMD->baseWidget());
1629     }
1630     else if (_mySMD) {
1631         return(_mySMD->baseWidget());
1632     }
1633     else {
1634         // Error out
1635     }
1636     return((Widget) NULL);
1637 }
1638
1639 Boolean
1640 AttachArea::isOwnerShellEditable()
1641 {
1642     // only SMD is editable
1643     if (_mySMD != NULL) {
1644         return TRUE;
1645     }
1646     else {
1647         return FALSE;
1648     }
1649 }
1650
1651 void
1652 AttachArea::setPendingAction(
1653     Boolean bval
1654 )
1655 {
1656     _pendingAction = bval;
1657     if (bval) {
1658         _numPendingActions++;
1659     }
1660     else {
1661         if (_numPendingActions > 0) {
1662             _numPendingActions--;
1663         }
1664     }
1665 }
1666
1667 void
1668 AttachArea::resetPendingAction()
1669 {
1670
1671     _numPendingActions = 0;
1672 }
1673
1674 int
1675 AttachArea::getNumPendingActions()
1676 {
1677     return(_numPendingActions);
1678 }
1679
1680 void
1681 AttachArea::selectAllAttachments()
1682 {
1683     
1684     Attachment **list;
1685     int numAttachments = getIconCount();
1686
1687     list = getList(); 
1688     
1689     if(list == NULL)
1690         return;
1691
1692     // if there's only 1 attachment, select it and
1693     // add its actions to the menu bar...
1694
1695     if (numAttachments == 1) {
1696         list[0]->primitive_select();
1697         list[0]->set_selected();
1698     }
1699     else {
1700         // More than 1 attachment.
1701         // Select them all. Don't enable their actions however.
1702
1703         for (int i=0; i < numAttachments; i++) 
1704             list[i]->primitive_select();
1705
1706         // Grey out the appropriate menu items in the RMW...
1707         _myOwner->owner()->all_attachments_selected();
1708         _cache_single_attachment = NULL;
1709         _attach_area_selection_state = AA_SEL_ALL;
1710     }
1711 }
1712
1713 int
1714 AttachArea::handleQuestionDialog(
1715     char *title,
1716     char *buf,
1717     char * helpId
1718 )
1719 {
1720     DtMailGenDialog *dialog;
1721     int answer;
1722
1723     if (_myRMW) {
1724         dialog = _myRMW->genDialog();
1725     }
1726     else if (_myVMD) {
1727         dialog = _myVMD->genDialog();
1728     }
1729     else if ( _mySMD) {
1730         dialog = _mySMD->genDialog();
1731     }
1732     else return(-1);
1733
1734     if (!dialog) return(-1);
1735
1736     dialog->setToQuestionDialog(
1737                         title,
1738                         buf);
1739     answer = dialog->post_and_return(helpId);
1740     return(answer);
1741 }
1742
1743 int
1744 AttachArea::handleErrorDialog(
1745     char *title,
1746     char *buf,
1747     char *helpId
1748 )
1749 {
1750     DtMailGenDialog *dialog;
1751     int answer;
1752
1753     if (_myRMW) {
1754         dialog = _myRMW->genDialog();
1755     }
1756     else if (_myVMD) {
1757         dialog = _myVMD->genDialog();
1758     }
1759     else if ( _mySMD) {
1760         dialog = _mySMD->genDialog();
1761     }
1762     else return(-1);
1763
1764     if (!dialog) return(-1);
1765
1766     dialog->setToErrorDialog(title, buf);
1767     answer = dialog->post_and_return(helpId);
1768     return(answer);
1769 }