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