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