Attachment.C 33 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319
  1. /*
  2. * CDE - Common Desktop Environment
  3. *
  4. * Copyright (c) 1993-2012, The Open Group. All rights reserved.
  5. *
  6. * These libraries and programs are free software; you can
  7. * redistribute them and/or modify them under the terms of the GNU
  8. * Lesser General Public License as published by the Free Software
  9. * Foundation; either version 2 of the License, or (at your option)
  10. * any later version.
  11. *
  12. * These libraries and programs are distributed in the hope that
  13. * they will be useful, but WITHOUT ANY WARRANTY; without even the
  14. * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  15. * PURPOSE. See the GNU Lesser General Public License for more
  16. * details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public
  19. * License along with these libraries and programs; if not, write
  20. * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
  21. * Floor, Boston, MA 02110-1301 USA
  22. */
  23. /* $TOG: Attachment.C /main/16 1998/07/23 17:58:44 mgreess $
  24. *
  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.
  32. */
  33. /*
  34. *+SNOTICE
  35. *
  36. * RESTRICTED CONFIDENTIAL INFORMATION:
  37. *
  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
  44. * Sun's request.
  45. *
  46. *+ENOTICE
  47. */
  48. #include <EUSCompat.h> // For strcasecmp()
  49. #include <stdio.h>
  50. #include <unistd.h>
  51. #include <sys/types.h>
  52. #include <sys/stat.h>
  53. #include <stdlib.h>
  54. #include <fcntl.h>
  55. #include <string.h>
  56. #include <ctype.h>
  57. #include <memory.h>
  58. #include <errno.h>
  59. #include <sys/utsname.h>
  60. #include <stdio.h>
  61. #include <Xm/Xm.h>
  62. #include <Xm/Form.h>
  63. #include <Xm/Label.h>
  64. #include <Xm/BulletinB.h>
  65. #include <Xm/AtomMgr.h>
  66. #include <Xm/DragDrop.h>
  67. #include <Xm/Screen.h>
  68. #include <Xm/PushB.h>
  69. #include <Xm/PushBG.h>
  70. #include <Xm/LabelG.h>
  71. #include <X11/IntrinsicP.h>
  72. #include <X11/Xatom.h>
  73. #include "Attachment.h"
  74. #include "Icon.h"
  75. #include "RoamMenuWindow.h"
  76. #include "RoamApp.h"
  77. #include "InfoDialogManager.h"
  78. #include "ViewMsgDialog.h"
  79. #include "RoamMenuWindow.h"
  80. #include "MailMsg.h"
  81. #include "MailSession.hh"
  82. #include <Dt/Dts.h>
  83. #include <DtMail/DtMailError.hh>
  84. #include <DtMail/IO.hh> // SafeAccess...
  85. #include "MemUtils.hh"
  86. #include "DtMailHelp.hh"
  87. #include "str_utils.h"
  88. extern "C" {
  89. extern XtPointer _XmStringUngenerate (
  90. XmString string,
  91. XmStringTag tag,
  92. XmTextType tag_type,
  93. XmTextType output_type);
  94. }
  95. extern nl_catd DtMailMsgCat;
  96. unsigned char validbits[] = {
  97. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  98. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00,
  99. 0x00, 0xfc, 0x3f, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0x00, 0x1f, 0xf8, 0x00,
  100. 0x80, 0x07, 0xe0, 0x01, 0x80, 0x03, 0xc0, 0x01, 0xc0, 0x01, 0x80, 0x03,
  101. 0xc0, 0x01, 0x80, 0x03, 0xe0, 0x00, 0x00, 0x07, 0xe0, 0x80, 0x01, 0x07,
  102. 0xe0, 0xc0, 0x03, 0x07, 0xe0, 0xc0, 0x03, 0x07, 0xe0, 0x80, 0x01, 0x07,
  103. 0xe0, 0x00, 0x00, 0x07, 0xc0, 0x01, 0x80, 0x03, 0xc0, 0x01, 0x80, 0x03,
  104. 0x80, 0x03, 0xc0, 0x01, 0x80, 0x07, 0xe0, 0x01, 0x00, 0x1f, 0xf8, 0x00,
  105. 0x00, 0xfe, 0x7f, 0x00, 0x00, 0xfc, 0x3f, 0x00, 0x00, 0xf0, 0x0f, 0x00,
  106. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  107. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
  108. unsigned char invalidbits[] = {
  109. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  110. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00,
  111. 0x00, 0xfc, 0x3f, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0x00, 0x1f, 0xf8, 0x00,
  112. 0x80, 0x0f, 0xe0, 0x01, 0x80, 0x1f, 0xc0, 0x01, 0xc0, 0x3f, 0x80, 0x03,
  113. 0xc0, 0x7d, 0x80, 0x03, 0xe0, 0xf8, 0x00, 0x07, 0xe0, 0xf0, 0x01, 0x07,
  114. 0xe0, 0xe0, 0x03, 0x07, 0xe0, 0xc0, 0x07, 0x07, 0xe0, 0x80, 0x0f, 0x07,
  115. 0xe0, 0x00, 0x1f, 0x07, 0xc0, 0x01, 0xbe, 0x03, 0xc0, 0x01, 0xfc, 0x03,
  116. 0x80, 0x03, 0xf8, 0x01, 0x80, 0x07, 0xf0, 0x01, 0x00, 0x1f, 0xf8, 0x00,
  117. 0x00, 0xfe, 0x7f, 0x00, 0x00, 0xfc, 0x3f, 0x00, 0x00, 0xf0, 0x0f, 0x00,
  118. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  119. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
  120. #define equal(a, b) (!strcasecmp(a,b))
  121. String typeName;
  122. #ifdef DEAD_WOOD
  123. void runit_callback( int *data );
  124. void norunit_callback( int *data );
  125. #endif /* DEAD_WOOD */
  126. static void okcb(XtPointer);
  127. /*
  128. * CDExc17304
  129. *
  130. * A note on this bug, several related bugs, design of C++ programs and
  131. * general coding style and proficiency. This module, as well as most
  132. * others in the dtmail application, violate many elements of good
  133. * OO design. Poor compartmentalization, poor abstraction, ambiguous data
  134. * ownership, ambiguous data model, lack of a clear Model/View/Controller
  135. * structure are all examples of things going wrong or being done badly.
  136. * In the case at hand, we have a much larger problem (inadequate design
  137. * of mmap()'d file handling) causing numerous small bugs from a
  138. * collaboration with these design problems. I will workaround the
  139. * bug and the design flaw by moving data ownership into this Class thus
  140. * adding stones to the Chinese Wall that separates this UI-like class
  141. * from the model-like classes in RFC. However, it is in no way a
  142. * real fix for the problems dtmail is experiencing.
  143. */
  144. Attachment::Attachment(
  145. AttachArea *classparent,
  146. String name,
  147. DtMail::BodyPart *body_part,
  148. int indx
  149. )
  150. : UIComponent (
  151. name
  152. ),
  153. _parent(classparent),
  154. _body_part(body_part),
  155. _index(indx),
  156. _canKillSelf(TRUE),
  157. _myActionIds(5),
  158. _myAllocContents(NULL),
  159. _myContents(NULL),
  160. _myContentsSize(0),
  161. _haveContents(FALSE),
  162. _myType(NULL),
  163. _subtype(NULL),
  164. _myActionsList(NULL)
  165. {
  166. if(strchr(name, '/') == NULL) // The name does not include a slash
  167. _label = XmStringCreateLocalized(name);
  168. else // The name does include a slash
  169. _label = XmStringCreateLocalized(strrchr(name, '/')+1);
  170. _key = theRoamApp.session()->session()->newObjectKey();
  171. myIcon = NULL;
  172. _background = 0;
  173. _foreground = 0;
  174. _attachmentWidth = 0;
  175. _attachmentHeight = 0;
  176. _positionX = 0;
  177. _positionY = 0;
  178. _deleted = false;
  179. _selected = false;
  180. _row = 0;
  181. _saveAsFilename = NULL;
  182. _ce_name = NULL;
  183. _ce_type = NULL;
  184. _type = 0;
  185. _binary = false;
  186. _executable = false;
  187. }
  188. Attachment::~Attachment(
  189. )
  190. {
  191. theRoamApp.session()->session()->removeObjectKey(_key);
  192. if (_label) {
  193. XmStringFree (_label);
  194. }
  195. if (_subtype) {
  196. free (_subtype);
  197. }
  198. if (_myType) {
  199. free (_myType);
  200. }
  201. delete myIcon;
  202. if (_myActionsList) {
  203. delete []_myActionsList;
  204. }
  205. if (_myAllocContents) {
  206. delete [] _myAllocContents;
  207. }
  208. _myAllocContents = NULL;
  209. _myContents = NULL;
  210. _myContentsSize = 0;
  211. }
  212. void
  213. Attachment::setAttachArea(AttachArea *aa)
  214. {
  215. _parent = aa;
  216. }
  217. void
  218. Attachment::initialize()
  219. {
  220. Widget widgetparent;
  221. assert( _parent != NULL);
  222. this->setContents();
  223. widgetparent = _parent->getClipWindow();
  224. _foreground = _parent->owner()->textEditor()->get_text_foreground();
  225. _background = _parent->owner()->textEditor()->get_text_background();
  226. _selected = FALSE;
  227. // We already have the name from the classing engine. Now map
  228. // the name to the MIME type and subtype
  229. name_to_type();
  230. myIcon = new Icon(this, _name, _label, _type, widgetparent, _index);
  231. _w = myIcon->baseWidget();
  232. _deleted = FALSE;
  233. XmUpdateDisplay(_w);
  234. {
  235. Arg args[2];
  236. int n;
  237. Dimension aaHeight;
  238. Widget sw;
  239. sw = _parent->getSWWindow();
  240. n = 0;
  241. XtSetArg(args[n], XmNwidth, &_attachmentWidth); n++;
  242. XtSetArg(args[n], XmNheight, &_attachmentHeight); n++;
  243. XtGetValues(_w, args, n);
  244. XtSetArg(args[0], XmNheight, &aaHeight); n++;
  245. XtGetValues(sw, args, 1);
  246. if( aaHeight < (_attachmentHeight+20) )
  247. {
  248. XtSetArg(args[0],XmNheight,(_attachmentHeight+20));
  249. XtSetValues(sw, args, 1);
  250. }
  251. }
  252. installDestroyHandler();
  253. }
  254. #ifdef DEAD_WOOD
  255. Boolean
  256. Attachment::check_if_binary(String contents, unsigned long size)
  257. {
  258. int i;
  259. for(i=0;i<size;i++) {
  260. if((!isprint(contents[i])) && (!isspace(contents[i])))
  261. return True;
  262. }
  263. return False;
  264. }
  265. #endif /* DEAD_WOOD */
  266. //
  267. // Map the name (which we got from the classing engine) to a
  268. // type and subtype
  269. //
  270. void
  271. Attachment::name_to_type()
  272. {
  273. char *subtype = new char[128];
  274. // Hack hack!
  275. // Hardcode ce_name to be text for now.
  276. // It should actually be determined dynamically from the type of
  277. // the attachment.
  278. _ce_name = "text";
  279. // If the type and subtype are already set then we don't need to
  280. // map a classing engine type to a MIME type; We already have
  281. // the MIME type, so just return
  282. if(_subtype != NULL)
  283. return;
  284. if(equal(_ce_name, "text")) { // text
  285. _type = TYPETEXT;
  286. _subtype = strdup("plain");
  287. } else if(equal(_ce_name, "richtext")) { // richtext
  288. _type = TYPETEXT;
  289. sprintf(subtype, "X-sun-%s",_ce_name);
  290. _subtype = strdup(subtype);
  291. } else if(equal(_ce_name, "audio-file")) { // audio-file
  292. _type = TYPEAUDIO;
  293. _subtype = strdup("basic");
  294. } else if(equal(_ce_name, "default")) { // default
  295. _type = TYPEAPPLICATION;
  296. sprintf(subtype, "X-sun-%s",_ce_name);
  297. _subtype = strdup(subtype);
  298. } else if(equal(_ce_name, "oda")) { // oda
  299. _type = TYPEAPPLICATION;
  300. _subtype = strdup("oda");
  301. } else if(equal(_ce_name, "postscript-file")) { // postscript
  302. _type = TYPEAPPLICATION;
  303. _subtype = strdup("PostScript");
  304. } else if(equal(_ce_name, "sun-raster")) { // sun-raster
  305. _type = TYPEIMAGE;
  306. sprintf(subtype, "X-%s",_ce_name);
  307. _subtype = strdup(subtype);
  308. } else if(equal(_ce_name, "jpeg-file")) { // jpeg-file
  309. _type = TYPEIMAGE;
  310. _subtype = strdup("jpeg");
  311. } else if(equal(_ce_name, "g3-file")) { // g3-file
  312. _type = TYPEIMAGE;
  313. sprintf(subtype, "X-sun-%s",_ce_name);
  314. _subtype = strdup(subtype);
  315. } else if(equal(_ce_name, "gif-file")) { // gif-file
  316. _type = TYPEIMAGE;
  317. _subtype = strdup("gif");
  318. } else if(equal(_ce_name, "pbm-file")) { // pbm-file
  319. _type = TYPEIMAGE;
  320. sprintf(subtype, "X-sun-%s",_ce_name);
  321. _subtype = strdup(subtype);
  322. } else if(equal(_ce_name, "pgm-file")) { // pgm-file
  323. _type = TYPEIMAGE;
  324. sprintf(subtype, "X-sun-%s",_ce_name);
  325. _subtype = strdup(subtype);
  326. } else if(equal(_ce_name, "ppm-file")) { // ppm-file
  327. _type = TYPEIMAGE;
  328. sprintf(subtype, "X-sun-%s",_ce_name);
  329. _subtype = strdup(subtype);
  330. } else if(equal(_ce_name, "xpm-file")) { // xpm-file
  331. _type = TYPEIMAGE;
  332. sprintf(subtype, "X-sun-%s",_ce_name);
  333. _subtype = strdup(subtype);
  334. } else if(equal(_ce_name, "tiff-file")) { // tiff-file
  335. _type = TYPEIMAGE;
  336. sprintf(subtype, "X-sun-%s",_ce_name);
  337. _subtype = strdup(subtype);
  338. } else if(equal(_ce_name, "troff")) { // troff
  339. _type = TYPETEXT;
  340. sprintf(subtype, "X-sun-%s",_ce_name);
  341. _subtype = strdup(subtype);
  342. } else if(equal(_ce_name, "nroff")) { // nroff
  343. _type = TYPETEXT;
  344. sprintf(subtype, "X-sun-%s",_ce_name);
  345. _subtype = strdup(subtype);
  346. } else if(equal(_ce_name, "h-file")) { // h-file
  347. _type = TYPETEXT;
  348. sprintf(subtype, "X-sun-%s",_ce_name);
  349. _subtype = strdup(subtype);
  350. } else if(equal(_ce_name, "c-file")) { // c-file
  351. _type = TYPETEXT;
  352. sprintf(subtype, "X-sun-%s",_ce_name);
  353. _subtype = strdup(subtype);
  354. } else if(equal(_ce_name, "makefile")) { // makefile
  355. _type = TYPETEXT;
  356. sprintf(subtype, "X-sun-%s",_ce_name);
  357. _subtype = strdup(subtype);
  358. } else if(equal(_ce_name, "mail-file")) { // mail-file
  359. _type = TYPETEXT;
  360. sprintf(subtype, "X-sun-%s",_ce_name);
  361. _subtype = strdup(subtype);
  362. } else if(equal(_ce_name, "mail-message")) { // mail-message
  363. _type = TYPETEXT;
  364. sprintf(subtype, "X-sun-%s",_ce_name);
  365. _subtype = strdup(subtype);
  366. } else {
  367. _type = TYPEAPPLICATION;
  368. sprintf(subtype, "X-sun-%s",_ce_name);
  369. _subtype = strdup(subtype);
  370. }
  371. delete [] subtype;
  372. }
  373. void
  374. Attachment::invokeAction(int index)
  375. {
  376. char *actionCommand = NULL;
  377. DtActionArg *actionArg = NULL;
  378. DtActionBuffer bufArg;
  379. char *exble = NULL;
  380. char *type = NULL;
  381. if (_myActionsList == NULL || NULL == _myActionsList[index]) return;
  382. this->setContents();
  383. actionCommand = _myActionsList[index];
  384. memset(&bufArg, 0, sizeof(bufArg));
  385. bufArg.bp = (void *)_myContents;
  386. bufArg.size = (int) _myContentsSize;
  387. // Determine the type based on the contents.
  388. // This is to compensate for errors that other MUAs could have
  389. // generated: some claim a bodyPart is rfc822 but deliver something else.
  390. type = bufArg.type = DtDtsBufferToDataType(
  391. (char*) _myContents,
  392. (const int) _myContentsSize,
  393. _name);
  394. if (_parent->isOwnerShellEditable())
  395. bufArg.writable = TRUE;
  396. else
  397. bufArg.writable = FALSE;
  398. // If this is the default action (aka Run) and the attachment is executable,
  399. // display a dialog informing the user of the risks of executing it.
  400. exble = DtDtsDataTypeToAttributeValue(type, DtDTS_DA_IS_EXECUTABLE, _name);
  401. if (0 == index && NULL != exble && DtDtsIsTrue(exble))
  402. {
  403. int answer;
  404. char *buf = new char[2048];
  405. sprintf(buf, "%s",
  406. 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."));
  407. answer = parent()->handleQuestionDialog(
  408. GETMSG(DT_catd, 1, 86, "Mailer"),
  409. buf,
  410. DTMAILHELPEXECUTEOK);
  411. delete [] buf;
  412. if (answer == 2) return;
  413. }
  414. // Passing a buffer
  415. actionArg = (DtActionArg *) malloc(sizeof(DtActionArg) * 1);
  416. memset(actionArg, 0, sizeof(DtActionArg));
  417. actionArg->argClass = 2;
  418. actionArg->u.buffer = bufArg;
  419. ActionCallback *acb = new ActionCallback(_key, this);
  420. DtActionInvoke(
  421. _parent->ownerShellWidget(),
  422. actionCommand, actionArg,
  423. 1, NULL, NULL, NULL, 1,
  424. (DtActionCallbackProc)& Attachment::actionCallback, acb);
  425. }
  426. void
  427. Attachment::handleDoubleClick()
  428. {
  429. _parent->attachmentFeedback(TRUE);
  430. invokeAction(0);
  431. _parent->attachmentFeedback(FALSE);
  432. }
  433. static void okcb( XtPointer )
  434. {
  435. //Empty
  436. // This function exists so that the OK button will appear on the
  437. // Info Dialog. It doesn't have to do anything because the dialog
  438. // automatically pops down. It is for information only.
  439. }
  440. #ifdef DEAD_WOOD
  441. void
  442. runit_callback(int *data)
  443. {
  444. *data=1;
  445. }
  446. void
  447. norunit_callback(int *data)
  448. {
  449. *data=2;
  450. }
  451. #endif /* DEAD_WOOD */
  452. int
  453. Attachment::operator==
  454. (
  455. const Attachment &
  456. )
  457. {
  458. return 1;
  459. }
  460. void
  461. Attachment::set_selected()
  462. {
  463. char *actions_list = NULL; //Comma separated list of actions
  464. char* anAction=NULL;
  465. int numActions = 0;
  466. _selected = TRUE;
  467. parent()->attachmentSelected(this);
  468. // Crude Hack.
  469. // Assuming that only 10 actions are possible.
  470. // Need a mechanism to query, determine how many possible and
  471. // allocate memory for that many.
  472. _myActionsList = new char*[10];
  473. // Retrieve the actions list. Walk through the list and
  474. // for each item in it, ask the parent to create a menu item
  475. // in its parent's menubar.
  476. actions_list = DtDtsDataTypeToAttributeValue(
  477. _myType,
  478. DtDTS_DA_ACTION_LIST,
  479. NULL
  480. );
  481. char **tmpActionCommand = _myActionsList;
  482. if (actions_list != NULL)
  483. anAction = strtok(actions_list, ",");
  484. if (anAction == NULL) {
  485. return;
  486. }
  487. *tmpActionCommand = strdup(anAction);
  488. while (*tmpActionCommand != NULL) {
  489. // strtok() requires that calls other than the first have NULL as
  490. // the first arg..
  491. tmpActionCommand++;
  492. numActions++;
  493. anAction = strtok(NULL, ",");
  494. if (anAction == NULL) {
  495. *tmpActionCommand = NULL;
  496. }
  497. else {
  498. *tmpActionCommand = strdup(anAction);
  499. }
  500. }
  501. parent()->addAttachmentActions(
  502. _myActionsList,
  503. numActions
  504. );
  505. free((void*) actions_list);
  506. }
  507. void
  508. Attachment::unselect()
  509. {
  510. _selected = FALSE;
  511. myIcon->unselect();
  512. }
  513. // Save the attachment to the specified file.
  514. void
  515. Attachment::saveToFile(DtMailEnv &, char *filename)
  516. {
  517. int answer;
  518. char *buf = new char[2048];
  519. char *helpId = NULL;
  520. if (SafeAccess(filename, F_OK) == 0) {
  521. sprintf(buf, GETMSG(DT_catd, 3, 42, "%s already exists. Replace?"),
  522. filename);
  523. helpId = DTMAILHELPALREADYEXISTS;
  524. answer = parent()->handleQuestionDialog(GETMSG(DT_catd,
  525. 1, 85,
  526. "Mailer"),
  527. buf,
  528. helpId);
  529. if (answer == 2) { // Pressed cancel
  530. delete [] buf;
  531. return;
  532. }
  533. if (unlink(filename) < 0) {
  534. sprintf(buf, GETMSG(DT_catd, 3, 43, "Unable to replace %s."), filename);
  535. helpId = DTMAILHELPNOREPLACE;
  536. answer = parent()->handleErrorDialog(GETMSG(DT_catd,
  537. 1, 86,
  538. "Mailer"),
  539. buf,
  540. helpId);
  541. delete [] buf;
  542. return;
  543. }
  544. }
  545. // if (_myContentsSize == 0) {// Oops! BE thinks attachment is of size 0.
  546. // 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");
  547. // answer = parent()->handleErrorDialog("BUG!", buf);
  548. //
  549. // // Call setContents again.
  550. // // This will help us debug why the body part has bogus contents.
  551. // this->setContents();
  552. // }
  553. // Create or truncate, and then write the bits.
  554. //
  555. int fd = SafeOpen(filename, O_RDWR | O_CREAT | O_TRUNC, 0600);
  556. if (fd < 0) {
  557. sprintf(buf, GETMSG(DT_catd, 3, 44, "Unable to create %s."), filename);
  558. helpId = DTMAILHELPNOCREATE;
  559. answer = parent()->handleErrorDialog(GETMSG(DT_catd, 1, 87, "Mailer"),
  560. buf,
  561. helpId);
  562. delete [] buf;
  563. return;
  564. }
  565. if (SafeWrite(fd, _myContents, (unsigned int)_myContentsSize) < _myContentsSize) {
  566. sprintf(buf, GETMSG(DT_catd, 3, 45, "Unable to create %s."),
  567. filename);
  568. helpId = DTMAILHELPNOCREATE;
  569. answer = parent()->handleErrorDialog(GETMSG(DT_catd, 1, 88, "Mailer"),
  570. buf,
  571. helpId);
  572. SafeClose(fd);
  573. unlink(filename);
  574. delete [] buf;
  575. return;
  576. }
  577. SafeClose(fd);
  578. // Stat the created file and see if it is of size 0.
  579. // If it is, engage the user in a dialog and involve a dtmail engineer
  580. // to attach a debugger to this process.
  581. // struct stat sbuf;
  582. // SafeStat(filename, &sbuf);
  583. //
  584. // if (sbuf.st_size == 0) {
  585. // 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");
  586. // answer = parent()->handleErrorDialog("BUG!", buf);
  587. // }
  588. delete [] buf;
  589. }
  590. void
  591. Attachment::setX(
  592. Position x
  593. )
  594. {
  595. Arg args[2];
  596. int n = 0;
  597. Boolean was_managed;
  598. _positionX = x;
  599. was_managed = isManaged();
  600. if (was_managed) unmanageIconWidget();
  601. n = 0;
  602. XtSetArg(args[n], XtNx, x); n++;
  603. XtSetValues( _w, args,n);
  604. if (was_managed) manageIconWidget();
  605. }
  606. void
  607. Attachment::setY(
  608. Position y
  609. )
  610. {
  611. Arg args[2];
  612. int n = 0;
  613. Boolean was_managed;
  614. _positionY = y;
  615. was_managed = isManaged();
  616. if (was_managed) unmanageIconWidget();
  617. n = 0;
  618. XtSetArg(args[n], XtNy, y); n++;
  619. XtSetValues( _w, args,n);
  620. if (was_managed) manageIconWidget();
  621. }
  622. #ifdef DEAD_WOOD
  623. void
  624. Attachment::setRow(
  625. int row
  626. )
  627. {
  628. _row = row;
  629. }
  630. #endif /* DEAD_WOOD */
  631. void
  632. Attachment::actionCallback(
  633. DtActionInvocationID id,
  634. XtPointer clientData,
  635. DtActionArg *action_arg,
  636. int argCount,
  637. DtActionStatus status
  638. )
  639. {
  640. ActionCallback *acb = (ActionCallback *) clientData;
  641. if (theRoamApp.session()->session()->validObjectKey(
  642. acb->_myKey) == DTM_FALSE) {
  643. // Error out. Post an error?
  644. return;
  645. }
  646. else {
  647. acb->_myAttachment->action(id, action_arg, argCount, status);
  648. }
  649. }
  650. void
  651. Attachment::action(
  652. DtActionInvocationID id,
  653. DtActionArg *actionArg,
  654. int, // argCount,
  655. int status
  656. )
  657. {
  658. DtActionBuffer bufArg;
  659. DtMailEnv mail_error;
  660. int answer;
  661. char *buf = new char[2048];
  662. const void * lclContents(NULL);
  663. unsigned long lclContentsSize(0);
  664. // Initialize the mail_error.
  665. mail_error.clear();
  666. if (status == DtACTION_INVOKED) {
  667. registerAction(id);
  668. _parent->setPendingAction(TRUE);
  669. }
  670. else if (status == DtACTION_DONE) {
  671. unregisterAction(id);
  672. _parent->setPendingAction(FALSE);
  673. // Check first if ownerShell is an SMD.
  674. // Secondly, check if the SMD is still available. If the user had
  675. // sent the message while this attachment was up, the SMD's reset()
  676. // method would have set the attachments' _deleted flag to TRUE.
  677. // So, check to see that the attachment is still valid before setting
  678. // its contents.
  679. //
  680. // Note: actionArg can be NULL if there were no actions associated
  681. // with the data type. Is this an Actions bug? Could be, but
  682. // we check for it anyway.
  683. if (actionArg != NULL && _parent->isOwnerShellEditable() && !_deleted) {
  684. if (actionArg->argClass == DtACTION_BUFFER) {
  685. bufArg = actionArg->u.buffer;
  686. if (bufArg.writable) {
  687. // Assume user edited launched attachment -- as
  688. // optimization, we can compare buffers to see if
  689. // content actually changed. For now, assume it changed.
  690. // Make a copy of incoming buffer and set body part's
  691. // contents, size. Let BE determine type.
  692. // Reset private variables.
  693. _body_part->setContents(
  694. mail_error,
  695. (char *)bufArg.bp,
  696. bufArg.size,
  697. NULL, NULL, 0, NULL);
  698. // if (mail_error.isSet()) {
  699. // //handle error
  700. // }
  701. assert(mail_error.isNotSet());
  702. //
  703. // CDExc17304. Note the following curiosity. The caller is considered
  704. // the owner of the _myType argument but the called retains ownership
  705. // of the contents.
  706. //
  707. if (_myType) {
  708. free(_myType);
  709. _myType = NULL;
  710. }
  711. _body_part->getContents(
  712. mail_error,
  713. &lclContents,
  714. &lclContentsSize,
  715. &_myType,
  716. NULL, 0, NULL);
  717. // if (mail_error.isSet()) {
  718. // //handle error
  719. // }
  720. assert(mail_error.isNotSet());
  721. _setMyContents(lclContents, int(lclContentsSize));
  722. }
  723. // Free the buffer...
  724. XtFree((char *)bufArg.bp);
  725. }
  726. else {
  727. // DtACTION_FILE
  728. // Read the file into a buffer and do the same stuff
  729. // as above.
  730. int tmp_file;
  731. DtActionFile fileArg = actionArg->u.file;
  732. struct stat stat_buf;
  733. if ( SafeStat ( fileArg.name, &stat_buf ) == -1 ) {
  734. mail_error.setError(DTME_ObjectAccessFailed);
  735. mail_error.logError(DTM_FALSE, "Mailer: Unable to process action, stat failed on file %s.\n", fileArg.name);
  736. delete [] buf;
  737. return;
  738. }
  739. tmp_file = SafeOpen(fileArg.name, O_RDONLY);
  740. char *tmp_buf = (char*) malloc((size_t) stat_buf.st_size);
  741. SafeRead(tmp_file, (void *)tmp_buf, (size_t) stat_buf.st_size);
  742. SafeClose(tmp_file);
  743. _body_part->setContents(mail_error,
  744. tmp_buf,
  745. stat_buf.st_size,
  746. NULL, NULL, 0, NULL);
  747. assert(mail_error.isNotSet());
  748. // Free the buffer
  749. free(tmp_buf);
  750. if (_myType) {
  751. free(_myType);
  752. _myType = NULL;
  753. }
  754. _body_part->getContents(mail_error,
  755. &lclContents,
  756. &lclContentsSize,
  757. &_myType,
  758. NULL, 0, NULL);
  759. assert(mail_error.isNotSet());
  760. _setMyContents(lclContents, int(lclContentsSize));
  761. }
  762. }
  763. }
  764. else if (status == DtACTION_INVALID_ID) {
  765. /* NL_COMMENT
  766. * Post a dialog explaining that the action was invalid
  767. */
  768. sprintf(buf, "%s",
  769. GETMSG(
  770. DT_catd, 3, 91, "Cannot execute invalid action."));
  771. answer = parent()->handleErrorDialog(GETMSG(DT_catd, 1, 86, "Mailer"),
  772. buf);
  773. unregisterAction(id);
  774. _parent->setPendingAction(FALSE);
  775. }
  776. else if (status == DtACTION_FAILED) {
  777. /* NL_COMMENT
  778. * Post a dialog explaining that the action failed.
  779. */
  780. sprintf(buf, "%s",
  781. GETMSG(DT_catd, 3, 92, "Executing action failed!"));
  782. answer = parent()->handleErrorDialog(GETMSG(DT_catd, 1, 86, "Mailer"),
  783. buf);
  784. unregisterAction(id);
  785. _parent->setPendingAction(FALSE);
  786. }
  787. else if (status == DtACTION_STATUS_UPDATE) {
  788. // Check if ownerShell is an SMD. Make sure the message has not
  789. // been sent before attempting to update things.
  790. if(actionArg != NULL && _parent->isOwnerShellEditable() && !_deleted) {
  791. if (actionArg->argClass == DtACTION_BUFFER) {
  792. bufArg = actionArg->u.buffer;
  793. if (bufArg.writable) {
  794. // Assume user edited launched attachment -- as
  795. // optimization, we can compare buffers to see if
  796. // content actually changed. For now, assume it changed.
  797. // Make a copy of incoming buffer and set body part's
  798. // contents, size. Let BE determine type.
  799. // Reset private variables.
  800. _body_part->setContents(
  801. mail_error,
  802. (char *)bufArg.bp,
  803. bufArg.size,
  804. NULL, NULL, 0, NULL);
  805. // if (mail_error.isSet()) {
  806. // //handle error
  807. // }
  808. assert(mail_error.isNotSet());
  809. if (_myType) {
  810. free(_myType);
  811. _myType = NULL;
  812. }
  813. _body_part->getContents(
  814. mail_error,
  815. &lclContents,
  816. &lclContentsSize,
  817. &_myType,
  818. NULL, 0, NULL);
  819. // if (mail_error.isSet()) {
  820. // //handle error
  821. // }
  822. assert(mail_error.isNotSet());
  823. _setMyContents(lclContents, int(lclContentsSize));
  824. }
  825. // Free the buffer
  826. XtFree((char *)bufArg.bp);
  827. }
  828. else {
  829. // DtACTION_FILE
  830. // Read the file into a buffer and do the same stuff
  831. // as above.
  832. int tmp_file;
  833. DtActionFile fileArg = actionArg->u.file;
  834. struct stat stat_buf;
  835. if ( SafeStat ( fileArg.name, &stat_buf ) == -1 ) {
  836. mail_error.setError(DTME_ObjectAccessFailed);
  837. mail_error.logError(DTM_FALSE, "Mailer: Unable to process action, stat failed on file %s.\n", fileArg.name);
  838. delete [] buf;
  839. return;
  840. }
  841. tmp_file = SafeOpen(fileArg.name, O_RDONLY);
  842. char *tmp_buf = (char*) malloc((size_t) stat_buf.st_size);
  843. SafeRead(tmp_file, (void *)tmp_buf, (size_t) stat_buf.st_size);
  844. SafeClose(tmp_file);
  845. _body_part->setContents(mail_error,
  846. (char *)tmp_buf,
  847. (int) stat_buf.st_size,
  848. NULL, NULL, 0, NULL);
  849. assert(mail_error.isNotSet());
  850. if (_myType) {
  851. free(_myType);
  852. _myType = NULL;
  853. }
  854. _body_part->getContents(mail_error,
  855. &lclContents,
  856. &lclContentsSize,
  857. &_myType,
  858. NULL, 0, NULL);
  859. assert(mail_error.isNotSet());
  860. _setMyContents(lclContents, int(lclContentsSize));
  861. // Free the buffer
  862. free(tmp_buf);
  863. }
  864. }
  865. }
  866. else if (status == DtACTION_CANCELED) {
  867. unregisterAction(id);
  868. _parent->setPendingAction(FALSE);
  869. if (actionArg != NULL) {
  870. XtFree((char *)(actionArg->u.buffer.bp));
  871. }
  872. }
  873. delete [] buf;
  874. }
  875. void
  876. Attachment::deleteIt()
  877. {
  878. DtMailEnv mail_error;
  879. // Initialize the mail_error.
  880. mail_error.clear();
  881. _deleted = TRUE;
  882. // Need to remove the view from display
  883. // Get the BE to mark the bodyPart as deleted
  884. _body_part->setFlag(mail_error, DtMailBodyPartDeletePending);
  885. }
  886. void
  887. Attachment::undeleteIt()
  888. {
  889. DtMailEnv mail_error;
  890. // Initialize the mail_error.
  891. mail_error.clear();
  892. _deleted = FALSE;
  893. _body_part->resetFlag(mail_error, DtMailBodyPartDeletePending);
  894. }
  895. void
  896. Attachment::registerAction(
  897. DtActionInvocationID id
  898. )
  899. {
  900. _canKillSelf = FALSE;
  901. _myActionIds.append(id);
  902. }
  903. void
  904. Attachment::unregisterAction(
  905. DtActionInvocationID id
  906. )
  907. {
  908. if (_myActionIds.length() == 0) {
  909. // error. Choke!
  910. }
  911. else {
  912. _myActionIds.remove(id);
  913. if (_canKillSelf) {
  914. // See copious documentation above.
  915. delete this;
  916. }
  917. }
  918. }
  919. void
  920. Attachment::quit()
  921. {
  922. _canKillSelf = TRUE;
  923. if (_myActionIds.length() == 0) {
  924. delete this;
  925. }
  926. }
  927. // ActionCallback
  928. ActionCallback::ActionCallback(
  929. DtMailObjectKey key,
  930. Attachment *att
  931. )
  932. {
  933. _myKey = key;
  934. _myAttachment = att;
  935. }
  936. ActionCallback::~ActionCallback()
  937. {
  938. }
  939. void
  940. Attachment::unmanageIconWidget(void)
  941. {
  942. XtUnmanageChild(_w);
  943. }
  944. void
  945. Attachment::manageIconWidget(void)
  946. {
  947. XtManageChild(_w);
  948. }
  949. void
  950. Attachment::setLabel(XmString str)
  951. {
  952. Arg args[2];
  953. int n;
  954. _label = XmStringCopy(str);
  955. n = 0;
  956. XtSetArg(args[n], XmNstring, _label); n++;
  957. //The Icon widget needs to be unmanaged first before involking XtSetValues
  958. // Otherwise, the parent of the Icon widget does not allow the icon widget
  959. // resize. The Icon widget will be remanaged after its dimensions (w and h)
  960. // are obtained by XtGetValues. This is a fix of the defect 176690.
  961. unmanageIconWidget();
  962. XtSetValues(_w, args, n);
  963. n = 0;
  964. XtSetArg(args[n], XmNwidth, &_attachmentWidth); n++;
  965. XtSetArg(args[n], XmNheight, &_attachmentHeight); n++;
  966. XtGetValues(_w, args, n);
  967. manageIconWidget();
  968. }
  969. void
  970. Attachment::primitive_select()
  971. {
  972. _selected = TRUE;
  973. myIcon->primitiveSelect();
  974. }
  975. void
  976. Attachment::rename(
  977. XmString new_name
  978. )
  979. {
  980. char *name = NULL;
  981. DtMailEnv mail_error;
  982. mail_error.clear();
  983. name = (char *) _XmStringUngenerate(new_name, NULL,
  984. XmMULTIBYTE_TEXT, XmMULTIBYTE_TEXT);
  985. _body_part->setContents(
  986. mail_error,
  987. NULL, 1, NULL,
  988. name, 0, NULL);
  989. this->setLabel(new_name);
  990. }
  991. void
  992. Attachment::setContents()
  993. {
  994. DtMailEnv mail_error;
  995. const void * lclContents;
  996. unsigned long lclContentsSize;
  997. // Initialize the mail_error.
  998. mail_error.clear();
  999. if (_myType) {
  1000. free(_myType);
  1001. _myType = NULL;
  1002. }
  1003. _body_part->getContents(
  1004. mail_error,
  1005. &lclContents,
  1006. &lclContentsSize,
  1007. &_myType,
  1008. NULL, 0, NULL);
  1009. // BE has returned an error condition...
  1010. // It would be nice to popup a dialog to let the user know that
  1011. // dtmail has run into a problem that it can't resolve. Unfortunately,
  1012. // the code for postFatalErrorDialog() has been ifdef'ed out. Perhaps
  1013. // the error dialog can be enabled at some point in the future.
  1014. // if (mail_error.isSet())
  1015. // parent()->myRMW->postFatalErrorDialog(mail_error);
  1016. assert ( mail_error.isNotSet() );
  1017. _setMyContents(lclContents, int(lclContentsSize));
  1018. _haveContents = TRUE;
  1019. // If it is a rfc822 message, check if it has From stuffing.
  1020. // From stuffing is ">From".
  1021. // If it has, advance the pointer to step past the ">" character.
  1022. if (_myType && !strcmp(_myType,"DTMAIL_FILE")) {
  1023. // If it has a From header, return. The classing engine uses
  1024. // that to determine the client that needs to be launched.
  1025. if (_myContents &&
  1026. 0 == strncasecmp((char *)_myContents, "From", 4)) {
  1027. return;
  1028. }
  1029. // Message doesn't begin with From. It may have From stuffing --
  1030. // ">From". Or it may have no From header at all. The MIME
  1031. // specs are vague on what headers an Message/RFC822 body part
  1032. // has to have. We need From to help the classing engine and
  1033. // therefore, we will by force (or hack) make it have a From :-)
  1034. if (_myContents &&
  1035. 0 == strncasecmp((char *)_myContents, ">From", 5)) {
  1036. // Has From stuffing.
  1037. char *ptr = (char *)_myContents;
  1038. ptr++; // Step past the first char
  1039. _myContents = (void *) ptr; // Reset contents
  1040. _myContentsSize--;
  1041. }
  1042. else {
  1043. // No "From" header.
  1044. // Generate a new content string by prepending an
  1045. // "From UNKNOWN" header.
  1046. char *buffer = NULL;
  1047. char *from_hdr = "From UNKNOWN";
  1048. int size = 0;
  1049. // Allocate a buffer for the new contents.
  1050. // One for the '\0' and two for the extra newlines.
  1051. size = strlen(from_hdr) + int(_myContentsSize) + 3;
  1052. buffer = new char[size];
  1053. // Look for the first occurrence of a colon or a newline.
  1054. char *sptr;
  1055. for (sptr = (char*) _myContents;
  1056. *sptr && *sptr != '\n' && *sptr != ':';
  1057. sptr++) {;}
  1058. // Copy in the default From header.
  1059. // Add a second newline if there are no rfc822 message headers.
  1060. // Assume that finding a colon prior to a newline indicates
  1061. // an rfc822 message header.
  1062. if (*sptr == ':')
  1063. sprintf(buffer, "%s\n", from_hdr);
  1064. else
  1065. sprintf(buffer, "%s\n\n", from_hdr);
  1066. // Copy in the original contents.
  1067. size = strlen(buffer);
  1068. memcpy(&buffer[size], (char *) _myContents, (int) _myContentsSize);
  1069. size += (int) _myContentsSize;
  1070. buffer[size] = '\0';
  1071. _setMyContents(buffer, size);
  1072. delete [] buffer;
  1073. }
  1074. }
  1075. }
  1076. void *
  1077. Attachment::getContents()
  1078. {
  1079. if (_myContents) {
  1080. return ( (void *)_myContents );
  1081. }
  1082. else {
  1083. this->setContents();
  1084. return ( (void *)_myContents );
  1085. }
  1086. }
  1087. /*
  1088. * _setMyContents
  1089. *
  1090. * Makes a real copy of the specified data to be used as the
  1091. * attachments's data. Note that a substring of the existing value
  1092. * can be passed in as an argument and the right thing will happen.
  1093. */
  1094. void
  1095. Attachment::_setMyContents(const void * data, int size)
  1096. {
  1097. char * new_contents;
  1098. int new_size;
  1099. if (size > 0) {
  1100. new_size = size;
  1101. new_contents = new char [new_size + 1];
  1102. memcpy(new_contents, data, new_size);
  1103. new_contents[new_size] = '\0';
  1104. }
  1105. else {
  1106. new_size = 0;
  1107. new_contents = NULL;
  1108. }
  1109. if (_myAllocContents != NULL) {
  1110. delete [] _myAllocContents;
  1111. }
  1112. _myAllocContents = new_contents;
  1113. _myContents = new_contents;
  1114. _myContentsSize = new_size;
  1115. return;
  1116. }