1 /* $TOG: Attachment.C /main/16 1998/07/23 17:58:44 mgreess $
3 * (c) Copyright 1996 Digital Equipment Corporation.
4 * (c) Copyright 1996 Hewlett-Packard Company.
5 * (c) Copyright 1996 International Business Machines Corp.
6 * (c) Copyright 1993-1996 Sun Microsystems, Inc.
7 * (c) Copyright 1996 Novell, Inc.
8 * (c) Copyright 1996 FUJITSU LIMITED.
9 * (c) Copyright 1996 Hitachi.
14 * RESTRICTED CONFIDENTIAL INFORMATION:
16 * The information in this document is subject to special
17 * restrictions in a confidential disclosure agreement between
18 * HP, IBM, Sun, USL, SCO and Univel. Do not distribute this
19 * document outside HP, IBM, Sun, USL, SCO, or Univel without
20 * Sun's specific written approval. This document and all copies
21 * and derivative works thereof must be returned or destroyed at
27 #include <EUSCompat.h> // For strcasecmp()
30 #include <sys/types.h>
38 #include <sys/utsname.h>
44 #include <Xm/BulletinB.h>
45 #include <Xm/AtomMgr.h>
46 #include <Xm/DragDrop.h>
47 #include <Xm/Screen.h>
49 #include <Xm/PushBG.h>
50 #include <Xm/LabelG.h>
51 #include <X11/IntrinsicP.h>
52 #include <X11/Xatom.h>
54 #include "Attachment.h"
56 #include "RoamMenuWindow.h"
58 #include "InfoDialogManager.h"
59 #include "ViewMsgDialog.h"
60 #include "RoamMenuWindow.h"
62 #include "MailSession.hh"
64 #include <DtMail/DtMailError.hh>
65 #include <DtMail/IO.hh> // SafeAccess...
66 #include "MemUtils.hh"
67 #include "DtMailHelp.hh"
68 #include "str_utils.h"
72 extern XtPointer _XmStringUngenerate (
76 XmTextType output_type);
79 extern nl_catd DtMailMsgCat;
81 unsigned char validbits[] = {
82 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
83 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00,
84 0x00, 0xfc, 0x3f, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0x00, 0x1f, 0xf8, 0x00,
85 0x80, 0x07, 0xe0, 0x01, 0x80, 0x03, 0xc0, 0x01, 0xc0, 0x01, 0x80, 0x03,
86 0xc0, 0x01, 0x80, 0x03, 0xe0, 0x00, 0x00, 0x07, 0xe0, 0x80, 0x01, 0x07,
87 0xe0, 0xc0, 0x03, 0x07, 0xe0, 0xc0, 0x03, 0x07, 0xe0, 0x80, 0x01, 0x07,
88 0xe0, 0x00, 0x00, 0x07, 0xc0, 0x01, 0x80, 0x03, 0xc0, 0x01, 0x80, 0x03,
89 0x80, 0x03, 0xc0, 0x01, 0x80, 0x07, 0xe0, 0x01, 0x00, 0x1f, 0xf8, 0x00,
90 0x00, 0xfe, 0x7f, 0x00, 0x00, 0xfc, 0x3f, 0x00, 0x00, 0xf0, 0x0f, 0x00,
91 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
92 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
94 unsigned char invalidbits[] = {
95 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
96 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00,
97 0x00, 0xfc, 0x3f, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0x00, 0x1f, 0xf8, 0x00,
98 0x80, 0x0f, 0xe0, 0x01, 0x80, 0x1f, 0xc0, 0x01, 0xc0, 0x3f, 0x80, 0x03,
99 0xc0, 0x7d, 0x80, 0x03, 0xe0, 0xf8, 0x00, 0x07, 0xe0, 0xf0, 0x01, 0x07,
100 0xe0, 0xe0, 0x03, 0x07, 0xe0, 0xc0, 0x07, 0x07, 0xe0, 0x80, 0x0f, 0x07,
101 0xe0, 0x00, 0x1f, 0x07, 0xc0, 0x01, 0xbe, 0x03, 0xc0, 0x01, 0xfc, 0x03,
102 0x80, 0x03, 0xf8, 0x01, 0x80, 0x07, 0xf0, 0x01, 0x00, 0x1f, 0xf8, 0x00,
103 0x00, 0xfe, 0x7f, 0x00, 0x00, 0xfc, 0x3f, 0x00, 0x00, 0xf0, 0x0f, 0x00,
104 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
105 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
107 #define equal(a, b) (!strcasecmp(a,b))
112 void runit_callback( int *data );
113 void norunit_callback( int *data );
114 #endif /* DEAD_WOOD */
115 static void okcb(XtPointer);
121 * A note on this bug, several related bugs, design of C++ programs and
122 * general coding style and proficiency. This module, as well as most
123 * others in the dtmail application, violate many elements of good
124 * OO design. Poor compartmentalization, poor abstraction, ambiguous data
125 * ownership, ambiguous data model, lack of a clear Model/View/Controller
126 * structure are all examples of things going wrong or being done badly.
127 * In the case at hand, we have a much larger problem (inadequate design
128 * of mmap()'d file handling) causing numerous small bugs from a
129 * collaboration with these design problems. I will workaround the
130 * bug and the design flaw by moving data ownership into this Class thus
131 * adding stones to the Chinese Wall that separates this UI-like class
132 * from the model-like classes in RFC. However, it is in no way a
133 * real fix for the problems dtmail is experiencing.
136 Attachment::Attachment(
137 AttachArea *classparent,
139 DtMail::BodyPart *body_part,
145 _parent(classparent),
146 _body_part(body_part),
150 _myAllocContents(NULL),
153 _haveContents(FALSE),
158 if(strchr(name, '/') == NULL) // The name does not include a slash
159 _label = XmStringCreateLocalized(name);
160 else // The name does include a slash
161 _label = XmStringCreateLocalized(strrchr(name, '/')+1);
163 _key = theRoamApp.session()->session()->newObjectKey();
166 Attachment::~Attachment(
170 theRoamApp.session()->session()->removeObjectKey(_key);
173 XmStringFree (_label);
183 if (_myActionsList) {
184 delete []_myActionsList;
186 if (_myAllocContents) {
187 delete [] _myAllocContents;
189 _myAllocContents = NULL;
196 Attachment::setAttachArea(AttachArea *aa)
203 Attachment::initialize()
207 assert( _parent != NULL);
211 widgetparent = _parent->getClipWindow();
213 _foreground = _parent->owner()->textEditor()->get_text_foreground();
214 _background = _parent->owner()->textEditor()->get_text_background();
218 // We already have the name from the classing engine. Now map
219 // the name to the MIME type and subtype
222 myIcon = new Icon(this, _name, _label, _type, widgetparent, _index);
224 _w = myIcon->baseWidget();
235 sw = _parent->getSWWindow();
238 XtSetArg(args[n], XmNwidth, &_attachmentWidth); n++;
239 XtSetArg(args[n], XmNheight, &_attachmentHeight); n++;
240 XtGetValues(_w, args, n);
241 XtSetArg(args[0], XmNheight, &aaHeight); n++;
242 XtGetValues(sw, args, 1);
243 if( aaHeight < (_attachmentHeight+20) )
245 XtSetArg(args[0],XmNheight,(_attachmentHeight+20));
246 XtSetValues(sw, args, 1);
251 installDestroyHandler();
256 Attachment::check_if_binary(String contents, unsigned long size)
260 for(i=0;i<size;i++) {
261 if((!isprint(contents[i])) && (!isspace(contents[i])))
266 #endif /* DEAD_WOOD */
269 // Map the name (which we got from the classing engine) to a
274 Attachment::name_to_type()
276 char *subtype = new char[128];
279 // Hardcode ce_name to be text for now.
280 // It should actually be determined dynamically from the type of
285 // If the type and subtype are already set then we don't need to
286 // map a classing engine type to a MIME type; We already have
287 // the MIME type, so just return
290 if(equal(_ce_name, "text")) { // text
292 _subtype = strdup("plain");
293 } else if(equal(_ce_name, "richtext")) { // richtext
295 sprintf(subtype, "X-sun-%s",_ce_name);
296 _subtype = strdup(subtype);
297 } else if(equal(_ce_name, "audio-file")) { // audio-file
299 _subtype = strdup("basic");
300 } else if(equal(_ce_name, "default")) { // default
301 _type = TYPEAPPLICATION;
302 sprintf(subtype, "X-sun-%s",_ce_name);
303 _subtype = strdup(subtype);
304 } else if(equal(_ce_name, "oda")) { // oda
305 _type = TYPEAPPLICATION;
306 _subtype = strdup("oda");
307 } else if(equal(_ce_name, "postscript-file")) { // postscript
308 _type = TYPEAPPLICATION;
309 _subtype = strdup("PostScript");
310 } else if(equal(_ce_name, "sun-raster")) { // sun-raster
312 sprintf(subtype, "X-%s",_ce_name);
313 _subtype = strdup(subtype);
314 } else if(equal(_ce_name, "jpeg-file")) { // jpeg-file
316 _subtype = strdup("jpeg");
317 } else if(equal(_ce_name, "g3-file")) { // g3-file
319 sprintf(subtype, "X-sun-%s",_ce_name);
320 _subtype = strdup(subtype);
321 } else if(equal(_ce_name, "gif-file")) { // gif-file
323 _subtype = strdup("gif");
324 } else if(equal(_ce_name, "pbm-file")) { // pbm-file
326 sprintf(subtype, "X-sun-%s",_ce_name);
327 _subtype = strdup(subtype);
328 } else if(equal(_ce_name, "pgm-file")) { // pgm-file
330 sprintf(subtype, "X-sun-%s",_ce_name);
331 _subtype = strdup(subtype);
332 } else if(equal(_ce_name, "ppm-file")) { // ppm-file
334 sprintf(subtype, "X-sun-%s",_ce_name);
335 _subtype = strdup(subtype);
336 } else if(equal(_ce_name, "xpm-file")) { // xpm-file
338 sprintf(subtype, "X-sun-%s",_ce_name);
339 _subtype = strdup(subtype);
340 } else if(equal(_ce_name, "tiff-file")) { // tiff-file
342 sprintf(subtype, "X-sun-%s",_ce_name);
343 _subtype = strdup(subtype);
344 } else if(equal(_ce_name, "troff")) { // troff
346 sprintf(subtype, "X-sun-%s",_ce_name);
347 _subtype = strdup(subtype);
348 } else if(equal(_ce_name, "nroff")) { // nroff
350 sprintf(subtype, "X-sun-%s",_ce_name);
351 _subtype = strdup(subtype);
352 } else if(equal(_ce_name, "h-file")) { // h-file
354 sprintf(subtype, "X-sun-%s",_ce_name);
355 _subtype = strdup(subtype);
356 } else if(equal(_ce_name, "c-file")) { // c-file
358 sprintf(subtype, "X-sun-%s",_ce_name);
359 _subtype = strdup(subtype);
360 } else if(equal(_ce_name, "makefile")) { // makefile
362 sprintf(subtype, "X-sun-%s",_ce_name);
363 _subtype = strdup(subtype);
364 } else if(equal(_ce_name, "mail-file")) { // mail-file
366 sprintf(subtype, "X-sun-%s",_ce_name);
367 _subtype = strdup(subtype);
368 } else if(equal(_ce_name, "mail-message")) { // mail-message
370 sprintf(subtype, "X-sun-%s",_ce_name);
371 _subtype = strdup(subtype);
373 _type = TYPEAPPLICATION;
374 sprintf(subtype, "X-sun-%s",_ce_name);
375 _subtype = strdup(subtype);
381 Attachment::invokeAction(int index)
383 char *actionCommand = NULL;
384 DtActionArg *actionArg = NULL;
385 DtActionBuffer bufArg;
390 if (_myActionsList == NULL || NULL == _myActionsList[index]) return;
393 actionCommand = _myActionsList[index];
394 memset(&bufArg, 0, sizeof(bufArg));
396 bufArg.bp = (void *)_myContents;
397 bufArg.size = (int) _myContentsSize;
399 // Determine the type based on the contents.
400 // This is to compensate for errors that other MUAs could have
401 // generated: some claim a bodyPart is rfc822 but deliver something else.
402 type = bufArg.type = DtDtsBufferToDataType(
404 (const int) _myContentsSize,
407 if (_parent->isOwnerShellEditable())
408 bufArg.writable = TRUE;
410 bufArg.writable = FALSE;
412 // If this is the default action (aka Run) and the attachment is executable,
413 // display a dialog informing the user of the risks of executing it.
414 exble = DtDtsDataTypeToAttributeValue(type, DtDTS_DA_IS_EXECUTABLE, _name);
415 if (0 == index && NULL != exble && DtDtsIsTrue(exble))
418 char *buf = new char[2048];
421 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."));
423 answer = parent()->handleQuestionDialog(
424 GETMSG(DT_catd, 1, 86, "Mailer"),
426 DTMAILHELPEXECUTEOK);
428 if (answer == 2) return;
432 actionArg = (DtActionArg *) malloc(sizeof(DtActionArg) * 1);
433 memset(actionArg, 0, sizeof(DtActionArg));
434 actionArg->argClass = 2;
435 actionArg->u.buffer = bufArg;
437 ActionCallback *acb = new ActionCallback(_key, this);
439 _parent->ownerShellWidget(),
440 actionCommand, actionArg,
441 1, NULL, NULL, NULL, 1,
442 (DtActionCallbackProc)& Attachment::actionCallback, acb);
446 Attachment::handleDoubleClick()
448 _parent->attachmentFeedback(TRUE);
450 _parent->attachmentFeedback(FALSE);
453 static void okcb( XtPointer )
456 // This function exists so that the OK button will appear on the
457 // Info Dialog. It doesn't have to do anything because the dialog
458 // automatically pops down. It is for information only.
463 runit_callback(int *data)
469 norunit_callback(int *data)
473 #endif /* DEAD_WOOD */
476 Attachment::operator==
485 Attachment::set_selected()
487 char *actions_list = NULL; //Comma separated list of actions
493 parent()->attachmentSelected(this);
496 // Assuming that only 10 actions are possible.
497 // Need a mechanism to query, determine how many possible and
498 // allocate memory for that many.
500 _myActionsList = new char*[10];
502 // Retrieve the actions list. Walk through the list and
503 // for each item in it, ask the parent to create a menu item
504 // in its parent's menubar.
506 actions_list = DtDtsDataTypeToAttributeValue(
508 DtDTS_DA_ACTION_LIST,
512 char **tmpActionCommand = _myActionsList;
514 if (actions_list != NULL)
515 anAction = strtok(actions_list, ",");
516 if (anAction == NULL) {
520 *tmpActionCommand = strdup(anAction);
522 while (*tmpActionCommand != NULL) {
524 // strtok() requires that calls other than the first have NULL as
530 anAction = strtok(NULL, ",");
531 if (anAction == NULL) {
532 *tmpActionCommand = NULL;
535 *tmpActionCommand = strdup(anAction);
538 parent()->addAttachmentActions(
543 free((void*) actions_list);
547 Attachment::unselect()
553 // Save the attachment to the specified file.
555 Attachment::saveToFile(DtMailEnv &, char *filename)
558 char *buf = new char[2048];
561 if (SafeAccess(filename, F_OK) == 0) {
563 sprintf(buf, GETMSG(DT_catd, 3, 42, "%s already exists. Replace?"),
565 helpId = DTMAILHELPALREADYEXISTS;
567 answer = parent()->handleQuestionDialog(GETMSG(DT_catd,
573 if (answer == 2) { // Pressed cancel
578 if (unlink(filename) < 0) {
579 sprintf(buf, GETMSG(DT_catd, 3, 43, "Unable to replace %s."), filename);
580 helpId = DTMAILHELPNOREPLACE;
581 answer = parent()->handleErrorDialog(GETMSG(DT_catd,
592 // if (_myContentsSize == 0) {// Oops! BE thinks attachment is of size 0.
593 // 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");
594 // answer = parent()->handleErrorDialog("BUG!", buf);
596 // // Call setContents again.
597 // // This will help us debug why the body part has bogus contents.
598 // this->setContents();
601 // Create or truncate, and then write the bits.
603 int fd = SafeOpen(filename, O_RDWR | O_CREAT | O_TRUNC, 0600);
605 sprintf(buf, GETMSG(DT_catd, 3, 44, "Unable to create %s."), filename);
606 helpId = DTMAILHELPNOCREATE;
607 answer = parent()->handleErrorDialog(GETMSG(DT_catd, 1, 87, "Mailer"),
614 if (SafeWrite(fd, _myContents, (unsigned int)_myContentsSize) < _myContentsSize) {
615 sprintf(buf, GETMSG(DT_catd, 3, 45, "Unable to create %s."),
617 helpId = DTMAILHELPNOCREATE;
618 answer = parent()->handleErrorDialog(GETMSG(DT_catd, 1, 88, "Mailer"),
629 // Stat the created file and see if it is of size 0.
630 // If it is, engage the user in a dialog and involve a dtmail engineer
631 // to attach a debugger to this process.
634 // SafeStat(filename, &sbuf);
636 // if (sbuf.st_size == 0) {
637 // 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");
638 // answer = parent()->handleErrorDialog("BUG!", buf);
654 was_managed = isManaged();
655 if (was_managed) unmanageIconWidget();
658 XtSetArg(args[n], XtNx, x); n++;
659 XtSetValues( _w, args,n);
661 if (was_managed) manageIconWidget();
675 was_managed = isManaged();
676 if (was_managed) unmanageIconWidget();
679 XtSetArg(args[n], XtNy, y); n++;
680 XtSetValues( _w, args,n);
682 if (was_managed) manageIconWidget();
693 #endif /* DEAD_WOOD */
697 Attachment::actionCallback(
698 DtActionInvocationID id,
699 XtPointer clientData,
700 DtActionArg *action_arg,
702 DtActionStatus status
705 ActionCallback *acb = (ActionCallback *) clientData;
706 if (theRoamApp.session()->session()->validObjectKey(
707 acb->_myKey) == DTM_FALSE) {
708 // Error out. Post an error?
712 acb->_myAttachment->action(id, action_arg, argCount, status);
718 DtActionInvocationID id,
719 DtActionArg *actionArg,
724 DtActionBuffer bufArg;
725 DtMailEnv mail_error;
727 char *buf = new char[2048];
728 const void * lclContents(NULL);
729 unsigned long lclContentsSize(0);
731 // Initialize the mail_error.
734 if (status == DtACTION_INVOKED) {
736 _parent->setPendingAction(TRUE);
738 else if (status == DtACTION_DONE) {
739 unregisterAction(id);
740 _parent->setPendingAction(FALSE);
742 // Check first if ownerShell is an SMD.
743 // Secondly, check if the SMD is still available. If the user had
744 // sent the message while this attachment was up, the SMD's reset()
745 // method would have set the attachments' _deleted flag to TRUE.
746 // So, check to see that the attachment is still valid before setting
749 // Note: actionArg can be NULL if there were no actions associated
750 // with the data type. Is this an Actions bug? Could be, but
751 // we check for it anyway.
753 if (actionArg != NULL && _parent->isOwnerShellEditable() && !_deleted) {
754 if (actionArg->argClass == DtACTION_BUFFER) {
755 bufArg = actionArg->u.buffer;
756 if (bufArg.writable) {
757 // Assume user edited launched attachment -- as
758 // optimization, we can compare buffers to see if
759 // content actually changed. For now, assume it changed.
760 // Make a copy of incoming buffer and set body part's
761 // contents, size. Let BE determine type.
762 // Reset private variables.
763 _body_part->setContents(
767 NULL, NULL, 0, NULL);
769 // if (mail_error.isSet()) {
773 assert(mail_error.isNotSet());
776 // CDExc17304. Note the following curiosity. The caller is considered
777 // the owner of the _myType argument but the called retains ownership
784 _body_part->getContents(
790 // if (mail_error.isSet()) {
793 assert(mail_error.isNotSet());
794 _setMyContents(lclContents, int(lclContentsSize));
796 // Free the buffer...
797 XtFree((char *)bufArg.bp);
801 // Read the file into a buffer and do the same stuff
805 DtActionFile fileArg = actionArg->u.file;
806 struct stat stat_buf;
808 if ( SafeStat ( fileArg.name, &stat_buf ) == -1 ) {
809 mail_error.setError(DTME_ObjectAccessFailed);
810 mail_error.logError(DTM_FALSE, "Mailer: Unable to process action, stat failed on file %s.\n", fileArg.name);
814 tmp_file = SafeOpen(fileArg.name, O_RDONLY);
815 char *tmp_buf = (char*) malloc((size_t) stat_buf.st_size);
816 SafeRead(tmp_file, (void *)tmp_buf, (size_t) stat_buf.st_size);
819 _body_part->setContents(mail_error,
822 NULL, NULL, 0, NULL);
824 assert(mail_error.isNotSet());
834 _body_part->getContents(mail_error,
840 assert(mail_error.isNotSet());
841 _setMyContents(lclContents, int(lclContentsSize));
845 else if (status == DtACTION_INVALID_ID) {
847 * Post a dialog explaining that the action was invalid
851 DT_catd, 3, 91, "Cannot execute invalid action."));
853 answer = parent()->handleErrorDialog(GETMSG(DT_catd, 1, 86, "Mailer"),
856 unregisterAction(id);
857 _parent->setPendingAction(FALSE);
859 else if (status == DtACTION_FAILED) {
862 * Post a dialog explaining that the action failed.
865 GETMSG(DT_catd, 3, 92, "Executing action failed!"));
867 answer = parent()->handleErrorDialog(GETMSG(DT_catd, 1, 86, "Mailer"),
870 unregisterAction(id);
871 _parent->setPendingAction(FALSE);
873 else if (status == DtACTION_STATUS_UPDATE) {
874 // Check if ownerShell is an SMD. Make sure the message has not
875 // been sent before attempting to update things.
877 if(actionArg != NULL && _parent->isOwnerShellEditable() && !_deleted) {
878 if (actionArg->argClass == DtACTION_BUFFER) {
879 bufArg = actionArg->u.buffer;
880 if (bufArg.writable) {
881 // Assume user edited launched attachment -- as
882 // optimization, we can compare buffers to see if
883 // content actually changed. For now, assume it changed.
884 // Make a copy of incoming buffer and set body part's
885 // contents, size. Let BE determine type.
886 // Reset private variables.
887 _body_part->setContents(
891 NULL, NULL, 0, NULL);
893 // if (mail_error.isSet()) {
897 assert(mail_error.isNotSet());
903 _body_part->getContents(
909 // if (mail_error.isSet()) {
913 assert(mail_error.isNotSet());
914 _setMyContents(lclContents, int(lclContentsSize));
917 XtFree((char *)bufArg.bp);
921 // Read the file into a buffer and do the same stuff
925 DtActionFile fileArg = actionArg->u.file;
926 struct stat stat_buf;
928 if ( SafeStat ( fileArg.name, &stat_buf ) == -1 ) {
929 mail_error.setError(DTME_ObjectAccessFailed);
930 mail_error.logError(DTM_FALSE, "Mailer: Unable to process action, stat failed on file %s.\n", fileArg.name);
934 tmp_file = SafeOpen(fileArg.name, O_RDONLY);
935 char *tmp_buf = (char*) malloc((size_t) stat_buf.st_size);
936 SafeRead(tmp_file, (void *)tmp_buf, (size_t) stat_buf.st_size);
939 _body_part->setContents(mail_error,
941 (int) stat_buf.st_size,
942 NULL, NULL, 0, NULL);
944 assert(mail_error.isNotSet());
951 _body_part->getContents(mail_error,
957 assert(mail_error.isNotSet());
958 _setMyContents(lclContents, int(lclContentsSize));
965 else if (status == DtACTION_CANCELED) {
966 unregisterAction(id);
967 _parent->setPendingAction(FALSE);
969 if (actionArg != NULL) {
970 XtFree((char *)(actionArg->u.buffer.bp));
977 Attachment::deleteIt()
979 DtMailEnv mail_error;
981 // Initialize the mail_error.
987 // Need to remove the view from display
989 // Get the BE to mark the bodyPart as deleted
990 _body_part->setFlag(mail_error, DtMailBodyPartDeletePending);
995 Attachment::undeleteIt()
997 DtMailEnv mail_error;
999 // Initialize the mail_error.
1005 _body_part->resetFlag(mail_error, DtMailBodyPartDeletePending);
1010 Attachment::registerAction(
1011 DtActionInvocationID id
1014 _canKillSelf = FALSE;
1015 _myActionIds.append(id);
1021 Attachment::unregisterAction(
1022 DtActionInvocationID id
1025 if (_myActionIds.length() == 0) {
1029 _myActionIds.remove(id);
1031 // See copious documentation above.
1040 _canKillSelf = TRUE;
1041 if (_myActionIds.length() == 0) {
1048 ActionCallback::ActionCallback(
1049 DtMailObjectKey key,
1054 _myAttachment = att;
1057 ActionCallback::~ActionCallback()
1064 Attachment::unmanageIconWidget(void)
1067 XtUnmanageChild(_w);
1071 Attachment::manageIconWidget(void)
1078 Attachment::setLabel(XmString str)
1082 _label = XmStringCopy(str);
1085 XtSetArg(args[n], XmNstring, _label); n++;
1086 //The Icon widget needs to be unmanaged first before involking XtSetValues
1087 // Otherwise, the parent of the Icon widget does not allow the icon widget
1088 // resize. The Icon widget will be remanaged after its dimensions (w and h)
1089 // are obtained by XtGetValues. This is a fix of the defect 176690.
1090 unmanageIconWidget();
1091 XtSetValues(_w, args, n);
1094 XtSetArg(args[n], XmNwidth, &_attachmentWidth); n++;
1095 XtSetArg(args[n], XmNheight, &_attachmentHeight); n++;
1096 XtGetValues(_w, args, n);
1101 Attachment::primitive_select()
1104 myIcon->primitiveSelect();
1114 DtMailEnv mail_error;
1118 name = (char *) _XmStringUngenerate(new_name, NULL,
1119 XmMULTIBYTE_TEXT, XmMULTIBYTE_TEXT);
1121 _body_part->setContents(
1126 this->setLabel(new_name);
1130 Attachment::setContents()
1132 DtMailEnv mail_error;
1133 const void * lclContents;
1134 unsigned long lclContentsSize;
1136 // Initialize the mail_error.
1143 _body_part->getContents(
1150 // BE has returned an error condition...
1152 // It would be nice to popup a dialog to let the user know that
1153 // dtmail has run into a problem that it can't resolve. Unfortunately,
1154 // the code for postFatalErrorDialog() has been ifdef'ed out. Perhaps
1155 // the error dialog can be enabled at some point in the future.
1157 // if (mail_error.isSet())
1158 // parent()->myRMW->postFatalErrorDialog(mail_error);
1159 assert ( mail_error.isNotSet() );
1160 _setMyContents(lclContents, int(lclContentsSize));
1162 _haveContents = TRUE;
1164 // If it is a rfc822 message, check if it has From stuffing.
1165 // From stuffing is ">From".
1166 // If it has, advance the pointer to step past the ">" character.
1168 if (_myType && !strcmp(_myType,"DTMAIL_FILE")) {
1170 // If it has a From header, return. The classing engine uses
1171 // that to determine the client that needs to be launched.
1174 0 == strncasecmp((char *)_myContents, "From", 4)) {
1178 // Message doesn't begin with From. It may have From stuffing --
1179 // ">From". Or it may have no From header at all. The MIME
1180 // specs are vague on what headers an Message/RFC822 body part
1181 // has to have. We need From to help the classing engine and
1182 // therefore, we will by force (or hack) make it have a From :-)
1185 0 == strncasecmp((char *)_myContents, ">From", 5)) {
1187 // Has From stuffing.
1189 char *ptr = (char *)_myContents;
1190 ptr++; // Step past the first char
1191 _myContents = (void *) ptr; // Reset contents
1197 // No "From" header.
1198 // Generate a new content string by prepending an
1199 // "From UNKNOWN" header.
1201 char *buffer = NULL;
1202 char *from_hdr = "From UNKNOWN";
1205 // Allocate a buffer for the new contents.
1206 // One for the '\0' and two for the extra newlines.
1207 size = strlen(from_hdr) + int(_myContentsSize) + 3;
1208 buffer = new char[size];
1210 // Look for the first occurance of a colon or a newline.
1212 for (sptr = (char*) _myContents;
1213 *sptr && *sptr != '\n' && *sptr != ':';
1216 // Copy in the default From header.
1217 // Add a second newline if there are no rfc822 message headers.
1218 // Assume that finding a colon prior to a newline indicates
1219 // an rfc822 message header.
1221 sprintf(buffer, "%s\n", from_hdr);
1223 sprintf(buffer, "%s\n\n", from_hdr);
1225 // Copy in the original contents.
1226 size = strlen(buffer);
1227 memcpy(&buffer[size], (char *) _myContents, (int) _myContentsSize);
1228 size += (int) _myContentsSize;
1229 buffer[size] = '\0';
1231 _setMyContents(buffer, size);
1238 Attachment::getContents()
1241 return ( (void *)_myContents );
1244 this->setContents();
1245 return ( (void *)_myContents );
1252 * Makes a real copy of the specified data to be used as the
1253 * attachments's data. Note that a substring of the existing value
1254 * can be passed in as an argument and the right thing will happen.
1257 Attachment::_setMyContents(const void * data, int size)
1259 char * new_contents;
1264 new_contents = new char [new_size + 1];
1265 memcpy(new_contents, data, new_size);
1266 new_contents[new_size] = '\0';
1270 new_contents = NULL;
1272 if (_myAllocContents != NULL) {
1273 delete [] _myAllocContents;
1275 _myAllocContents = new_contents;
1276 _myContents = new_contents;
1277 _myContentsSize = new_size;