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();
190 _attachmentWidth = 0;
191 _attachmentHeight = 0;
197 _saveAsFilename = NULL;
206 Attachment::~Attachment(
210 theRoamApp.session()->session()->removeObjectKey(_key);
213 XmStringFree (_label);
223 if (_myActionsList) {
224 delete []_myActionsList;
226 if (_myAllocContents) {
227 delete [] _myAllocContents;
229 _myAllocContents = NULL;
236 Attachment::setAttachArea(AttachArea *aa)
243 Attachment::initialize()
247 assert( _parent != NULL);
251 widgetparent = _parent->getClipWindow();
253 _foreground = _parent->owner()->textEditor()->get_text_foreground();
254 _background = _parent->owner()->textEditor()->get_text_background();
258 // We already have the name from the classing engine. Now map
259 // the name to the MIME type and subtype
262 myIcon = new Icon(this, _name, _label, _type, widgetparent, _index);
264 _w = myIcon->baseWidget();
275 sw = _parent->getSWWindow();
278 XtSetArg(args[n], XmNwidth, &_attachmentWidth); n++;
279 XtSetArg(args[n], XmNheight, &_attachmentHeight); n++;
280 XtGetValues(_w, args, n);
281 XtSetArg(args[0], XmNheight, &aaHeight); n++;
282 XtGetValues(sw, args, 1);
283 if( aaHeight < (_attachmentHeight+20) )
285 XtSetArg(args[0],XmNheight,(_attachmentHeight+20));
286 XtSetValues(sw, args, 1);
291 installDestroyHandler();
296 Attachment::check_if_binary(String contents, unsigned long size)
300 for(i=0;i<size;i++) {
301 if((!isprint(contents[i])) && (!isspace(contents[i])))
306 #endif /* DEAD_WOOD */
309 // Map the name (which we got from the classing engine) to a
314 Attachment::name_to_type()
316 char *subtype = new char[128];
319 // Hardcode ce_name to be text for now.
320 // It should actually be determined dynamically from the type of
325 // If the type and subtype are already set then we don't need to
326 // map a classing engine type to a MIME type; We already have
327 // the MIME type, so just return
330 if(equal(_ce_name, "text")) { // text
332 _subtype = strdup("plain");
333 } else if(equal(_ce_name, "richtext")) { // richtext
335 sprintf(subtype, "X-sun-%s",_ce_name);
336 _subtype = strdup(subtype);
337 } else if(equal(_ce_name, "audio-file")) { // audio-file
339 _subtype = strdup("basic");
340 } else if(equal(_ce_name, "default")) { // default
341 _type = TYPEAPPLICATION;
342 sprintf(subtype, "X-sun-%s",_ce_name);
343 _subtype = strdup(subtype);
344 } else if(equal(_ce_name, "oda")) { // oda
345 _type = TYPEAPPLICATION;
346 _subtype = strdup("oda");
347 } else if(equal(_ce_name, "postscript-file")) { // postscript
348 _type = TYPEAPPLICATION;
349 _subtype = strdup("PostScript");
350 } else if(equal(_ce_name, "sun-raster")) { // sun-raster
352 sprintf(subtype, "X-%s",_ce_name);
353 _subtype = strdup(subtype);
354 } else if(equal(_ce_name, "jpeg-file")) { // jpeg-file
356 _subtype = strdup("jpeg");
357 } else if(equal(_ce_name, "g3-file")) { // g3-file
359 sprintf(subtype, "X-sun-%s",_ce_name);
360 _subtype = strdup(subtype);
361 } else if(equal(_ce_name, "gif-file")) { // gif-file
363 _subtype = strdup("gif");
364 } else if(equal(_ce_name, "pbm-file")) { // pbm-file
366 sprintf(subtype, "X-sun-%s",_ce_name);
367 _subtype = strdup(subtype);
368 } else if(equal(_ce_name, "pgm-file")) { // pgm-file
370 sprintf(subtype, "X-sun-%s",_ce_name);
371 _subtype = strdup(subtype);
372 } else if(equal(_ce_name, "ppm-file")) { // ppm-file
374 sprintf(subtype, "X-sun-%s",_ce_name);
375 _subtype = strdup(subtype);
376 } else if(equal(_ce_name, "xpm-file")) { // xpm-file
378 sprintf(subtype, "X-sun-%s",_ce_name);
379 _subtype = strdup(subtype);
380 } else if(equal(_ce_name, "tiff-file")) { // tiff-file
382 sprintf(subtype, "X-sun-%s",_ce_name);
383 _subtype = strdup(subtype);
384 } else if(equal(_ce_name, "troff")) { // troff
386 sprintf(subtype, "X-sun-%s",_ce_name);
387 _subtype = strdup(subtype);
388 } else if(equal(_ce_name, "nroff")) { // nroff
390 sprintf(subtype, "X-sun-%s",_ce_name);
391 _subtype = strdup(subtype);
392 } else if(equal(_ce_name, "h-file")) { // h-file
394 sprintf(subtype, "X-sun-%s",_ce_name);
395 _subtype = strdup(subtype);
396 } else if(equal(_ce_name, "c-file")) { // c-file
398 sprintf(subtype, "X-sun-%s",_ce_name);
399 _subtype = strdup(subtype);
400 } else if(equal(_ce_name, "makefile")) { // makefile
402 sprintf(subtype, "X-sun-%s",_ce_name);
403 _subtype = strdup(subtype);
404 } else if(equal(_ce_name, "mail-file")) { // mail-file
406 sprintf(subtype, "X-sun-%s",_ce_name);
407 _subtype = strdup(subtype);
408 } else if(equal(_ce_name, "mail-message")) { // mail-message
410 sprintf(subtype, "X-sun-%s",_ce_name);
411 _subtype = strdup(subtype);
413 _type = TYPEAPPLICATION;
414 sprintf(subtype, "X-sun-%s",_ce_name);
415 _subtype = strdup(subtype);
421 Attachment::invokeAction(int index)
423 char *actionCommand = NULL;
424 DtActionArg *actionArg = NULL;
425 DtActionBuffer bufArg;
430 if (_myActionsList == NULL || NULL == _myActionsList[index]) return;
433 actionCommand = _myActionsList[index];
434 memset(&bufArg, 0, sizeof(bufArg));
436 bufArg.bp = (void *)_myContents;
437 bufArg.size = (int) _myContentsSize;
439 // Determine the type based on the contents.
440 // This is to compensate for errors that other MUAs could have
441 // generated: some claim a bodyPart is rfc822 but deliver something else.
442 type = bufArg.type = DtDtsBufferToDataType(
444 (const int) _myContentsSize,
447 if (_parent->isOwnerShellEditable())
448 bufArg.writable = TRUE;
450 bufArg.writable = FALSE;
452 // If this is the default action (aka Run) and the attachment is executable,
453 // display a dialog informing the user of the risks of executing it.
454 exble = DtDtsDataTypeToAttributeValue(type, DtDTS_DA_IS_EXECUTABLE, _name);
455 if (0 == index && NULL != exble && DtDtsIsTrue(exble))
458 char *buf = new char[2048];
461 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."));
463 answer = parent()->handleQuestionDialog(
464 GETMSG(DT_catd, 1, 86, "Mailer"),
466 DTMAILHELPEXECUTEOK);
468 if (answer == 2) return;
472 actionArg = (DtActionArg *) malloc(sizeof(DtActionArg) * 1);
473 memset(actionArg, 0, sizeof(DtActionArg));
474 actionArg->argClass = 2;
475 actionArg->u.buffer = bufArg;
477 ActionCallback *acb = new ActionCallback(_key, this);
479 _parent->ownerShellWidget(),
480 actionCommand, actionArg,
481 1, NULL, NULL, NULL, 1,
482 (DtActionCallbackProc)& Attachment::actionCallback, acb);
486 Attachment::handleDoubleClick()
488 _parent->attachmentFeedback(TRUE);
490 _parent->attachmentFeedback(FALSE);
493 static void okcb( XtPointer )
496 // This function exists so that the OK button will appear on the
497 // Info Dialog. It doesn't have to do anything because the dialog
498 // automatically pops down. It is for information only.
503 runit_callback(int *data)
509 norunit_callback(int *data)
513 #endif /* DEAD_WOOD */
516 Attachment::operator==
525 Attachment::set_selected()
527 char *actions_list = NULL; //Comma separated list of actions
533 parent()->attachmentSelected(this);
536 // Assuming that only 10 actions are possible.
537 // Need a mechanism to query, determine how many possible and
538 // allocate memory for that many.
540 _myActionsList = new char*[10];
542 // Retrieve the actions list. Walk through the list and
543 // for each item in it, ask the parent to create a menu item
544 // in its parent's menubar.
546 actions_list = DtDtsDataTypeToAttributeValue(
548 DtDTS_DA_ACTION_LIST,
552 char **tmpActionCommand = _myActionsList;
554 if (actions_list != NULL)
555 anAction = strtok(actions_list, ",");
556 if (anAction == NULL) {
560 *tmpActionCommand = strdup(anAction);
562 while (*tmpActionCommand != NULL) {
564 // strtok() requires that calls other than the first have NULL as
570 anAction = strtok(NULL, ",");
571 if (anAction == NULL) {
572 *tmpActionCommand = NULL;
575 *tmpActionCommand = strdup(anAction);
578 parent()->addAttachmentActions(
583 free((void*) actions_list);
587 Attachment::unselect()
593 // Save the attachment to the specified file.
595 Attachment::saveToFile(DtMailEnv &, char *filename)
598 char *buf = new char[2048];
601 if (SafeAccess(filename, F_OK) == 0) {
603 sprintf(buf, GETMSG(DT_catd, 3, 42, "%s already exists. Replace?"),
605 helpId = DTMAILHELPALREADYEXISTS;
607 answer = parent()->handleQuestionDialog(GETMSG(DT_catd,
613 if (answer == 2) { // Pressed cancel
618 if (unlink(filename) < 0) {
619 sprintf(buf, GETMSG(DT_catd, 3, 43, "Unable to replace %s."), filename);
620 helpId = DTMAILHELPNOREPLACE;
621 answer = parent()->handleErrorDialog(GETMSG(DT_catd,
632 // if (_myContentsSize == 0) {// Oops! BE thinks attachment is of size 0.
633 // 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");
634 // answer = parent()->handleErrorDialog("BUG!", buf);
636 // // Call setContents again.
637 // // This will help us debug why the body part has bogus contents.
638 // this->setContents();
641 // Create or truncate, and then write the bits.
643 int fd = SafeOpen(filename, O_RDWR | O_CREAT | O_TRUNC, 0600);
645 sprintf(buf, GETMSG(DT_catd, 3, 44, "Unable to create %s."), filename);
646 helpId = DTMAILHELPNOCREATE;
647 answer = parent()->handleErrorDialog(GETMSG(DT_catd, 1, 87, "Mailer"),
654 if (SafeWrite(fd, _myContents, (unsigned int)_myContentsSize) < _myContentsSize) {
655 sprintf(buf, GETMSG(DT_catd, 3, 45, "Unable to create %s."),
657 helpId = DTMAILHELPNOCREATE;
658 answer = parent()->handleErrorDialog(GETMSG(DT_catd, 1, 88, "Mailer"),
669 // Stat the created file and see if it is of size 0.
670 // If it is, engage the user in a dialog and involve a dtmail engineer
671 // to attach a debugger to this process.
674 // SafeStat(filename, &sbuf);
676 // if (sbuf.st_size == 0) {
677 // 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");
678 // answer = parent()->handleErrorDialog("BUG!", buf);
694 was_managed = isManaged();
695 if (was_managed) unmanageIconWidget();
698 XtSetArg(args[n], XtNx, x); n++;
699 XtSetValues( _w, args,n);
701 if (was_managed) manageIconWidget();
715 was_managed = isManaged();
716 if (was_managed) unmanageIconWidget();
719 XtSetArg(args[n], XtNy, y); n++;
720 XtSetValues( _w, args,n);
722 if (was_managed) manageIconWidget();
733 #endif /* DEAD_WOOD */
737 Attachment::actionCallback(
738 DtActionInvocationID id,
739 XtPointer clientData,
740 DtActionArg *action_arg,
742 DtActionStatus status
745 ActionCallback *acb = (ActionCallback *) clientData;
746 if (theRoamApp.session()->session()->validObjectKey(
747 acb->_myKey) == DTM_FALSE) {
748 // Error out. Post an error?
752 acb->_myAttachment->action(id, action_arg, argCount, status);
758 DtActionInvocationID id,
759 DtActionArg *actionArg,
764 DtActionBuffer bufArg;
765 DtMailEnv mail_error;
767 char *buf = new char[2048];
768 const void * lclContents(NULL);
769 unsigned long lclContentsSize(0);
771 // Initialize the mail_error.
774 if (status == DtACTION_INVOKED) {
776 _parent->setPendingAction(TRUE);
778 else if (status == DtACTION_DONE) {
779 unregisterAction(id);
780 _parent->setPendingAction(FALSE);
782 // Check first if ownerShell is an SMD.
783 // Secondly, check if the SMD is still available. If the user had
784 // sent the message while this attachment was up, the SMD's reset()
785 // method would have set the attachments' _deleted flag to TRUE.
786 // So, check to see that the attachment is still valid before setting
789 // Note: actionArg can be NULL if there were no actions associated
790 // with the data type. Is this an Actions bug? Could be, but
791 // we check for it anyway.
793 if (actionArg != NULL && _parent->isOwnerShellEditable() && !_deleted) {
794 if (actionArg->argClass == DtACTION_BUFFER) {
795 bufArg = actionArg->u.buffer;
796 if (bufArg.writable) {
797 // Assume user edited launched attachment -- as
798 // optimization, we can compare buffers to see if
799 // content actually changed. For now, assume it changed.
800 // Make a copy of incoming buffer and set body part's
801 // contents, size. Let BE determine type.
802 // Reset private variables.
803 _body_part->setContents(
807 NULL, NULL, 0, NULL);
809 // if (mail_error.isSet()) {
813 assert(mail_error.isNotSet());
816 // CDExc17304. Note the following curiosity. The caller is considered
817 // the owner of the _myType argument but the called retains ownership
824 _body_part->getContents(
830 // if (mail_error.isSet()) {
833 assert(mail_error.isNotSet());
834 _setMyContents(lclContents, int(lclContentsSize));
836 // Free the buffer...
837 XtFree((char *)bufArg.bp);
841 // Read the file into a buffer and do the same stuff
845 DtActionFile fileArg = actionArg->u.file;
846 struct stat stat_buf;
848 if ( SafeStat ( fileArg.name, &stat_buf ) == -1 ) {
849 mail_error.setError(DTME_ObjectAccessFailed);
850 mail_error.logError(DTM_FALSE, "Mailer: Unable to process action, stat failed on file %s.\n", fileArg.name);
854 tmp_file = SafeOpen(fileArg.name, O_RDONLY);
855 char *tmp_buf = (char*) malloc((size_t) stat_buf.st_size);
856 SafeRead(tmp_file, (void *)tmp_buf, (size_t) stat_buf.st_size);
859 _body_part->setContents(mail_error,
862 NULL, NULL, 0, NULL);
864 assert(mail_error.isNotSet());
874 _body_part->getContents(mail_error,
880 assert(mail_error.isNotSet());
881 _setMyContents(lclContents, int(lclContentsSize));
885 else if (status == DtACTION_INVALID_ID) {
887 * Post a dialog explaining that the action was invalid
891 DT_catd, 3, 91, "Cannot execute invalid action."));
893 answer = parent()->handleErrorDialog(GETMSG(DT_catd, 1, 86, "Mailer"),
896 unregisterAction(id);
897 _parent->setPendingAction(FALSE);
899 else if (status == DtACTION_FAILED) {
902 * Post a dialog explaining that the action failed.
905 GETMSG(DT_catd, 3, 92, "Executing action failed!"));
907 answer = parent()->handleErrorDialog(GETMSG(DT_catd, 1, 86, "Mailer"),
910 unregisterAction(id);
911 _parent->setPendingAction(FALSE);
913 else if (status == DtACTION_STATUS_UPDATE) {
914 // Check if ownerShell is an SMD. Make sure the message has not
915 // been sent before attempting to update things.
917 if(actionArg != NULL && _parent->isOwnerShellEditable() && !_deleted) {
918 if (actionArg->argClass == DtACTION_BUFFER) {
919 bufArg = actionArg->u.buffer;
920 if (bufArg.writable) {
921 // Assume user edited launched attachment -- as
922 // optimization, we can compare buffers to see if
923 // content actually changed. For now, assume it changed.
924 // Make a copy of incoming buffer and set body part's
925 // contents, size. Let BE determine type.
926 // Reset private variables.
927 _body_part->setContents(
931 NULL, NULL, 0, NULL);
933 // if (mail_error.isSet()) {
937 assert(mail_error.isNotSet());
943 _body_part->getContents(
949 // if (mail_error.isSet()) {
953 assert(mail_error.isNotSet());
954 _setMyContents(lclContents, int(lclContentsSize));
957 XtFree((char *)bufArg.bp);
961 // Read the file into a buffer and do the same stuff
965 DtActionFile fileArg = actionArg->u.file;
966 struct stat stat_buf;
968 if ( SafeStat ( fileArg.name, &stat_buf ) == -1 ) {
969 mail_error.setError(DTME_ObjectAccessFailed);
970 mail_error.logError(DTM_FALSE, "Mailer: Unable to process action, stat failed on file %s.\n", fileArg.name);
974 tmp_file = SafeOpen(fileArg.name, O_RDONLY);
975 char *tmp_buf = (char*) malloc((size_t) stat_buf.st_size);
976 SafeRead(tmp_file, (void *)tmp_buf, (size_t) stat_buf.st_size);
979 _body_part->setContents(mail_error,
981 (int) stat_buf.st_size,
982 NULL, NULL, 0, NULL);
984 assert(mail_error.isNotSet());
991 _body_part->getContents(mail_error,
997 assert(mail_error.isNotSet());
998 _setMyContents(lclContents, int(lclContentsSize));
1005 else if (status == DtACTION_CANCELED) {
1006 unregisterAction(id);
1007 _parent->setPendingAction(FALSE);
1009 if (actionArg != NULL) {
1010 XtFree((char *)(actionArg->u.buffer.bp));
1017 Attachment::deleteIt()
1019 DtMailEnv mail_error;
1021 // Initialize the mail_error.
1027 // Need to remove the view from display
1029 // Get the BE to mark the bodyPart as deleted
1030 _body_part->setFlag(mail_error, DtMailBodyPartDeletePending);
1035 Attachment::undeleteIt()
1037 DtMailEnv mail_error;
1039 // Initialize the mail_error.
1045 _body_part->resetFlag(mail_error, DtMailBodyPartDeletePending);
1050 Attachment::registerAction(
1051 DtActionInvocationID id
1054 _canKillSelf = FALSE;
1055 _myActionIds.append(id);
1061 Attachment::unregisterAction(
1062 DtActionInvocationID id
1065 if (_myActionIds.length() == 0) {
1069 _myActionIds.remove(id);
1071 // See copious documentation above.
1080 _canKillSelf = TRUE;
1081 if (_myActionIds.length() == 0) {
1088 ActionCallback::ActionCallback(
1089 DtMailObjectKey key,
1094 _myAttachment = att;
1097 ActionCallback::~ActionCallback()
1104 Attachment::unmanageIconWidget(void)
1107 XtUnmanageChild(_w);
1111 Attachment::manageIconWidget(void)
1118 Attachment::setLabel(XmString str)
1122 _label = XmStringCopy(str);
1125 XtSetArg(args[n], XmNstring, _label); n++;
1126 //The Icon widget needs to be unmanaged first before involking XtSetValues
1127 // Otherwise, the parent of the Icon widget does not allow the icon widget
1128 // resize. The Icon widget will be remanaged after its dimensions (w and h)
1129 // are obtained by XtGetValues. This is a fix of the defect 176690.
1130 unmanageIconWidget();
1131 XtSetValues(_w, args, n);
1134 XtSetArg(args[n], XmNwidth, &_attachmentWidth); n++;
1135 XtSetArg(args[n], XmNheight, &_attachmentHeight); n++;
1136 XtGetValues(_w, args, n);
1141 Attachment::primitive_select()
1144 myIcon->primitiveSelect();
1154 DtMailEnv mail_error;
1158 name = (char *) _XmStringUngenerate(new_name, NULL,
1159 XmMULTIBYTE_TEXT, XmMULTIBYTE_TEXT);
1161 _body_part->setContents(
1166 this->setLabel(new_name);
1170 Attachment::setContents()
1172 DtMailEnv mail_error;
1173 const void * lclContents;
1174 unsigned long lclContentsSize;
1176 // Initialize the mail_error.
1183 _body_part->getContents(
1190 // BE has returned an error condition...
1192 // It would be nice to popup a dialog to let the user know that
1193 // dtmail has run into a problem that it can't resolve. Unfortunately,
1194 // the code for postFatalErrorDialog() has been ifdef'ed out. Perhaps
1195 // the error dialog can be enabled at some point in the future.
1197 // if (mail_error.isSet())
1198 // parent()->myRMW->postFatalErrorDialog(mail_error);
1199 assert ( mail_error.isNotSet() );
1200 _setMyContents(lclContents, int(lclContentsSize));
1202 _haveContents = TRUE;
1204 // If it is a rfc822 message, check if it has From stuffing.
1205 // From stuffing is ">From".
1206 // If it has, advance the pointer to step past the ">" character.
1208 if (_myType && !strcmp(_myType,"DTMAIL_FILE")) {
1210 // If it has a From header, return. The classing engine uses
1211 // that to determine the client that needs to be launched.
1214 0 == strncasecmp((char *)_myContents, "From", 4)) {
1218 // Message doesn't begin with From. It may have From stuffing --
1219 // ">From". Or it may have no From header at all. The MIME
1220 // specs are vague on what headers an Message/RFC822 body part
1221 // has to have. We need From to help the classing engine and
1222 // therefore, we will by force (or hack) make it have a From :-)
1225 0 == strncasecmp((char *)_myContents, ">From", 5)) {
1227 // Has From stuffing.
1229 char *ptr = (char *)_myContents;
1230 ptr++; // Step past the first char
1231 _myContents = (void *) ptr; // Reset contents
1237 // No "From" header.
1238 // Generate a new content string by prepending an
1239 // "From UNKNOWN" header.
1241 char *buffer = NULL;
1242 char *from_hdr = "From UNKNOWN";
1245 // Allocate a buffer for the new contents.
1246 // One for the '\0' and two for the extra newlines.
1247 size = strlen(from_hdr) + int(_myContentsSize) + 3;
1248 buffer = new char[size];
1250 // Look for the first occurance of a colon or a newline.
1252 for (sptr = (char*) _myContents;
1253 *sptr && *sptr != '\n' && *sptr != ':';
1256 // Copy in the default From header.
1257 // Add a second newline if there are no rfc822 message headers.
1258 // Assume that finding a colon prior to a newline indicates
1259 // an rfc822 message header.
1261 sprintf(buffer, "%s\n", from_hdr);
1263 sprintf(buffer, "%s\n\n", from_hdr);
1265 // Copy in the original contents.
1266 size = strlen(buffer);
1267 memcpy(&buffer[size], (char *) _myContents, (int) _myContentsSize);
1268 size += (int) _myContentsSize;
1269 buffer[size] = '\0';
1271 _setMyContents(buffer, size);
1278 Attachment::getContents()
1281 return ( (void *)_myContents );
1284 this->setContents();
1285 return ( (void *)_myContents );
1292 * Makes a real copy of the specified data to be used as the
1293 * attachments's data. Note that a substring of the existing value
1294 * can be passed in as an argument and the right thing will happen.
1297 Attachment::_setMyContents(const void * data, int size)
1299 char * new_contents;
1304 new_contents = new char [new_size + 1];
1305 memcpy(new_contents, data, new_size);
1306 new_contents[new_size] = '\0';
1310 new_contents = NULL;
1312 if (_myAllocContents != NULL) {
1313 delete [] _myAllocContents;
1315 _myAllocContents = new_contents;
1316 _myContents = new_contents;
1317 _myContentsSize = new_size;