2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
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)
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
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
23 /* $TOG: Attachment.C /main/16 1998/07/23 17:58:44 mgreess $
25 * (c) Copyright 1996 Digital Equipment Corporation.
26 * (c) Copyright 1996 Hewlett-Packard Company.
27 * (c) Copyright 1996 International Business Machines Corp.
28 * (c) Copyright 1993-1996 Sun Microsystems, Inc.
29 * (c) Copyright 1996 Novell, Inc.
30 * (c) Copyright 1996 FUJITSU LIMITED.
31 * (c) Copyright 1996 Hitachi.
36 * RESTRICTED CONFIDENTIAL INFORMATION:
38 * The information in this document is subject to special
39 * restrictions in a confidential disclosure agreement between
40 * HP, IBM, Sun, USL, SCO and Univel. Do not distribute this
41 * document outside HP, IBM, Sun, USL, SCO, or Univel without
42 * Sun's specific written approval. This document and all copies
43 * and derivative works thereof must be returned or destroyed at
49 #include <EUSCompat.h> // For strcasecmp()
52 #include <sys/types.h>
60 #include <sys/utsname.h>
66 #include <Xm/BulletinB.h>
67 #include <Xm/AtomMgr.h>
68 #include <Xm/DragDrop.h>
69 #include <Xm/Screen.h>
71 #include <Xm/PushBG.h>
72 #include <Xm/LabelG.h>
73 #include <X11/IntrinsicP.h>
74 #include <X11/Xatom.h>
76 #include "Attachment.h"
78 #include "RoamMenuWindow.h"
80 #include "InfoDialogManager.h"
81 #include "ViewMsgDialog.h"
82 #include "RoamMenuWindow.h"
84 #include "MailSession.hh"
86 #include <DtMail/DtMailError.hh>
87 #include <DtMail/IO.hh> // SafeAccess...
88 #include "MemUtils.hh"
89 #include "DtMailHelp.hh"
90 #include "str_utils.h"
94 extern XtPointer _XmStringUngenerate (
98 XmTextType output_type);
101 extern nl_catd DtMailMsgCat;
103 unsigned char validbits[] = {
104 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
105 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00,
106 0x00, 0xfc, 0x3f, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0x00, 0x1f, 0xf8, 0x00,
107 0x80, 0x07, 0xe0, 0x01, 0x80, 0x03, 0xc0, 0x01, 0xc0, 0x01, 0x80, 0x03,
108 0xc0, 0x01, 0x80, 0x03, 0xe0, 0x00, 0x00, 0x07, 0xe0, 0x80, 0x01, 0x07,
109 0xe0, 0xc0, 0x03, 0x07, 0xe0, 0xc0, 0x03, 0x07, 0xe0, 0x80, 0x01, 0x07,
110 0xe0, 0x00, 0x00, 0x07, 0xc0, 0x01, 0x80, 0x03, 0xc0, 0x01, 0x80, 0x03,
111 0x80, 0x03, 0xc0, 0x01, 0x80, 0x07, 0xe0, 0x01, 0x00, 0x1f, 0xf8, 0x00,
112 0x00, 0xfe, 0x7f, 0x00, 0x00, 0xfc, 0x3f, 0x00, 0x00, 0xf0, 0x0f, 0x00,
113 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
114 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
116 unsigned char invalidbits[] = {
117 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
118 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00,
119 0x00, 0xfc, 0x3f, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0x00, 0x1f, 0xf8, 0x00,
120 0x80, 0x0f, 0xe0, 0x01, 0x80, 0x1f, 0xc0, 0x01, 0xc0, 0x3f, 0x80, 0x03,
121 0xc0, 0x7d, 0x80, 0x03, 0xe0, 0xf8, 0x00, 0x07, 0xe0, 0xf0, 0x01, 0x07,
122 0xe0, 0xe0, 0x03, 0x07, 0xe0, 0xc0, 0x07, 0x07, 0xe0, 0x80, 0x0f, 0x07,
123 0xe0, 0x00, 0x1f, 0x07, 0xc0, 0x01, 0xbe, 0x03, 0xc0, 0x01, 0xfc, 0x03,
124 0x80, 0x03, 0xf8, 0x01, 0x80, 0x07, 0xf0, 0x01, 0x00, 0x1f, 0xf8, 0x00,
125 0x00, 0xfe, 0x7f, 0x00, 0x00, 0xfc, 0x3f, 0x00, 0x00, 0xf0, 0x0f, 0x00,
126 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
127 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
129 #define equal(a, b) (!strcasecmp(a,b))
134 void runit_callback( int *data );
135 void norunit_callback( int *data );
136 #endif /* DEAD_WOOD */
137 static void okcb(XtPointer);
143 * A note on this bug, several related bugs, design of C++ programs and
144 * general coding style and proficiency. This module, as well as most
145 * others in the dtmail application, violate many elements of good
146 * OO design. Poor compartmentalization, poor abstraction, ambiguous data
147 * ownership, ambiguous data model, lack of a clear Model/View/Controller
148 * structure are all examples of things going wrong or being done badly.
149 * In the case at hand, we have a much larger problem (inadequate design
150 * of mmap()'d file handling) causing numerous small bugs from a
151 * collaboration with these design problems. I will workaround the
152 * bug and the design flaw by moving data ownership into this Class thus
153 * adding stones to the Chinese Wall that separates this UI-like class
154 * from the model-like classes in RFC. However, it is in no way a
155 * real fix for the problems dtmail is experiencing.
158 Attachment::Attachment(
159 AttachArea *classparent,
161 DtMail::BodyPart *body_part,
167 _parent(classparent),
168 _body_part(body_part),
172 _myAllocContents(NULL),
175 _haveContents(FALSE),
180 if(strchr(name, '/') == NULL) // The name does not include a slash
181 _label = XmStringCreateLocalized(name);
182 else // The name does include a slash
183 _label = XmStringCreateLocalized(strrchr(name, '/')+1);
185 _key = theRoamApp.session()->session()->newObjectKey();
188 Attachment::~Attachment(
192 theRoamApp.session()->session()->removeObjectKey(_key);
195 XmStringFree (_label);
205 if (_myActionsList) {
206 delete []_myActionsList;
208 if (_myAllocContents) {
209 delete [] _myAllocContents;
211 _myAllocContents = NULL;
218 Attachment::setAttachArea(AttachArea *aa)
225 Attachment::initialize()
229 assert( _parent != NULL);
233 widgetparent = _parent->getClipWindow();
235 _foreground = _parent->owner()->textEditor()->get_text_foreground();
236 _background = _parent->owner()->textEditor()->get_text_background();
240 // We already have the name from the classing engine. Now map
241 // the name to the MIME type and subtype
244 myIcon = new Icon(this, _name, _label, _type, widgetparent, _index);
246 _w = myIcon->baseWidget();
257 sw = _parent->getSWWindow();
260 XtSetArg(args[n], XmNwidth, &_attachmentWidth); n++;
261 XtSetArg(args[n], XmNheight, &_attachmentHeight); n++;
262 XtGetValues(_w, args, n);
263 XtSetArg(args[0], XmNheight, &aaHeight); n++;
264 XtGetValues(sw, args, 1);
265 if( aaHeight < (_attachmentHeight+20) )
267 XtSetArg(args[0],XmNheight,(_attachmentHeight+20));
268 XtSetValues(sw, args, 1);
273 installDestroyHandler();
278 Attachment::check_if_binary(String contents, unsigned long size)
282 for(i=0;i<size;i++) {
283 if((!isprint(contents[i])) && (!isspace(contents[i])))
288 #endif /* DEAD_WOOD */
291 // Map the name (which we got from the classing engine) to a
296 Attachment::name_to_type()
298 char *subtype = new char[128];
301 // Hardcode ce_name to be text for now.
302 // It should actually be determined dynamically from the type of
307 // If the type and subtype are already set then we don't need to
308 // map a classing engine type to a MIME type; We already have
309 // the MIME type, so just return
312 if(equal(_ce_name, "text")) { // text
314 _subtype = strdup("plain");
315 } else if(equal(_ce_name, "richtext")) { // richtext
317 sprintf(subtype, "X-sun-%s",_ce_name);
318 _subtype = strdup(subtype);
319 } else if(equal(_ce_name, "audio-file")) { // audio-file
321 _subtype = strdup("basic");
322 } else if(equal(_ce_name, "default")) { // default
323 _type = TYPEAPPLICATION;
324 sprintf(subtype, "X-sun-%s",_ce_name);
325 _subtype = strdup(subtype);
326 } else if(equal(_ce_name, "oda")) { // oda
327 _type = TYPEAPPLICATION;
328 _subtype = strdup("oda");
329 } else if(equal(_ce_name, "postscript-file")) { // postscript
330 _type = TYPEAPPLICATION;
331 _subtype = strdup("PostScript");
332 } else if(equal(_ce_name, "sun-raster")) { // sun-raster
334 sprintf(subtype, "X-%s",_ce_name);
335 _subtype = strdup(subtype);
336 } else if(equal(_ce_name, "jpeg-file")) { // jpeg-file
338 _subtype = strdup("jpeg");
339 } else if(equal(_ce_name, "g3-file")) { // g3-file
341 sprintf(subtype, "X-sun-%s",_ce_name);
342 _subtype = strdup(subtype);
343 } else if(equal(_ce_name, "gif-file")) { // gif-file
345 _subtype = strdup("gif");
346 } else if(equal(_ce_name, "pbm-file")) { // pbm-file
348 sprintf(subtype, "X-sun-%s",_ce_name);
349 _subtype = strdup(subtype);
350 } else if(equal(_ce_name, "pgm-file")) { // pgm-file
352 sprintf(subtype, "X-sun-%s",_ce_name);
353 _subtype = strdup(subtype);
354 } else if(equal(_ce_name, "ppm-file")) { // ppm-file
356 sprintf(subtype, "X-sun-%s",_ce_name);
357 _subtype = strdup(subtype);
358 } else if(equal(_ce_name, "xpm-file")) { // xpm-file
360 sprintf(subtype, "X-sun-%s",_ce_name);
361 _subtype = strdup(subtype);
362 } else if(equal(_ce_name, "tiff-file")) { // tiff-file
364 sprintf(subtype, "X-sun-%s",_ce_name);
365 _subtype = strdup(subtype);
366 } else if(equal(_ce_name, "troff")) { // troff
368 sprintf(subtype, "X-sun-%s",_ce_name);
369 _subtype = strdup(subtype);
370 } else if(equal(_ce_name, "nroff")) { // nroff
372 sprintf(subtype, "X-sun-%s",_ce_name);
373 _subtype = strdup(subtype);
374 } else if(equal(_ce_name, "h-file")) { // h-file
376 sprintf(subtype, "X-sun-%s",_ce_name);
377 _subtype = strdup(subtype);
378 } else if(equal(_ce_name, "c-file")) { // c-file
380 sprintf(subtype, "X-sun-%s",_ce_name);
381 _subtype = strdup(subtype);
382 } else if(equal(_ce_name, "makefile")) { // makefile
384 sprintf(subtype, "X-sun-%s",_ce_name);
385 _subtype = strdup(subtype);
386 } else if(equal(_ce_name, "mail-file")) { // mail-file
388 sprintf(subtype, "X-sun-%s",_ce_name);
389 _subtype = strdup(subtype);
390 } else if(equal(_ce_name, "mail-message")) { // mail-message
392 sprintf(subtype, "X-sun-%s",_ce_name);
393 _subtype = strdup(subtype);
395 _type = TYPEAPPLICATION;
396 sprintf(subtype, "X-sun-%s",_ce_name);
397 _subtype = strdup(subtype);
403 Attachment::invokeAction(int index)
405 char *actionCommand = NULL;
406 DtActionArg *actionArg = NULL;
407 DtActionBuffer bufArg;
412 if (_myActionsList == NULL || NULL == _myActionsList[index]) return;
415 actionCommand = _myActionsList[index];
416 memset(&bufArg, 0, sizeof(bufArg));
418 bufArg.bp = (void *)_myContents;
419 bufArg.size = (int) _myContentsSize;
421 // Determine the type based on the contents.
422 // This is to compensate for errors that other MUAs could have
423 // generated: some claim a bodyPart is rfc822 but deliver something else.
424 type = bufArg.type = DtDtsBufferToDataType(
426 (const int) _myContentsSize,
429 if (_parent->isOwnerShellEditable())
430 bufArg.writable = TRUE;
432 bufArg.writable = FALSE;
434 // If this is the default action (aka Run) and the attachment is executable,
435 // display a dialog informing the user of the risks of executing it.
436 exble = DtDtsDataTypeToAttributeValue(type, DtDTS_DA_IS_EXECUTABLE, _name);
437 if (0 == index && NULL != exble && DtDtsIsTrue(exble))
440 char *buf = new char[2048];
443 GETMSG(DT_catd, 3, 81, "This attachment may contain commands that can cause serious\ndamage. It is recommended that you only execute it after you\nare certain it is safe to do so.\n\nPress OK if you are certain it is safe,\nCancel to cancel execution."));
445 answer = parent()->handleQuestionDialog(
446 GETMSG(DT_catd, 1, 86, "Mailer"),
448 DTMAILHELPEXECUTEOK);
450 if (answer == 2) return;
454 actionArg = (DtActionArg *) malloc(sizeof(DtActionArg) * 1);
455 memset(actionArg, 0, sizeof(DtActionArg));
456 actionArg->argClass = 2;
457 actionArg->u.buffer = bufArg;
459 ActionCallback *acb = new ActionCallback(_key, this);
461 _parent->ownerShellWidget(),
462 actionCommand, actionArg,
463 1, NULL, NULL, NULL, 1,
464 (DtActionCallbackProc)& Attachment::actionCallback, acb);
468 Attachment::handleDoubleClick()
470 _parent->attachmentFeedback(TRUE);
472 _parent->attachmentFeedback(FALSE);
475 static void okcb( XtPointer )
478 // This function exists so that the OK button will appear on the
479 // Info Dialog. It doesn't have to do anything because the dialog
480 // automatically pops down. It is for information only.
485 runit_callback(int *data)
491 norunit_callback(int *data)
495 #endif /* DEAD_WOOD */
498 Attachment::operator==
507 Attachment::set_selected()
509 char *actions_list = NULL; //Comma separated list of actions
515 parent()->attachmentSelected(this);
518 // Assuming that only 10 actions are possible.
519 // Need a mechanism to query, determine how many possible and
520 // allocate memory for that many.
522 _myActionsList = new char*[10];
524 // Retrieve the actions list. Walk through the list and
525 // for each item in it, ask the parent to create a menu item
526 // in its parent's menubar.
528 actions_list = DtDtsDataTypeToAttributeValue(
530 DtDTS_DA_ACTION_LIST,
534 char **tmpActionCommand = _myActionsList;
536 if (actions_list != NULL)
537 anAction = strtok(actions_list, ",");
538 if (anAction == NULL) {
542 *tmpActionCommand = strdup(anAction);
544 while (*tmpActionCommand != NULL) {
546 // strtok() requires that calls other than the first have NULL as
552 anAction = strtok(NULL, ",");
553 if (anAction == NULL) {
554 *tmpActionCommand = NULL;
557 *tmpActionCommand = strdup(anAction);
560 parent()->addAttachmentActions(
565 free((void*) actions_list);
569 Attachment::unselect()
575 // Save the attachment to the specified file.
577 Attachment::saveToFile(DtMailEnv &, char *filename)
580 char *buf = new char[2048];
583 if (SafeAccess(filename, F_OK) == 0) {
585 sprintf(buf, GETMSG(DT_catd, 3, 42, "%s already exists. Replace?"),
587 helpId = DTMAILHELPALREADYEXISTS;
589 answer = parent()->handleQuestionDialog(GETMSG(DT_catd,
595 if (answer == 2) { // Pressed cancel
600 if (unlink(filename) < 0) {
601 sprintf(buf, GETMSG(DT_catd, 3, 43, "Unable to replace %s."), filename);
602 helpId = DTMAILHELPNOREPLACE;
603 answer = parent()->handleErrorDialog(GETMSG(DT_catd,
614 // if (_myContentsSize == 0) {// Oops! BE thinks attachment is of size 0.
615 // sprintf(buf, "Mailer BE thinks attachment is size 0.\nPlease call a Dtmail engineer to attach a debugger\n to this process to begin debugging. Only after attaching the debugger should you click OK.\n");
616 // answer = parent()->handleErrorDialog("BUG!", buf);
618 // // Call setContents again.
619 // // This will help us debug why the body part has bogus contents.
620 // this->setContents();
623 // Create or truncate, and then write the bits.
625 int fd = SafeOpen(filename, O_RDWR | O_CREAT | O_TRUNC, 0600);
627 sprintf(buf, GETMSG(DT_catd, 3, 44, "Unable to create %s."), filename);
628 helpId = DTMAILHELPNOCREATE;
629 answer = parent()->handleErrorDialog(GETMSG(DT_catd, 1, 87, "Mailer"),
636 if (SafeWrite(fd, _myContents, (unsigned int)_myContentsSize) < _myContentsSize) {
637 sprintf(buf, GETMSG(DT_catd, 3, 45, "Unable to create %s."),
639 helpId = DTMAILHELPNOCREATE;
640 answer = parent()->handleErrorDialog(GETMSG(DT_catd, 1, 88, "Mailer"),
651 // Stat the created file and see if it is of size 0.
652 // If it is, engage the user in a dialog and involve a dtmail engineer
653 // to attach a debugger to this process.
656 // SafeStat(filename, &sbuf);
658 // if (sbuf.st_size == 0) {
659 // sprintf(buf, "Mailer produced a zero length file.\nPlease call a Dtmail engineer to attach a debugger\n to this process to begin debugging. Only after attaching the debugger should you click OK.\n");
660 // answer = parent()->handleErrorDialog("BUG!", buf);
676 was_managed = isManaged();
677 if (was_managed) unmanageIconWidget();
680 XtSetArg(args[n], XtNx, x); n++;
681 XtSetValues( _w, args,n);
683 if (was_managed) manageIconWidget();
697 was_managed = isManaged();
698 if (was_managed) unmanageIconWidget();
701 XtSetArg(args[n], XtNy, y); n++;
702 XtSetValues( _w, args,n);
704 if (was_managed) manageIconWidget();
715 #endif /* DEAD_WOOD */
719 Attachment::actionCallback(
720 DtActionInvocationID id,
721 XtPointer clientData,
722 DtActionArg *action_arg,
724 DtActionStatus status
727 ActionCallback *acb = (ActionCallback *) clientData;
728 if (theRoamApp.session()->session()->validObjectKey(
729 acb->_myKey) == DTM_FALSE) {
730 // Error out. Post an error?
734 acb->_myAttachment->action(id, action_arg, argCount, status);
740 DtActionInvocationID id,
741 DtActionArg *actionArg,
746 DtActionBuffer bufArg;
747 DtMailEnv mail_error;
749 char *buf = new char[2048];
750 const void * lclContents(NULL);
751 unsigned long lclContentsSize(0);
753 // Initialize the mail_error.
756 if (status == DtACTION_INVOKED) {
758 _parent->setPendingAction(TRUE);
760 else if (status == DtACTION_DONE) {
761 unregisterAction(id);
762 _parent->setPendingAction(FALSE);
764 // Check first if ownerShell is an SMD.
765 // Secondly, check if the SMD is still available. If the user had
766 // sent the message while this attachment was up, the SMD's reset()
767 // method would have set the attachments' _deleted flag to TRUE.
768 // So, check to see that the attachment is still valid before setting
771 // Note: actionArg can be NULL if there were no actions associated
772 // with the data type. Is this an Actions bug? Could be, but
773 // we check for it anyway.
775 if (actionArg != NULL && _parent->isOwnerShellEditable() && !_deleted) {
776 if (actionArg->argClass == DtACTION_BUFFER) {
777 bufArg = actionArg->u.buffer;
778 if (bufArg.writable) {
779 // Assume user edited launched attachment -- as
780 // optimization, we can compare buffers to see if
781 // content actually changed. For now, assume it changed.
782 // Make a copy of incoming buffer and set body part's
783 // contents, size. Let BE determine type.
784 // Reset private variables.
785 _body_part->setContents(
789 NULL, NULL, 0, NULL);
791 // if (mail_error.isSet()) {
795 assert(mail_error.isNotSet());
798 // CDExc17304. Note the following curiosity. The caller is considered
799 // the owner of the _myType argument but the called retains ownership
806 _body_part->getContents(
812 // if (mail_error.isSet()) {
815 assert(mail_error.isNotSet());
816 _setMyContents(lclContents, int(lclContentsSize));
818 // Free the buffer...
819 XtFree((char *)bufArg.bp);
823 // Read the file into a buffer and do the same stuff
827 DtActionFile fileArg = actionArg->u.file;
828 struct stat stat_buf;
830 if ( SafeStat ( fileArg.name, &stat_buf ) == -1 ) {
831 mail_error.setError(DTME_ObjectAccessFailed);
832 mail_error.logError(DTM_FALSE, "Mailer: Unable to process action, stat failed on file %s.\n", fileArg.name);
836 tmp_file = SafeOpen(fileArg.name, O_RDONLY);
837 char *tmp_buf = (char*) malloc((size_t) stat_buf.st_size);
838 SafeRead(tmp_file, (void *)tmp_buf, (size_t) stat_buf.st_size);
841 _body_part->setContents(mail_error,
844 NULL, NULL, 0, NULL);
846 assert(mail_error.isNotSet());
856 _body_part->getContents(mail_error,
862 assert(mail_error.isNotSet());
863 _setMyContents(lclContents, int(lclContentsSize));
867 else if (status == DtACTION_INVALID_ID) {
869 * Post a dialog explaining that the action was invalid
873 DT_catd, 3, 91, "Cannot execute invalid action."));
875 answer = parent()->handleErrorDialog(GETMSG(DT_catd, 1, 86, "Mailer"),
878 unregisterAction(id);
879 _parent->setPendingAction(FALSE);
881 else if (status == DtACTION_FAILED) {
884 * Post a dialog explaining that the action failed.
887 GETMSG(DT_catd, 3, 92, "Executing action failed!"));
889 answer = parent()->handleErrorDialog(GETMSG(DT_catd, 1, 86, "Mailer"),
892 unregisterAction(id);
893 _parent->setPendingAction(FALSE);
895 else if (status == DtACTION_STATUS_UPDATE) {
896 // Check if ownerShell is an SMD. Make sure the message has not
897 // been sent before attempting to update things.
899 if(actionArg != NULL && _parent->isOwnerShellEditable() && !_deleted) {
900 if (actionArg->argClass == DtACTION_BUFFER) {
901 bufArg = actionArg->u.buffer;
902 if (bufArg.writable) {
903 // Assume user edited launched attachment -- as
904 // optimization, we can compare buffers to see if
905 // content actually changed. For now, assume it changed.
906 // Make a copy of incoming buffer and set body part's
907 // contents, size. Let BE determine type.
908 // Reset private variables.
909 _body_part->setContents(
913 NULL, NULL, 0, NULL);
915 // if (mail_error.isSet()) {
919 assert(mail_error.isNotSet());
925 _body_part->getContents(
931 // if (mail_error.isSet()) {
935 assert(mail_error.isNotSet());
936 _setMyContents(lclContents, int(lclContentsSize));
939 XtFree((char *)bufArg.bp);
943 // Read the file into a buffer and do the same stuff
947 DtActionFile fileArg = actionArg->u.file;
948 struct stat stat_buf;
950 if ( SafeStat ( fileArg.name, &stat_buf ) == -1 ) {
951 mail_error.setError(DTME_ObjectAccessFailed);
952 mail_error.logError(DTM_FALSE, "Mailer: Unable to process action, stat failed on file %s.\n", fileArg.name);
956 tmp_file = SafeOpen(fileArg.name, O_RDONLY);
957 char *tmp_buf = (char*) malloc((size_t) stat_buf.st_size);
958 SafeRead(tmp_file, (void *)tmp_buf, (size_t) stat_buf.st_size);
961 _body_part->setContents(mail_error,
963 (int) stat_buf.st_size,
964 NULL, NULL, 0, NULL);
966 assert(mail_error.isNotSet());
973 _body_part->getContents(mail_error,
979 assert(mail_error.isNotSet());
980 _setMyContents(lclContents, int(lclContentsSize));
987 else if (status == DtACTION_CANCELED) {
988 unregisterAction(id);
989 _parent->setPendingAction(FALSE);
991 if (actionArg != NULL) {
992 XtFree((char *)(actionArg->u.buffer.bp));
999 Attachment::deleteIt()
1001 DtMailEnv mail_error;
1003 // Initialize the mail_error.
1009 // Need to remove the view from display
1011 // Get the BE to mark the bodyPart as deleted
1012 _body_part->setFlag(mail_error, DtMailBodyPartDeletePending);
1017 Attachment::undeleteIt()
1019 DtMailEnv mail_error;
1021 // Initialize the mail_error.
1027 _body_part->resetFlag(mail_error, DtMailBodyPartDeletePending);
1032 Attachment::registerAction(
1033 DtActionInvocationID id
1036 _canKillSelf = FALSE;
1037 _myActionIds.append(id);
1043 Attachment::unregisterAction(
1044 DtActionInvocationID id
1047 if (_myActionIds.length() == 0) {
1051 _myActionIds.remove(id);
1053 // See copious documentation above.
1062 _canKillSelf = TRUE;
1063 if (_myActionIds.length() == 0) {
1070 ActionCallback::ActionCallback(
1071 DtMailObjectKey key,
1076 _myAttachment = att;
1079 ActionCallback::~ActionCallback()
1086 Attachment::unmanageIconWidget(void)
1089 XtUnmanageChild(_w);
1093 Attachment::manageIconWidget(void)
1100 Attachment::setLabel(XmString str)
1104 _label = XmStringCopy(str);
1107 XtSetArg(args[n], XmNstring, _label); n++;
1108 //The Icon widget needs to be unmanaged first before involking XtSetValues
1109 // Otherwise, the parent of the Icon widget does not allow the icon widget
1110 // resize. The Icon widget will be remanaged after its dimensions (w and h)
1111 // are obtained by XtGetValues. This is a fix of the defect 176690.
1112 unmanageIconWidget();
1113 XtSetValues(_w, args, n);
1116 XtSetArg(args[n], XmNwidth, &_attachmentWidth); n++;
1117 XtSetArg(args[n], XmNheight, &_attachmentHeight); n++;
1118 XtGetValues(_w, args, n);
1123 Attachment::primitive_select()
1126 myIcon->primitiveSelect();
1136 DtMailEnv mail_error;
1140 name = (char *) _XmStringUngenerate(new_name, NULL,
1141 XmMULTIBYTE_TEXT, XmMULTIBYTE_TEXT);
1143 _body_part->setContents(
1148 this->setLabel(new_name);
1152 Attachment::setContents()
1154 DtMailEnv mail_error;
1155 const void * lclContents;
1156 unsigned long lclContentsSize;
1158 // Initialize the mail_error.
1165 _body_part->getContents(
1172 // BE has returned an error condition...
1174 // It would be nice to popup a dialog to let the user know that
1175 // dtmail has run into a problem that it can't resolve. Unfortunately,
1176 // the code for postFatalErrorDialog() has been ifdef'ed out. Perhaps
1177 // the error dialog can be enabled at some point in the future.
1179 // if (mail_error.isSet())
1180 // parent()->myRMW->postFatalErrorDialog(mail_error);
1181 assert ( mail_error.isNotSet() );
1182 _setMyContents(lclContents, int(lclContentsSize));
1184 _haveContents = TRUE;
1186 // If it is a rfc822 message, check if it has From stuffing.
1187 // From stuffing is ">From".
1188 // If it has, advance the pointer to step past the ">" character.
1190 if (_myType && !strcmp(_myType,"DTMAIL_FILE")) {
1192 // If it has a From header, return. The classing engine uses
1193 // that to determine the client that needs to be launched.
1196 0 == strncasecmp((char *)_myContents, "From", 4)) {
1200 // Message doesn't begin with From. It may have From stuffing --
1201 // ">From". Or it may have no From header at all. The MIME
1202 // specs are vague on what headers an Message/RFC822 body part
1203 // has to have. We need From to help the classing engine and
1204 // therefore, we will by force (or hack) make it have a From :-)
1207 0 == strncasecmp((char *)_myContents, ">From", 5)) {
1209 // Has From stuffing.
1211 char *ptr = (char *)_myContents;
1212 ptr++; // Step past the first char
1213 _myContents = (void *) ptr; // Reset contents
1219 // No "From" header.
1220 // Generate a new content string by prepending an
1221 // "From UNKNOWN" header.
1223 char *buffer = NULL;
1224 char *from_hdr = "From UNKNOWN";
1227 // Allocate a buffer for the new contents.
1228 // One for the '\0' and two for the extra newlines.
1229 size = strlen(from_hdr) + int(_myContentsSize) + 3;
1230 buffer = new char[size];
1232 // Look for the first occurance of a colon or a newline.
1234 for (sptr = (char*) _myContents;
1235 *sptr && *sptr != '\n' && *sptr != ':';
1238 // Copy in the default From header.
1239 // Add a second newline if there are no rfc822 message headers.
1240 // Assume that finding a colon prior to a newline indicates
1241 // an rfc822 message header.
1243 sprintf(buffer, "%s\n", from_hdr);
1245 sprintf(buffer, "%s\n\n", from_hdr);
1247 // Copy in the original contents.
1248 size = strlen(buffer);
1249 memcpy(&buffer[size], (char *) _myContents, (int) _myContentsSize);
1250 size += (int) _myContentsSize;
1251 buffer[size] = '\0';
1253 _setMyContents(buffer, size);
1260 Attachment::getContents()
1263 return ( (void *)_myContents );
1266 this->setContents();
1267 return ( (void *)_myContents );
1274 * Makes a real copy of the specified data to be used as the
1275 * attachments's data. Note that a substring of the existing value
1276 * can be passed in as an argument and the right thing will happen.
1279 Attachment::_setMyContents(const void * data, int size)
1281 char * new_contents;
1286 new_contents = new char [new_size + 1];
1287 memcpy(new_contents, data, new_size);
1288 new_contents[new_size] = '\0';
1292 new_contents = NULL;
1294 if (_myAllocContents != NULL) {
1295 delete [] _myAllocContents;
1297 _myAllocContents = new_contents;
1298 _myContents = new_contents;
1299 _myContentsSize = new_size;