dthelp: Change to ANSI function definitions
[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     map = (char *) mmap(0, map_size, PROT_READ, MAP_PRIVATE, fd, 0);
679
680     if (map == (char *)-1) {
681         // We could not map it for some reason. Let's just read it into
682         // buffer and pass it to XmText.
683         //
684
685         buffer = new char[s.st_size + 1];
686
687         if (!buffer) {
688             sprintf(buf, "%s",
689                     GETMSG(DT_catd, 3, 36, "Unable to allocate memory."));
690             helpId = DTMAILHELPNOALLOCMEM;
691             answer = this->handleErrorDialog(GETMSG(DT_catd, 1, 83, "Mailer"), 
692                                              buf,
693                                              helpId);
694             return(NULL);
695         }
696
697         if (read(fd, buffer, (unsigned int) s.st_size) < 0) {
698             SafeClose(fd);
699             delete [] buf;
700             delete [] buffer;
701             delete [] errormsg;
702             return(NULL);
703         }
704         buffer[s.st_size] = 0;
705         bp->setContents(
706                 mail_error, buffer, s.st_size, NULL, fname_start, 0, NULL
707                 );
708     }
709     else {
710         // We now have a mapped file. XmText wants a zero terminated
711         // buffer. We get luck with mmap because unless the file is
712         // an even page size, we will have some zero fill bytes that
713         // are legal to access.
714         //
715         // Of course in the case of an even page size file we must
716         // copy the buffer, terminate it and then give it to XmText.
717         //
718         bp->setContents(
719             mail_error, map, s.st_size, NULL, fname_start, 0, NULL
720         );
721         munmap(map, map_size);
722     }
723     SafeClose(fd);
724
725
726     // _iconCount + 1 because iconCount starts at 0 and we want 
727     // attachmentCount to begin at 1.  attachmentCount is set to be
728     // in the widget's userData.  
729
730
731     if(name)
732         lbl = strdup(name);
733     else {
734         if(strchr(filename, '/') == NULL) // The name does not include a slash
735             lbl = strdup(filename);
736         else                       // The name does include a slash
737             lbl = strdup(strrchr(filename, '/')+1);
738     }    
739     Attachment *attachment = new Attachment(this, lbl, bp, _iconCount + 1);
740     attachment->setAttachArea(this);
741     attachment->initialize();
742     addToList( attachment );
743
744     // Update the display.  The Compose Window needs immediate update.
745
746     this->manageList();
747
748     delete [] buf;
749     delete [] errormsg;
750     return(attachment);
751 }
752
753 Attachment*
754 AttachArea::addAttachment(
755     DtMail::Message *msg,
756     DtMail::BodyPart *lastAttBP,
757     String name,
758     DtMailBuffer buf
759 )
760 {
761     DtMailEnv mail_error;
762     DtMail::BodyPart * bp = NULL;
763
764     if (!name)
765         name = "noname";
766
767     mail_error.clear();
768
769     bp = msg->newBodyPart(mail_error, lastAttBP);
770     bp->setContents(mail_error, buf.buffer, buf.size, NULL, name, 0, NULL);
771
772     Attachment *attachment = new Attachment(this,
773                                             name,
774                                             bp,
775                                             _iconCount + 1);
776     attachment->setAttachArea(this);
777     attachment->initialize();
778     addToList(attachment);
779
780     // Update the display.  The Compose Window needs immediate update.
781
782     this->manageList();
783
784     return(attachment);
785 }
786
787 Attachment* 
788 AttachArea::addAttachment( 
789     String name,
790     DtMail::BodyPart *body_part
791 )
792 {
793     // _iconCount + 1 because iconCount starts at 0 and we want 
794     //  attachmentCount to begin at 1.  attachmentCount is set to be
795     // in the widget's userData.  
796
797     Attachment *attachment = new Attachment(
798                                         this, 
799                                         name, 
800                                         body_part, 
801                                         _iconCount + 1
802                                 );
803     attachment->setAttachArea(this);
804     attachment->initialize();
805     addToList( attachment );
806
807     return(attachment);
808 }
809
810 #ifdef DEAD_WOOD
811 void
812 AttachArea::add_attachment(
813     Attachment *attachment
814 )
815 {
816     
817      attachment->setAttachArea(this);
818      attachment->initialize();
819      addToList( attachment );
820 }
821
822 //
823 // This function truly deletes all the attachments in the AttachArea
824 // The widgets are unmanaged and the attachment classes are deleted.
825 //
826
827 void AttachArea::deleteAttachments( )
828 {
829     int i;
830     WidgetList deleteList;
831     int count;
832
833     Attachment **list = getList();
834  
835      // First, unmanaged all the attachment at once so there is no
836      // flickering when we delete them
837
838      deleteList = (WidgetList)XtMalloc(sizeof(Widget) * getIconCount());
839
840      for(i=0;i<getIconCount();i++)
841         deleteList[i] = list[i]->baseWidget();
842      XtUnmanageChildren(deleteList, i);
843
844      delete deleteList;
845      XtFree((char *)deleteList);
846  
847     // Delete each attachment in the list
848     count = getIconCount();
849     for(i=count-1;i>=0;i--) {
850         delete list[i];
851         decIconCount();
852     }
853
854      _iconCount = 0;
855      _iconSelectedCount = 0;
856      _deleteCount = 0;
857      CalcLastRow();
858      AdjustCurrentRow();
859      SetScrollBarSize(getLastRow()+1);
860      activateDeactivate();
861      _attachmentList=NULL;
862      _attachmentsSize = 0;
863      _selectedAttachmentsSize = 0;
864 }
865 #endif /* DEAD_WOOD */
866
867 void AttachArea::manageList( )
868 {
869     int i;
870     Attachment **list = getList();
871
872     for (i=0; i<getIconCount(); i++)
873       list[i]->unmanageIconWidget();
874
875     CalcAllAttachmentPositions();
876     CalcLastRow();
877     AdjustCurrentRow();
878     SetScrollBarSize(getLastRow()+1);
879     DisplayAttachmentsInRow(_currentRow);
880 }
881
882 #ifdef DEAD_WOOD
883 //
884 // Find the x and y position for a newly created attachment
885 //
886
887 void AttachArea::CalcAttachmentPosition(Attachment *item)
888 {
889     int i, j;
890     Boolean found_managed = FALSE;
891
892      Attachment **list = getList();
893      for(i=0, j=0;i<getIconCount();i++)
894         if(!list[i]->isDeleted()) {
895             j = i;
896             found_managed = TRUE;
897         }
898     calculate_attachment_position(
899        found_managed ? list[j] : (Attachment *)NULL, item
900        );
901
902 }      
903 #endif /* DEAD_WOOD */
904
905 //
906 // Display the attachments in row X
907 //
908
909 void AttachArea::DisplayAttachmentsInRow(unsigned int X)
910 {
911     int i;
912     int managecount, unmanagecount;
913
914     Attachment **list = getList();
915     WidgetList manageIconList, unmanageIconList;
916
917     if (getIconCount())
918     {
919         manageIconList = (WidgetList) XtMalloc(sizeof(Widget)*getIconCount());
920         unmanageIconList = (WidgetList) XtMalloc(sizeof(Widget)*getIconCount());
921      
922         managecount = unmanagecount = 0;
923         for(i=0;i<getIconCount();i++) {
924             if(!list[i]->isDeleted()) {
925                 if(list[i]->getRow() == X) {
926                     if(!list[i]->isManaged()) {
927                         manageIconList[managecount] = list[i]->baseWidget();
928                         managecount++;
929                     } 
930                 }
931                 else { // if deleted
932                     if(list[i]->isManaged()) {
933                         unmanageIconList[unmanagecount] = list[i]->baseWidget();
934                         unmanagecount++;
935                     }
936                 }
937             }
938         }
939
940         XtUnmanageChildren(unmanageIconList, unmanagecount);
941         XtManageChildren(manageIconList, managecount);
942
943
944         XtFree((char *)manageIconList);
945         XtFree((char *)unmanageIconList);
946     }
947
948     this->attachment_summary(_iconCount - _deleteCount, _deleteCount);
949 }
950
951 //
952 // Calculate the position of every non-deleted Attachment
953 //
954
955 void AttachArea::CalcAllAttachmentPositions()
956 {
957     int i, j;
958     Attachment **list = getList();
959  
960     j = -1;
961     for(i=0;i<getIconCount();i++) {
962         if(!list[i]->isDeleted()) {
963             calculate_attachment_position(
964                         (j == -1) ? (Attachment *)NULL : list[j],
965                         list[i]);
966             j = i;
967         }
968     }
969 }
970
971 //
972 // Determine the position of attachment "item" given reference
973 // attachment "ref"
974 //
975
976 void AttachArea::calculate_attachment_position(
977     Attachment *ref,
978     Attachment *item
979 )
980 {
981     if(ref == NULL) {
982         item->setX(HSPACE);
983         item->setY(VSPACE);
984         item->setRow(0);
985         return;
986     }
987     if(((Dimension)(ref->getX() + 
988                     ref->getWidth() + 
989                     HSPACE + 
990                     item->getWidth()))  > getAAWidth() ) {
991         item->setX(HSPACE);
992         item->setY(VSPACE);
993         item->setRow(ref->getRow() + 1);
994     } else {
995         item->setX(ref->getX() + ref->getWidth() + HSPACE);
996         item->setRow(ref->getRow());
997         item->setY(VSPACE);
998     }
999 }
1000
1001 //
1002 // Invoked when the user moves the slider by any method
1003 // If the user is dragging the slider then this callback
1004 // is only invoked when the user releases the mouse button
1005 //
1006
1007 void AttachArea::valueChangedCallback ( 
1008     Widget, 
1009     XtPointer clientData, 
1010     XtPointer callData 
1011 )
1012 {
1013     AttachArea *obj = (AttachArea *) clientData;
1014
1015     obj->valueChanged( callData );
1016 }
1017
1018 void AttachArea::valueChanged( XtPointer callData )
1019 {
1020     XmScrollBarCallbackStruct *cbs = (XmScrollBarCallbackStruct *)callData;
1021
1022     _currentRow = cbs->value;
1023     DisplayAttachmentsInRow(_currentRow);
1024 }
1025
1026 //
1027 // Invoked when the user drags the slider
1028 //
1029
1030 void AttachArea::dragCallback ( 
1031     Widget, 
1032     XtPointer clientData, 
1033     XtPointer callData 
1034 )
1035 {
1036     AttachArea *obj = (AttachArea *) clientData;
1037
1038     obj->dragSlider( callData );
1039 }
1040
1041 void AttachArea::dragSlider( XtPointer callData )
1042 {
1043     XmScrollBarCallbackStruct *cbs = (XmScrollBarCallbackStruct *)callData;
1044
1045     if(cbs->value == _currentRow)
1046         return;
1047     _currentRow = cbs->value;
1048     DisplayAttachmentsInRow(_currentRow);
1049 }
1050
1051 //
1052 // Calculate the number of rows
1053 //
1054
1055 void AttachArea::CalcLastRow()
1056 {
1057     int i;
1058     unsigned row = 0;
1059      Attachment **list = getList();
1060  
1061      for(i=0;i<getIconCount();i++) {
1062         if(!list[i]->isDeleted()) {
1063             row = list[i]->getRow();
1064         }
1065      }
1066     _lastRow = row;
1067 }
1068
1069 //
1070 // Set the XmmNmaximum resource to size
1071 //
1072
1073 void AttachArea::SetScrollBarSize(unsigned int size)
1074 {
1075     XtVaSetValues(_vsb, 
1076         XmNmaximum, size,
1077         NULL);
1078 }
1079
1080 //
1081 // If the current row is greater than the last row, adjust the
1082 // current row to be equal to the last row.
1083 //
1084
1085 void AttachArea::AdjustCurrentRow()
1086 {
1087     if(_currentRow > _lastRow) {
1088         _currentRow = _lastRow;
1089         XtVaSetValues(_vsb, XmNvalue, _currentRow, NULL);
1090     }
1091 }
1092
1093 XmString
1094 AttachArea::getSelectedAttachName()
1095 {
1096     XmString str = (XmString)NULL;
1097
1098     if(_cache_single_attachment)
1099         str = _cache_single_attachment->getLabel();
1100
1101     return(str);
1102 }
1103
1104 void
1105 AttachArea::setSelectedAttachName(
1106     XmString new_name
1107 )
1108 {
1109     int i;
1110     Boolean set = FALSE;
1111     Attachment **list = this->getList();
1112
1113     XmString nn = XmStringCopy(new_name);
1114
1115     // Set name of first selected attachment to new_name
1116     for(i=0;i<this->getIconCount() && !set;i++)
1117         if(list[i]->isSelected()) {
1118             list[i]->rename(nn);
1119             set = TRUE;
1120         }
1121     this->manageList();
1122 }
1123
1124
1125 void
1126 AttachArea::attachmentSelected(
1127     Attachment *attachment
1128
1129 {
1130     // First deselect other selected attachments
1131     this->unselectOtherSelectedAttachments(attachment);
1132     
1133     // Enable the menu item at the toplevel shell's menubar.
1134     if(_cache_single_attachment == NULL)
1135         _myOwner->owner()->attachment_selected();
1136
1137     // Cache the single selected attachment
1138     _cache_single_attachment = attachment;
1139     _attach_area_selection_state = AA_SEL_SINGLE;
1140 }
1141
1142 void
1143 AttachArea::attachmentFeedback(
1144     Boolean value
1145 )
1146 {
1147     _myOwner->owner()->attachmentFeedback(value);
1148 }
1149     
1150 char *
1151 AttachArea::calcKbytes(unsigned int bytes)
1152 {
1153     static char kstring[64];
1154
1155     if(bytes < 103)
1156         sprintf(kstring, "%d bytes",bytes);
1157     else if(bytes < 1024)
1158         sprintf(kstring, " .%dk", bytes/103);
1159     else
1160         sprintf(kstring, "%dk", bytes/1024);
1161
1162     return kstring;
1163 }
1164
1165 void
1166 AttachArea::addToRowOfAttachmentsStatus()
1167 {
1168     XmString labelStr2;
1169
1170     // Size of first label
1171     
1172     labelStr2 = XmStringCreateLocalized(
1173                         GETMSG(DT_catd, 3, 37, "Summary of attachments"));
1174
1175
1176     _attachments_summary = XtCreateManagedWidget("Attachments_Summary", 
1177                                                  xmLabelWidgetClass,
1178                                                  rowOfAttachmentsStatus, NULL, 0);
1179
1180     XtVaSetValues(_attachments_summary,
1181                   XmNalignment, XmALIGNMENT_END,
1182                   XmNlabelString, labelStr2,
1183                   XmNrightAttachment, XmATTACH_FORM,
1184                   NULL );
1185
1186      XmStringFree(labelStr2);
1187 }
1188
1189 void
1190 AttachArea::parseAttachments(
1191     DtMailEnv &mail_error,
1192     DtMail::Message* msg,
1193     Boolean empty,
1194     int startBP
1195 )
1196 {
1197     DtMail::BodyPart * tmpBP;
1198     int index = 1;
1199     int num_attachments = 0;
1200     char * name;
1201
1202
1203     // First unmanage and empty out the current contents.
1204
1205     // SMD sets this boolean to FALSE so that previous message's attachments
1206     // are not cleared.  E.g. Including/forwarding multiple messages each
1207     // with attachments.
1208     // RMW sets this boolean to TRUE so that all attachments are cleared in
1209     // the attachment pane everytime a new message is displayed.
1210
1211     if ( empty ) {
1212
1213         // First unmanage the clipWindow.
1214         // Unmanaging the attachment pane is visually ugly
1215
1216         XtUnmanageChild(_clipWindow);
1217         this->clearAttachArea();
1218     }
1219
1220     _deleteCount = 0;
1221
1222     // Now fill list with new attachments.
1223
1224     tmpBP = msg->getFirstBodyPart(mail_error);
1225     if (mail_error.isSet()) {
1226         // do something
1227     }
1228
1229     // Sync up the index with the bodyPart from which to begin
1230     // adding attachments into attachPane.
1231     // 
1232     while (startBP > index) {
1233         tmpBP = msg->getNextBodyPart(mail_error, tmpBP);
1234         index++;
1235     }
1236     
1237     while (tmpBP != NULL) {
1238         num_attachments++;
1239         tmpBP->getContents(
1240                         mail_error,
1241                         NULL,
1242                         NULL,
1243                         NULL,
1244                         &name,
1245                         NULL,
1246                         NULL);
1247         
1248         if (mail_error.isSet()) {
1249             // do something
1250         }
1251
1252         // It is possible for an attachment to not have a name.
1253         if (!name) {
1254             name = "NoName";
1255         }
1256
1257         this->addAttachment(name, tmpBP);
1258         tmpBP = msg->getNextBodyPart(mail_error, tmpBP);
1259         if (mail_error.isSet()) {
1260             // do something
1261         }
1262
1263         free(name);
1264     }
1265 }
1266
1267 void
1268 AttachArea::attachment_summary(
1269     int live,
1270     int dead
1271 )
1272 {
1273
1274     char *buf = NULL;
1275     char * tmp1;
1276     char * tmp2;
1277
1278     if ((live == 1) && (dead == 0)) {
1279         tmp1 = GETMSG(DT_catd, 3, 38, "attachment");
1280         buf = new char[strlen(tmp1) + 64];
1281         sprintf(buf, "%d %s", live, tmp1);
1282     }
1283     else if ((live >= 0) && (dead == 0)) {
1284         /* NL_COMMENT
1285          * "attachments" is the plural form of "attachment".
1286          */
1287         tmp1 = GETMSG(DT_catd, 3, 39, "attachments");
1288         buf = new char[strlen(tmp1) + 64];
1289         sprintf(buf, "%d %s", live, tmp1);
1290     }
1291     else if ((live >= 0) && (dead > 0)) {
1292         tmp1 = GETMSG(DT_catd, 3, 40, "attachments");
1293         tmp2 = GETMSG(DT_catd, 3, 41, "deleted");
1294         buf = new char[strlen(tmp1) + strlen(tmp2) + 64];
1295         sprintf(buf, "%d %s, %d %s", live, tmp1, dead, tmp2);
1296     }
1297     
1298     if (buf) {
1299         XmString buf_str = XmStringCreateLocalized(buf);
1300         XtVaSetValues(_attachments_summary,
1301             XmNlabelString, buf_str,
1302             NULL );
1303     
1304         delete [] buf;
1305         XmStringFree(buf_str);
1306     }
1307 }
1308
1309 void
1310 AttachArea::manage()
1311 {
1312     XtArgVal /* Dimension */ ht;
1313     XtArgVal /* Dimension */ pht;
1314     Widget sww;
1315
1316     // Update the display
1317     sww = getSWWindow();
1318     this->manageList();
1319
1320     XtAddCallback(
1321                 _clipWindow, 
1322                 XmNresizeCallback, &AttachArea::resizeCallback,
1323                 (XtPointer) this );
1324
1325     XtAddCallback(
1326                 _clipWindow, 
1327                 XmNinputCallback, &AttachArea::inputCallback,
1328                 (XtPointer) this);
1329
1330     XtAddEventHandler(
1331                 _clipWindow, ButtonPressMask,
1332                 FALSE, MenuButtonHandler,
1333                 (XtPointer) this);
1334
1335     // hack
1336     XtVaGetValues(sww, XmNheight, &ht, NULL);
1337     XtVaGetValues(_w, XmNheight, &pht, NULL);
1338     // Manage the clipWindow back
1339     if (!XtIsManaged(_clipWindow)) XtManageChild(_clipWindow);
1340
1341     // hack
1342     XtVaSetValues(sww, XmNheight, ht, NULL);
1343     UIComponent::manage();
1344     XtVaSetValues(_w, XmNheight, pht, NULL);
1345 }
1346
1347 void
1348 AttachArea::unmanage()
1349 {
1350     int i;
1351     Attachment **list = getList();
1352
1353     // Unmanage the widgets it currently has
1354     for (i=0; i<getIconCount(); i++)
1355       list[i]->unmanageIconWidget();
1356
1357     XtRemoveCallback(
1358         _clipWindow, 
1359         XmNresizeCallback, &AttachArea::resizeCallback,
1360         (XtPointer) this );
1361
1362     XtRemoveCallback(
1363         _clipWindow, 
1364         XmNinputCallback, &AttachArea::inputCallback,
1365         (XtPointer) this );
1366
1367     XtRemoveEventHandler(
1368         _clipWindow, ButtonPressMask,
1369         FALSE, MenuButtonHandler,
1370         (XtPointer) this);
1371
1372     UIComponent::unmanage();
1373 }
1374
1375 void
1376 AttachArea::removeCurrentAttachments()
1377 {
1378
1379     Attachment **list = getList();
1380     int i;
1381
1382     // Unmanage the widgets it currently has
1383
1384     for (i=0; i<getIconCount(); i++) {
1385
1386         list[i]->unmanageIconWidget();
1387         list[i]->deleteIt();
1388     }
1389
1390     // Reset
1391     if (_attachmentList)
1392         delete []_attachmentList;
1393     _attachmentList = NULL;
1394     _iconCount = 0;
1395     _deleteCount = 0;
1396     _attach_area_selection_state = AA_SEL_NONE;
1397     _cache_single_attachment = NULL;
1398
1399     this->attachment_summary(_iconCount, _deleteCount);
1400 }
1401
1402 // Similar to removeCurrentAttachments().
1403 // Except we don't display a summary that there are no attachments.
1404 // Plus has potential for other (different) usage.
1405
1406 void
1407 AttachArea::clearAttachArea()
1408 {
1409
1410     Attachment **list = getList();
1411     int i;
1412
1413     // Unmanage the widgets it currently has
1414
1415     for (i=0; i<getIconCount(); i++) {
1416
1417         list[i]->unmanageIconWidget();
1418         delete list[i];
1419     }
1420
1421     // Reset
1422     if (_attachmentList)
1423         delete []_attachmentList;
1424     _attachmentList = NULL;
1425     _iconCount = 0;
1426     _deleteCount = 0;
1427     _attach_area_selection_state = AA_SEL_NONE;
1428     _cache_single_attachment = NULL;
1429 }
1430
1431 #ifdef DEAD_WOOD
1432 void
1433 AttachArea::saveAttachmentToFile(
1434     DtMailEnv &mail_error,
1435     char *save_path
1436 )
1437 {
1438
1439     Attachment *attachment = this->getSelectedAttachment();
1440
1441     if(attachment != NULL)
1442         attachment->saveToFile(mail_error, save_path);
1443
1444 }
1445 #endif /* DEAD_WOOD */
1446
1447 void
1448 AttachArea::deleteSelectedAttachments(
1449     DtMailEnv &         //mail_error
1450 )
1451 {
1452     Attachment **list = getList();
1453     int i;
1454     
1455     for (i = 0; i<getIconCount(); i++) {
1456         if (list[i]->isSelected() && !list[i]->isDeleted()) {
1457
1458             // unselect it first.  Else, when undeleted it comes
1459             // off selected
1460             
1461             list[i]->unselect();
1462             list[i]->deleteIt();
1463             _deleteCount++;
1464         }
1465     }
1466     
1467     // Unmanage all.
1468     // Their positions need to get recomputed and the undeleted
1469     // ones get remanaged in manageList().
1470
1471     for (i=0; i<getIconCount(); i++) {
1472         list[i]->unmanageIconWidget();
1473     }
1474
1475     _cache_single_attachment = NULL;
1476     _attach_area_selection_state = AA_SEL_NONE;
1477
1478     this->manageList();
1479 }
1480
1481
1482 #ifdef DEAD_WOOD
1483 void
1484 AttachArea::undeleteAllDeletedAttachments(
1485     DtMailEnv &         //mail_error
1486 )
1487 {
1488 }
1489 #endif /* DEAD_WOOD */
1490
1491 void
1492 AttachArea::undeleteLastDeletedAttachment(
1493     DtMailEnv &mail_error
1494 )
1495 {
1496
1497     Attachment *tmpAttachment;
1498     Attachment **list;
1499     time_t time_deleted = 0, tmpTime = 0;
1500     int i;
1501
1502     if (_deleteCount == 0) {
1503         return;
1504     }
1505
1506     list = getList();
1507
1508     tmpAttachment = list[0];
1509     time_deleted = tmpAttachment->getBodyPart()->getDeleteTime(mail_error);
1510     if (mail_error.isSet()) {
1511         // do something
1512     }
1513
1514     for (i=1; i<getIconCount(); i++) {
1515         if (list[i]->isDeleted()) {
1516             tmpTime = list[i]->getBodyPart()->getDeleteTime(mail_error);
1517             if (mail_error.isSet()) {
1518                 // do something
1519             }
1520             if ( tmpTime > time_deleted) {
1521                 time_deleted = tmpTime;
1522                 tmpAttachment = list[i];
1523             }
1524         }
1525     }
1526
1527     tmpAttachment->undeleteIt();
1528     _deleteCount--;
1529
1530     // Unmanage all.
1531     // Their positions need to get recomputed and the deleted
1532     // ones get remanaged in manageList().
1533
1534     for (i=0; i<getIconCount(); i++) {
1535         list[i]->unmanageIconWidget();
1536     }
1537
1538
1539     this->manageList();
1540
1541 }
1542
1543     
1544 void
1545 AttachArea::unselectOtherSelectedAttachments(
1546     Attachment *attachment
1547 )
1548 {
1549     if(_attach_area_selection_state == AA_SEL_NONE)
1550         return;
1551
1552     if(_attach_area_selection_state == AA_SEL_ALL) {
1553         int i;
1554         Attachment **list;
1555
1556         list = getList(); 
1557
1558         for (i=0; i < getIconCount(); i++) 
1559             if (list[i]->isSelected() && list[i] != attachment) 
1560                 list[i]->unselect();
1561     } 
1562     else if (_cache_single_attachment && 
1563             (attachment != _cache_single_attachment)) {
1564         _cache_single_attachment->unselect();
1565         _cache_single_attachment = NULL;
1566     }
1567
1568    if(attachment == NULL) {
1569         // Grey out the appropriate menu items in the RMW...
1570         _myOwner->owner()->all_attachments_deselected();
1571         _attach_area_selection_state = AA_SEL_NONE;
1572         _cache_single_attachment = NULL;
1573    }
1574 }
1575
1576 void
1577 AttachArea::addAttachmentActions(
1578     char **actions,
1579     int indx
1580 )
1581 {
1582
1583     _myOwner->owner()->addAttachmentActions(
1584                                 actions,
1585                                 indx
1586                         );
1587
1588 }
1589
1590 void
1591 AttachArea::setOwnerShell(
1592     RoamMenuWindow *rmw
1593 )
1594 {
1595     _myRMW = rmw;
1596 }
1597
1598 void
1599 AttachArea::setOwnerShell(
1600     ViewMsgDialog *vmd
1601 )
1602 {
1603     _myVMD = vmd;
1604 }
1605
1606 void
1607 AttachArea::setOwnerShell(
1608     SendMsgDialog *smd
1609 )
1610 {
1611     _mySMD = smd;
1612 }
1613
1614 Widget
1615 AttachArea::ownerShellWidget()
1616 {
1617     if (_myRMW) {
1618         return(_myRMW->baseWidget());
1619     }
1620     else if (_myVMD) {
1621         return(_myVMD->baseWidget());
1622     }
1623     else if (_mySMD) {
1624         return(_mySMD->baseWidget());
1625     }
1626     else {
1627         // Error out
1628     }
1629     return((Widget) NULL);
1630 }
1631
1632 Boolean
1633 AttachArea::isOwnerShellEditable()
1634 {
1635     // only SMD is editable
1636     if (_mySMD != NULL) {
1637         return TRUE;
1638     }
1639     else {
1640         return FALSE;
1641     }
1642 }
1643
1644 void
1645 AttachArea::setPendingAction(
1646     Boolean bval
1647 )
1648 {
1649     _pendingAction = bval;
1650     if (bval) {
1651         _numPendingActions++;
1652     }
1653     else {
1654         if (_numPendingActions > 0) {
1655             _numPendingActions--;
1656         }
1657     }
1658 }
1659
1660 void
1661 AttachArea::resetPendingAction()
1662 {
1663
1664     _numPendingActions = 0;
1665 }
1666
1667 int
1668 AttachArea::getNumPendingActions()
1669 {
1670     return(_numPendingActions);
1671 }
1672
1673 void
1674 AttachArea::selectAllAttachments()
1675 {
1676     
1677     Attachment **list;
1678     int numAttachments = getIconCount();
1679
1680     list = getList(); 
1681     
1682     if(list == NULL)
1683         return;
1684
1685     // if there's only 1 attachment, select it and
1686     // add its actions to the menu bar...
1687
1688     if (numAttachments == 1) {
1689         list[0]->primitive_select();
1690         list[0]->set_selected();
1691     }
1692     else {
1693         // More than 1 attachment.
1694         // Select them all. Don't enable their actions however.
1695
1696         for (int i=0; i < numAttachments; i++) 
1697             list[i]->primitive_select();
1698
1699         // Grey out the appropriate menu items in the RMW...
1700         _myOwner->owner()->all_attachments_selected();
1701         _cache_single_attachment = NULL;
1702         _attach_area_selection_state = AA_SEL_ALL;
1703     }
1704 }
1705
1706 int
1707 AttachArea::handleQuestionDialog(
1708     char *title,
1709     char *buf,
1710     char * helpId
1711 )
1712 {
1713     DtMailGenDialog *dialog;
1714     int answer;
1715
1716     if (_myRMW) {
1717         dialog = _myRMW->genDialog();
1718     }
1719     else if (_myVMD) {
1720         dialog = _myVMD->genDialog();
1721     }
1722     else if ( _mySMD) {
1723         dialog = _mySMD->genDialog();
1724     }
1725     else return(-1);
1726
1727     if (!dialog) return(-1);
1728
1729     dialog->setToQuestionDialog(
1730                         title,
1731                         buf);
1732     answer = dialog->post_and_return(helpId);
1733     return(answer);
1734 }
1735
1736 int
1737 AttachArea::handleErrorDialog(
1738     char *title,
1739     char *buf,
1740     char *helpId
1741 )
1742 {
1743     DtMailGenDialog *dialog;
1744     int answer;
1745
1746     if (_myRMW) {
1747         dialog = _myRMW->genDialog();
1748     }
1749     else if (_myVMD) {
1750         dialog = _myVMD->genDialog();
1751     }
1752     else if ( _mySMD) {
1753         dialog = _mySMD->genDialog();
1754     }
1755     else return(-1);
1756
1757     if (!dialog) return(-1);
1758
1759     dialog->setToErrorDialog(title, buf);
1760     answer = dialog->post_and_return(helpId);
1761     return(answer);
1762 }