TDE personal information management applications
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

kmreaderwin.cpp 106KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095
  1. // -*- mode: C++; c-file-style: "gnu" -*-
  2. // kmreaderwin.cpp
  3. // Author: Markus Wuebben <markus.wuebben@kde.org>
  4. // define this to copy all html that is written to the readerwindow to
  5. // filehtmlwriter.out in the current working directory
  6. // #define KMAIL_READER_HTML_DEBUG 1
  7. #include <config.h>
  8. #include "kmreaderwin.h"
  9. #include "globalsettings.h"
  10. #include "kmversion.h"
  11. #include "kmmainwidget.h"
  12. #include "kmreadermainwin.h"
  13. #include <libtdepim/tdefileio.h>
  14. #include "kmfolderindex.h"
  15. #include "kmcommands.h"
  16. #include "kmmsgpartdlg.h"
  17. #include "mailsourceviewer.h"
  18. using KMail::MailSourceViewer;
  19. #include "partNode.h"
  20. #include "kmmsgdict.h"
  21. #include "messagesender.h"
  22. #include "kcursorsaver.h"
  23. #include "kmfolder.h"
  24. #include "vcardviewer.h"
  25. using KMail::VCardViewer;
  26. #include "objecttreeparser.h"
  27. using KMail::ObjectTreeParser;
  28. #include "partmetadata.h"
  29. using KMail::PartMetaData;
  30. #include "attachmentstrategy.h"
  31. using KMail::AttachmentStrategy;
  32. #include "headerstrategy.h"
  33. using KMail::HeaderStrategy;
  34. #include "headerstyle.h"
  35. using KMail::HeaderStyle;
  36. #include "tdehtmlparthtmlwriter.h"
  37. using KMail::HtmlWriter;
  38. using KMail::KHtmlPartHtmlWriter;
  39. #include "htmlstatusbar.h"
  40. using KMail::HtmlStatusBar;
  41. #include "folderjob.h"
  42. using KMail::FolderJob;
  43. #include "csshelper.h"
  44. using KMail::CSSHelper;
  45. #include "isubject.h"
  46. using KMail::ISubject;
  47. #include "urlhandlermanager.h"
  48. using KMail::URLHandlerManager;
  49. #include "interfaces/observable.h"
  50. #include "util.h"
  51. #include "kmheaders.h"
  52. #include "broadcaststatus.h"
  53. #include <kmime_mdn.h>
  54. using namespace KMime;
  55. #ifdef KMAIL_READER_HTML_DEBUG
  56. #include "filehtmlwriter.h"
  57. using KMail::FileHtmlWriter;
  58. #include "teehtmlwriter.h"
  59. using KMail::TeeHtmlWriter;
  60. #endif
  61. #include <kasciistringtools.h>
  62. #include <kstringhandler.h>
  63. #include <mimelib/mimepp.h>
  64. #include <mimelib/body.h>
  65. #include <mimelib/utility.h>
  66. #include <kleo/specialjob.h>
  67. #include <kleo/cryptobackend.h>
  68. #include <kleo/cryptobackendfactory.h>
  69. // KABC includes
  70. #include <tdeabc/addressee.h>
  71. #include <tdeabc/vcardconverter.h>
  72. // tdehtml headers
  73. #include <tdehtml_part.h>
  74. #include <tdehtmlview.h> // So that we can get rid of the frames
  75. #include <dom/html_element.h>
  76. #include <dom/html_block.h>
  77. #include <dom/html_document.h>
  78. #include <dom/dom_string.h>
  79. #include <dom/dom_exception.h>
  80. #include <tdeapplication.h>
  81. // for the click on attachment stuff (dnaber):
  82. #include <kuserprofile.h>
  83. #include <kcharsets.h>
  84. #include <tdepopupmenu.h>
  85. #include <kstandarddirs.h> // Sven's : for access and getpid
  86. #include <kcursor.h>
  87. #include <kdebug.h>
  88. #include <tdefiledialog.h>
  89. #include <tdelocale.h>
  90. #include <tdemessagebox.h>
  91. #include <tdeglobalsettings.h>
  92. #include <krun.h>
  93. #include <tdetempfile.h>
  94. #include <kprocess.h>
  95. #include <kdialog.h>
  96. #include <tdeaction.h>
  97. #include <kiconloader.h>
  98. #include <kmdcodec.h>
  99. #include <kasciistricmp.h>
  100. #include <kurldrag.h>
  101. #include <tqclipboard.h>
  102. #include <tqhbox.h>
  103. #include <tqtextcodec.h>
  104. #include <tqpaintdevicemetrics.h>
  105. #include <tqlayout.h>
  106. #include <tqlabel.h>
  107. #include <tqsplitter.h>
  108. #include <tqstyle.h>
  109. // X headers...
  110. #undef Never
  111. #undef Always
  112. #include <unistd.h>
  113. #include <stdlib.h>
  114. #include <sys/stat.h>
  115. #include <errno.h>
  116. #include <stdio.h>
  117. #include <ctype.h>
  118. #include <string.h>
  119. #ifdef HAVE_PATHS_H
  120. #include <paths.h>
  121. #endif
  122. class NewByteArray : public TQByteArray
  123. {
  124. public:
  125. NewByteArray &appendNULL();
  126. NewByteArray &operator+=( const char * );
  127. NewByteArray &operator+=( const TQByteArray & );
  128. NewByteArray &operator+=( const TQCString & );
  129. TQByteArray& qByteArray();
  130. };
  131. NewByteArray& NewByteArray::appendNULL()
  132. {
  133. TQByteArray::detach();
  134. uint len1 = size();
  135. if ( !TQByteArray::resize( len1 + 1 ) )
  136. return *this;
  137. *(data() + len1) = '\0';
  138. return *this;
  139. }
  140. NewByteArray& NewByteArray::operator+=( const char * newData )
  141. {
  142. if ( !newData )
  143. return *this;
  144. TQByteArray::detach();
  145. uint len1 = size();
  146. uint len2 = tqstrlen( newData );
  147. if ( !TQByteArray::resize( len1 + len2 ) )
  148. return *this;
  149. memcpy( data() + len1, newData, len2 );
  150. return *this;
  151. }
  152. NewByteArray& NewByteArray::operator+=( const TQByteArray & newData )
  153. {
  154. if ( newData.isNull() )
  155. return *this;
  156. TQByteArray::detach();
  157. uint len1 = size();
  158. uint len2 = newData.size();
  159. if ( !TQByteArray::resize( len1 + len2 ) )
  160. return *this;
  161. memcpy( data() + len1, newData.data(), len2 );
  162. return *this;
  163. }
  164. NewByteArray& NewByteArray::operator+=( const TQCString & newData )
  165. {
  166. if ( newData.isEmpty() )
  167. return *this;
  168. TQByteArray::detach();
  169. uint len1 = size();
  170. uint len2 = newData.length(); // forget about the trailing 0x00 !
  171. if ( !TQByteArray::resize( len1 + len2 ) )
  172. return *this;
  173. memcpy( data() + len1, newData.data(), len2 );
  174. return *this;
  175. }
  176. TQByteArray& NewByteArray::qByteArray()
  177. {
  178. return *((TQByteArray*)this);
  179. }
  180. // This function returns the complete data that were in this
  181. // message parts - *after* all encryption has been removed that
  182. // could be removed.
  183. // - This is used to store the message in decrypted form.
  184. void KMReaderWin::objectTreeToDecryptedMsg( partNode* node,
  185. NewByteArray& resultingData,
  186. KMMessage& theMessage,
  187. bool weAreReplacingTheRootNode,
  188. int recCount )
  189. {
  190. kdDebug(5006) << TQString("-------------------------------------------------" ) << endl;
  191. kdDebug(5006) << TQString("KMReaderWin::objectTreeToDecryptedMsg( %1 ) START").arg( recCount ) << endl;
  192. if( node ) {
  193. kdDebug(5006) << node->typeString() << '/' << node->subTypeString() << endl;
  194. partNode* curNode = node;
  195. partNode* dataNode = curNode;
  196. partNode * child = node->firstChild();
  197. const bool bIsMultipart = node->type() == DwMime::kTypeMultipart ;
  198. bool bKeepPartAsIs = false;
  199. switch( curNode->type() ){
  200. case DwMime::kTypeMultipart: {
  201. switch( curNode->subType() ){
  202. case DwMime::kSubtypeSigned: {
  203. bKeepPartAsIs = true;
  204. }
  205. break;
  206. case DwMime::kSubtypeEncrypted: {
  207. if ( child )
  208. dataNode = child;
  209. }
  210. break;
  211. }
  212. }
  213. break;
  214. case DwMime::kTypeMessage: {
  215. switch( curNode->subType() ){
  216. case DwMime::kSubtypeRfc822: {
  217. if ( child )
  218. dataNode = child;
  219. }
  220. break;
  221. }
  222. }
  223. break;
  224. case DwMime::kTypeApplication: {
  225. switch( curNode->subType() ){
  226. case DwMime::kSubtypeOctetStream: {
  227. if ( child )
  228. dataNode = child;
  229. }
  230. break;
  231. case DwMime::kSubtypePkcs7Signature: {
  232. // note: subtype Pkcs7Signature specifies a signature part
  233. // which we do NOT want to remove!
  234. bKeepPartAsIs = true;
  235. }
  236. break;
  237. case DwMime::kSubtypePkcs7Mime: {
  238. // note: subtype Pkcs7Mime can also be signed
  239. // and we do NOT want to remove the signature!
  240. if ( child && curNode->encryptionState() != KMMsgNotEncrypted )
  241. dataNode = child;
  242. }
  243. break;
  244. }
  245. }
  246. break;
  247. }
  248. DwHeaders& rootHeaders( theMessage.headers() );
  249. DwBodyPart * part = dataNode->dwPart() ? dataNode->dwPart() : 0;
  250. DwHeaders * headers(
  251. (part && part->hasHeaders())
  252. ? &part->Headers()
  253. : ( (weAreReplacingTheRootNode || !dataNode->parentNode())
  254. ? &rootHeaders
  255. : 0 ) );
  256. if( dataNode == curNode ) {
  257. kdDebug(5006) << "dataNode == curNode: Save curNode without replacing it." << endl;
  258. // A) Store the headers of this part IF curNode is not the root node
  259. // AND we are not replacing a node that already *has* replaced
  260. // the root node in previous recursion steps of this function...
  261. if( headers ) {
  262. if( dataNode->parentNode() && !weAreReplacingTheRootNode ) {
  263. kdDebug(5006) << "dataNode is NOT replacing the root node: Store the headers." << endl;
  264. resultingData += headers->AsString().c_str();
  265. } else if( weAreReplacingTheRootNode && part && part->hasHeaders() ){
  266. kdDebug(5006) << "dataNode replace the root node: Do NOT store the headers but change" << endl;
  267. kdDebug(5006) << " the Message's headers accordingly." << endl;
  268. kdDebug(5006) << " old Content-Type = " << rootHeaders.ContentType().AsString().c_str() << endl;
  269. kdDebug(5006) << " new Content-Type = " << headers->ContentType( ).AsString().c_str() << endl;
  270. rootHeaders.ContentType() = headers->ContentType();
  271. theMessage.setContentTransferEncodingStr(
  272. headers->HasContentTransferEncoding()
  273. ? headers->ContentTransferEncoding().AsString().c_str()
  274. : "" );
  275. rootHeaders.ContentDescription() = headers->ContentDescription();
  276. rootHeaders.ContentDisposition() = headers->ContentDisposition();
  277. theMessage.setNeedsAssembly();
  278. }
  279. }
  280. if ( bKeepPartAsIs ) {
  281. resultingData += dataNode->encodedBody();
  282. } else {
  283. // B) Store the body of this part.
  284. if( headers && bIsMultipart && dataNode->firstChild() ) {
  285. kdDebug(5006) << "is valid Multipart, processing children:" << endl;
  286. TQCString boundary = headers->ContentType().Boundary().c_str();
  287. curNode = dataNode->firstChild();
  288. // store children of multipart
  289. while( curNode ) {
  290. kdDebug(5006) << "--boundary" << endl;
  291. if( resultingData.size() &&
  292. ( '\n' != resultingData.at( resultingData.size()-1 ) ) )
  293. resultingData += TQCString( "\n" );
  294. resultingData += TQCString( "\n" );
  295. resultingData += "--";
  296. resultingData += boundary;
  297. resultingData += "\n";
  298. // note: We are processing a harmless multipart that is *not*
  299. // to be replaced by one of it's children, therefor
  300. // we set their doStoreHeaders to true.
  301. objectTreeToDecryptedMsg( curNode,
  302. resultingData,
  303. theMessage,
  304. false,
  305. recCount + 1 );
  306. curNode = curNode->nextSibling();
  307. }
  308. kdDebug(5006) << "--boundary--" << endl;
  309. resultingData += "\n--";
  310. resultingData += boundary;
  311. resultingData += "--\n\n";
  312. kdDebug(5006) << "Multipart processing children - DONE" << endl;
  313. } else if( part ){
  314. // store simple part
  315. kdDebug(5006) << "is Simple part or invalid Multipart, storing body data .. DONE" << endl;
  316. resultingData += part->Body().AsString().c_str();
  317. }
  318. }
  319. } else {
  320. kdDebug(5006) << "dataNode != curNode: Replace curNode by dataNode." << endl;
  321. bool rootNodeReplaceFlag = weAreReplacingTheRootNode || !curNode->parentNode();
  322. if( rootNodeReplaceFlag ) {
  323. kdDebug(5006) << " Root node will be replaced." << endl;
  324. } else {
  325. kdDebug(5006) << " Root node will NOT be replaced." << endl;
  326. }
  327. // store special data to replace the current part
  328. // (e.g. decrypted data or embedded RfC 822 data)
  329. objectTreeToDecryptedMsg( dataNode,
  330. resultingData,
  331. theMessage,
  332. rootNodeReplaceFlag,
  333. recCount + 1 );
  334. }
  335. }
  336. kdDebug(5006) << TQString("\nKMReaderWin::objectTreeToDecryptedMsg( %1 ) END").arg( recCount ) << endl;
  337. }
  338. /*
  339. ===========================================================================
  340. E N D O F T E M P O R A R Y M I M E C O D E
  341. ===========================================================================
  342. */
  343. void KMReaderWin::createWidgets() {
  344. TQVBoxLayout * vlay = new TQVBoxLayout( this );
  345. mSplitter = new TQSplitter( Qt::Vertical, this, "mSplitter" );
  346. vlay->addWidget( mSplitter );
  347. mMimePartTree = new KMMimePartTree( this, mSplitter, "mMimePartTree" );
  348. mBox = new TQHBox( mSplitter, "mBox" );
  349. setStyleDependantFrameWidth();
  350. mBox->setFrameStyle( mMimePartTree->frameStyle() );
  351. mColorBar = new HtmlStatusBar( mBox, "mColorBar" );
  352. mViewer = new TDEHTMLPart( mBox, "mViewer" );
  353. mSplitter->setOpaqueResize( TDEGlobalSettings::opaqueResize() );
  354. mSplitter->setResizeMode( mMimePartTree, TQSplitter::KeepSize );
  355. }
  356. const int KMReaderWin::delay = 150;
  357. //-----------------------------------------------------------------------------
  358. KMReaderWin::KMReaderWin(TQWidget *aParent,
  359. TQWidget *mainWindow,
  360. TDEActionCollection* actionCollection,
  361. const char *aName,
  362. int aFlags )
  363. : TQWidget(aParent, aName, aFlags | TQt::WDestructiveClose),
  364. mSerNumOfOriginalMessage( 0 ),
  365. mNodeIdOffset( -1 ),
  366. mAttachmentStrategy( 0 ),
  367. mHeaderStrategy( 0 ),
  368. mHeaderStyle( 0 ),
  369. mUpdateReaderWinTimer( 0, "mUpdateReaderWinTimer" ),
  370. mResizeTimer( 0, "mResizeTimer" ),
  371. mDelayedMarkTimer( 0, "mDelayedMarkTimer" ),
  372. mHeaderRefreshTimer( 0, "mHeaderRefreshTimer" ),
  373. mOldGlobalOverrideEncoding( "---" ), // init with dummy value
  374. mCSSHelper( 0 ),
  375. mRootNode( 0 ),
  376. mMainWindow( mainWindow ),
  377. mActionCollection( actionCollection ),
  378. mMailToComposeAction( 0 ),
  379. mMailToReplyAction( 0 ),
  380. mMailToForwardAction( 0 ),
  381. mAddAddrBookAction( 0 ),
  382. mOpenAddrBookAction( 0 ),
  383. mCopyAction( 0 ),
  384. mCopyURLAction( 0 ),
  385. mUrlOpenAction( 0 ),
  386. mUrlSaveAsAction( 0 ),
  387. mAddBookmarksAction( 0 ),
  388. mStartIMChatAction( 0 ),
  389. mSelectAllAction( 0 ),
  390. mHeaderOnlyAttachmentsAction( 0 ),
  391. mSelectEncodingAction( 0 ),
  392. mToggleFixFontAction( 0 ),
  393. mCanStartDrag( false ),
  394. mHtmlWriter( 0 ),
  395. mSavedRelativePosition( 0 ),
  396. mDecrytMessageOverwrite( false ),
  397. mShowSignatureDetails( false ),
  398. mShowAttachmentQuicklist( true ),
  399. mShowRawToltecMail( false )
  400. {
  401. mExternalWindow = (aParent == mainWindow );
  402. mSplitterSizes << 180 << 100;
  403. mMimeTreeMode = 1;
  404. mMimeTreeAtBottom = true;
  405. mAutoDelete = false;
  406. mLastSerNum = 0;
  407. mWaitingForSerNum = 0;
  408. mMessage = 0;
  409. mMsgDisplay = true;
  410. mPrinting = false;
  411. mShowColorbar = false;
  412. mAtmUpdate = false;
  413. createWidgets();
  414. createActions( actionCollection );
  415. initHtmlWidget();
  416. readConfig();
  417. mHtmlOverride = false;
  418. mHtmlLoadExtOverride = false;
  419. mLevelQuote = GlobalSettings::self()->collapseQuoteLevelSpin() - 1;
  420. connect( &mUpdateReaderWinTimer, TQT_SIGNAL(timeout()),
  421. TQT_TQOBJECT(this), TQT_SLOT(updateReaderWin()) );
  422. connect( &mResizeTimer, TQT_SIGNAL(timeout()),
  423. TQT_TQOBJECT(this), TQT_SLOT(slotDelayedResize()) );
  424. connect( &mDelayedMarkTimer, TQT_SIGNAL(timeout()),
  425. TQT_TQOBJECT(this), TQT_SLOT(slotTouchMessage()) );
  426. connect( &mHeaderRefreshTimer, TQT_SIGNAL(timeout()),
  427. TQT_TQOBJECT(this), TQT_SLOT(updateHeader()) );
  428. }
  429. void KMReaderWin::createActions( TDEActionCollection * ac ) {
  430. if ( !ac )
  431. return;
  432. TDERadioAction *raction = 0;
  433. // header style
  434. TDEActionMenu *headerMenu =
  435. new TDEActionMenu( i18n("View->", "&Headers"), ac, "view_headers" );
  436. headerMenu->setToolTip( i18n("Choose display style of message headers") );
  437. connect( headerMenu, TQT_SIGNAL(activated()),
  438. TQT_TQOBJECT(this), TQT_SLOT(slotCycleHeaderStyles()) );
  439. raction = new TDERadioAction( i18n("View->headers->", "&Enterprise Headers"), 0,
  440. TQT_TQOBJECT(this), TQT_SLOT(slotEnterpriseHeaders()),
  441. ac, "view_headers_enterprise" );
  442. raction->setToolTip( i18n("Show the list of headers in Enterprise style") );
  443. raction->setExclusiveGroup( "view_headers_group" );
  444. headerMenu->insert(raction);
  445. raction = new TDERadioAction( i18n("View->headers->", "&Fancy Headers"), 0,
  446. TQT_TQOBJECT(this), TQT_SLOT(slotFancyHeaders()),
  447. ac, "view_headers_fancy" );
  448. raction->setToolTip( i18n("Show the list of headers in a fancy format") );
  449. raction->setExclusiveGroup( "view_headers_group" );
  450. headerMenu->insert( raction );
  451. raction = new TDERadioAction( i18n("View->headers->", "&Brief Headers"), 0,
  452. TQT_TQOBJECT(this), TQT_SLOT(slotBriefHeaders()),
  453. ac, "view_headers_brief" );
  454. raction->setToolTip( i18n("Show brief list of message headers") );
  455. raction->setExclusiveGroup( "view_headers_group" );
  456. headerMenu->insert( raction );
  457. raction = new TDERadioAction( i18n("View->headers->", "&Standard Headers"), 0,
  458. TQT_TQOBJECT(this), TQT_SLOT(slotStandardHeaders()),
  459. ac, "view_headers_standard" );
  460. raction->setToolTip( i18n("Show standard list of message headers") );
  461. raction->setExclusiveGroup( "view_headers_group" );
  462. headerMenu->insert( raction );
  463. raction = new TDERadioAction( i18n("View->headers->", "&Long Headers"), 0,
  464. TQT_TQOBJECT(this), TQT_SLOT(slotLongHeaders()),
  465. ac, "view_headers_long" );
  466. raction->setToolTip( i18n("Show long list of message headers") );
  467. raction->setExclusiveGroup( "view_headers_group" );
  468. headerMenu->insert( raction );
  469. raction = new TDERadioAction( i18n("View->headers->", "&All Headers"), 0,
  470. TQT_TQOBJECT(this), TQT_SLOT(slotAllHeaders()),
  471. ac, "view_headers_all" );
  472. raction->setToolTip( i18n("Show all message headers") );
  473. raction->setExclusiveGroup( "view_headers_group" );
  474. headerMenu->insert( raction );
  475. // attachment style
  476. TDEActionMenu *attachmentMenu =
  477. new TDEActionMenu( i18n("View->", "&Attachments"), ac, "view_attachments" );
  478. attachmentMenu->setToolTip( i18n("Choose display style of attachments") );
  479. connect( attachmentMenu, TQT_SIGNAL(activated()),
  480. TQT_TQOBJECT(this), TQT_SLOT(slotCycleAttachmentStrategy()) );
  481. raction = new TDERadioAction( i18n("View->attachments->", "&As Icons"), 0,
  482. TQT_TQOBJECT(this), TQT_SLOT(slotIconicAttachments()),
  483. ac, "view_attachments_as_icons" );
  484. raction->setToolTip( i18n("Show all attachments as icons. Click to see them.") );
  485. raction->setExclusiveGroup( "view_attachments_group" );
  486. attachmentMenu->insert( raction );
  487. raction = new TDERadioAction( i18n("View->attachments->", "&Smart"), 0,
  488. TQT_TQOBJECT(this), TQT_SLOT(slotSmartAttachments()),
  489. ac, "view_attachments_smart" );
  490. raction->setToolTip( i18n("Show attachments as suggested by sender.") );
  491. raction->setExclusiveGroup( "view_attachments_group" );
  492. attachmentMenu->insert( raction );
  493. raction = new TDERadioAction( i18n("View->attachments->", "&Inline"), 0,
  494. TQT_TQOBJECT(this), TQT_SLOT(slotInlineAttachments()),
  495. ac, "view_attachments_inline" );
  496. raction->setToolTip( i18n("Show all attachments inline (if possible)") );
  497. raction->setExclusiveGroup( "view_attachments_group" );
  498. attachmentMenu->insert( raction );
  499. raction = new TDERadioAction( i18n("View->attachments->", "&Hide"), 0,
  500. TQT_TQOBJECT(this), TQT_SLOT(slotHideAttachments()),
  501. ac, "view_attachments_hide" );
  502. raction->setToolTip( i18n("Do not show attachments in the message viewer") );
  503. raction->setExclusiveGroup( "view_attachments_group" );
  504. attachmentMenu->insert( raction );
  505. mHeaderOnlyAttachmentsAction = new TDERadioAction( i18n( "View->attachments->", "In Header &Only" ), 0,
  506. TQT_TQOBJECT(this), TQT_SLOT( slotHeaderOnlyAttachments() ),
  507. ac, "view_attachments_headeronly" );
  508. mHeaderOnlyAttachmentsAction->setToolTip( i18n( "Show Attachments only in the header of the mail" ) );
  509. mHeaderOnlyAttachmentsAction->setExclusiveGroup( "view_attachments_group" );
  510. attachmentMenu->insert( mHeaderOnlyAttachmentsAction );
  511. // Set Encoding submenu
  512. mSelectEncodingAction = new TDESelectAction( i18n( "&Set Encoding" ), "charset", 0,
  513. TQT_TQOBJECT(this), TQT_SLOT( slotSetEncoding() ),
  514. ac, "encoding" );
  515. TQStringList encodings = KMMsgBase::supportedEncodings( false );
  516. encodings.prepend( i18n( "Auto" ) );
  517. mSelectEncodingAction->setItems( encodings );
  518. mSelectEncodingAction->setCurrentItem( 0 );
  519. mMailToComposeAction = new TDEAction( i18n("New Message To..."), "mail_new",
  520. 0, TQT_TQOBJECT(this), TQT_SLOT(slotMailtoCompose()), ac,
  521. "mailto_compose" );
  522. mMailToReplyAction = new TDEAction( i18n("Reply To..."), "mail_reply",
  523. 0, TQT_TQOBJECT(this), TQT_SLOT(slotMailtoReply()), ac,
  524. "mailto_reply" );
  525. mMailToForwardAction = new TDEAction( i18n("Forward To..."), "mail_forward",
  526. 0, TQT_TQOBJECT(this), TQT_SLOT(slotMailtoForward()), ac,
  527. "mailto_forward" );
  528. mAddAddrBookAction = new TDEAction( i18n("Add to Address Book"),
  529. 0, TQT_TQOBJECT(this), TQT_SLOT(slotMailtoAddAddrBook()),
  530. ac, "add_addr_book" );
  531. mOpenAddrBookAction = new TDEAction( i18n("Open in Address Book"),
  532. 0, TQT_TQOBJECT(this), TQT_SLOT(slotMailtoOpenAddrBook()),
  533. ac, "openin_addr_book" );
  534. mCopyAction = KStdAction::copy( TQT_TQOBJECT(this), TQT_SLOT(slotCopySelectedText()), ac, "kmail_copy");
  535. mSelectAllAction = new TDEAction( i18n("Select All Text"), CTRL+SHIFT+Key_A, TQT_TQOBJECT(this),
  536. TQT_SLOT(selectAll()), ac, "mark_all_text" );
  537. mCopyURLAction = new TDEAction( i18n("Copy Link Address"), 0, TQT_TQOBJECT(this),
  538. TQT_SLOT(slotUrlCopy()), ac, "copy_url" );
  539. mUrlOpenAction = new TDEAction( i18n("Open URL"), 0, TQT_TQOBJECT(this),
  540. TQT_SLOT(slotUrlOpen()), ac, "open_url" );
  541. mAddBookmarksAction = new TDEAction( i18n("Bookmark This Link"),
  542. "bookmark_add",
  543. 0, TQT_TQOBJECT(this), TQT_SLOT(slotAddBookmarks()),
  544. ac, "add_bookmarks" );
  545. mUrlSaveAsAction = new TDEAction( i18n("Save Link As..."), 0, TQT_TQOBJECT(this),
  546. TQT_SLOT(slotUrlSave()), ac, "saveas_url" );
  547. mToggleFixFontAction = new TDEToggleAction( i18n("Use Fi&xed Font"),
  548. Key_X, TQT_TQOBJECT(this), TQT_SLOT(slotToggleFixedFont()),
  549. ac, "toggle_fixedfont" );
  550. mStartIMChatAction = new TDEAction( i18n("Chat &With..."), 0, TQT_TQOBJECT(this),
  551. TQT_SLOT(slotIMChat()), ac, "start_im_chat" );
  552. }
  553. // little helper function
  554. TDERadioAction *KMReaderWin::actionForHeaderStyle( const HeaderStyle * style, const HeaderStrategy * strategy ) {
  555. if ( !mActionCollection )
  556. return 0;
  557. const char * actionName = 0;
  558. if ( style == HeaderStyle::enterprise() )
  559. actionName = "view_headers_enterprise";
  560. if ( style == HeaderStyle::fancy() )
  561. actionName = "view_headers_fancy";
  562. else if ( style == HeaderStyle::brief() )
  563. actionName = "view_headers_brief";
  564. else if ( style == HeaderStyle::plain() ) {
  565. if ( strategy == HeaderStrategy::standard() )
  566. actionName = "view_headers_standard";
  567. else if ( strategy == HeaderStrategy::rich() )
  568. actionName = "view_headers_long";
  569. else if ( strategy == HeaderStrategy::all() )
  570. actionName = "view_headers_all";
  571. }
  572. if ( actionName )
  573. return static_cast<TDERadioAction*>(mActionCollection->action(actionName));
  574. else
  575. return 0;
  576. }
  577. TDERadioAction *KMReaderWin::actionForAttachmentStrategy( const AttachmentStrategy * as ) {
  578. if ( !mActionCollection )
  579. return 0;
  580. const char * actionName = 0;
  581. if ( as == AttachmentStrategy::iconic() )
  582. actionName = "view_attachments_as_icons";
  583. else if ( as == AttachmentStrategy::smart() )
  584. actionName = "view_attachments_smart";
  585. else if ( as == AttachmentStrategy::inlined() )
  586. actionName = "view_attachments_inline";
  587. else if ( as == AttachmentStrategy::hidden() )
  588. actionName = "view_attachments_hide";
  589. else if ( as == AttachmentStrategy::headerOnly() )
  590. actionName = "view_attachments_headeronly";
  591. if ( actionName )
  592. return static_cast<TDERadioAction*>(mActionCollection->action(actionName));
  593. else
  594. return 0;
  595. }
  596. void KMReaderWin::slotEnterpriseHeaders() {
  597. setHeaderStyleAndStrategy( HeaderStyle::enterprise(),
  598. HeaderStrategy::rich() );
  599. if( !mExternalWindow )
  600. writeConfig();
  601. }
  602. void KMReaderWin::slotFancyHeaders() {
  603. setHeaderStyleAndStrategy( HeaderStyle::fancy(),
  604. HeaderStrategy::rich() );
  605. if( !mExternalWindow )
  606. writeConfig();
  607. }
  608. void KMReaderWin::slotBriefHeaders() {
  609. setHeaderStyleAndStrategy( HeaderStyle::brief(),
  610. HeaderStrategy::brief() );
  611. if( !mExternalWindow )
  612. writeConfig();
  613. }
  614. void KMReaderWin::slotStandardHeaders() {
  615. setHeaderStyleAndStrategy( HeaderStyle::plain(),
  616. HeaderStrategy::standard());
  617. writeConfig();
  618. }
  619. void KMReaderWin::slotLongHeaders() {
  620. setHeaderStyleAndStrategy( HeaderStyle::plain(),
  621. HeaderStrategy::rich() );
  622. if( !mExternalWindow )
  623. writeConfig();
  624. }
  625. void KMReaderWin::slotAllHeaders() {
  626. setHeaderStyleAndStrategy( HeaderStyle::plain(),
  627. HeaderStrategy::all() );
  628. if( !mExternalWindow )
  629. writeConfig();
  630. }
  631. void KMReaderWin::slotLevelQuote( int l )
  632. {
  633. mLevelQuote = l;
  634. saveRelativePosition();
  635. update(true);
  636. }
  637. void KMReaderWin::slotCycleHeaderStyles() {
  638. const HeaderStrategy * strategy = headerStrategy();
  639. const HeaderStyle * style = headerStyle();
  640. const char * actionName = 0;
  641. if ( style == HeaderStyle::enterprise() ) {
  642. slotFancyHeaders();
  643. actionName = "view_headers_fancy";
  644. }
  645. if ( style == HeaderStyle::fancy() ) {
  646. slotBriefHeaders();
  647. actionName = "view_headers_brief";
  648. } else if ( style == HeaderStyle::brief() ) {
  649. slotStandardHeaders();
  650. actionName = "view_headers_standard";
  651. } else if ( style == HeaderStyle::plain() ) {
  652. if ( strategy == HeaderStrategy::standard() ) {
  653. slotLongHeaders();
  654. actionName = "view_headers_long";
  655. } else if ( strategy == HeaderStrategy::rich() ) {
  656. slotAllHeaders();
  657. actionName = "view_headers_all";
  658. } else if ( strategy == HeaderStrategy::all() ) {
  659. slotEnterpriseHeaders();
  660. actionName = "view_headers_enterprise";
  661. }
  662. }
  663. if ( actionName )
  664. static_cast<TDERadioAction*>( mActionCollection->action( actionName ) )->setChecked( true );
  665. }
  666. void KMReaderWin::slotIconicAttachments() {
  667. setAttachmentStrategy( AttachmentStrategy::iconic() );
  668. }
  669. void KMReaderWin::slotSmartAttachments() {
  670. setAttachmentStrategy( AttachmentStrategy::smart() );
  671. }
  672. void KMReaderWin::slotInlineAttachments() {
  673. setAttachmentStrategy( AttachmentStrategy::inlined() );
  674. }
  675. void KMReaderWin::slotHideAttachments() {
  676. setAttachmentStrategy( AttachmentStrategy::hidden() );
  677. }
  678. void KMReaderWin::slotHeaderOnlyAttachments() {
  679. setAttachmentStrategy( AttachmentStrategy::headerOnly() );
  680. }
  681. void KMReaderWin::slotCycleAttachmentStrategy() {
  682. setAttachmentStrategy( attachmentStrategy()->next() );
  683. TDERadioAction * action = actionForAttachmentStrategy( attachmentStrategy() );
  684. assert( action );
  685. action->setChecked( true );
  686. }
  687. //-----------------------------------------------------------------------------
  688. KMReaderWin::~KMReaderWin()
  689. {
  690. clearBodyPartMementos();
  691. delete mHtmlWriter; mHtmlWriter = 0;
  692. delete mCSSHelper;
  693. if (mAutoDelete) delete message();
  694. delete mRootNode; mRootNode = 0;
  695. removeTempFiles();
  696. }
  697. //-----------------------------------------------------------------------------
  698. void KMReaderWin::slotMessageArrived( KMMessage *msg )
  699. {
  700. if (msg && ((KMMsgBase*)msg)->isMessage()) {
  701. if ( msg->getMsgSerNum() == mWaitingForSerNum ) {
  702. setMsg( msg, true );
  703. } else {
  704. //kdDebug( 5006 ) << "KMReaderWin::slotMessageArrived - ignoring update" << endl;
  705. }
  706. }
  707. }
  708. //-----------------------------------------------------------------------------
  709. void KMReaderWin::update( KMail::Interface::Observable * observable )
  710. {
  711. if ( !mAtmUpdate ) {
  712. // reparse the msg
  713. //kdDebug(5006) << "KMReaderWin::update - message" << endl;
  714. updateReaderWin();
  715. return;
  716. }
  717. if ( !mRootNode )
  718. return;
  719. KMMessage* msg = static_cast<KMMessage*>( observable );
  720. assert( msg != 0 );
  721. // find our partNode and update it
  722. if ( !msg->lastUpdatedPart() ) {
  723. kdDebug(5006) << "KMReaderWin::update - no updated part" << endl;
  724. return;
  725. }
  726. partNode* node = mRootNode->findNodeForDwPart( msg->lastUpdatedPart() );
  727. if ( !node ) {
  728. kdDebug(5006) << "KMReaderWin::update - can't find node for part" << endl;
  729. return;
  730. }
  731. node->setDwPart( msg->lastUpdatedPart() );
  732. // update the tmp file
  733. // we have to set it writeable temporarily
  734. ::chmod( TQFile::encodeName( mAtmCurrentName ), S_IRWXU );
  735. TQByteArray data = node->msgPart().bodyDecodedBinary();
  736. size_t size = data.size();
  737. if ( node->msgPart().type() == DwMime::kTypeText && size) {
  738. size = KMail::Util::crlf2lf( data.data(), size );
  739. }
  740. KPIM::kBytesToFile( data.data(), size, mAtmCurrentName, false, false, false );
  741. ::chmod( TQFile::encodeName( mAtmCurrentName ), S_IRUSR );
  742. mAtmUpdate = false;
  743. }
  744. //-----------------------------------------------------------------------------
  745. void KMReaderWin::removeTempFiles()
  746. {
  747. for (TQStringList::Iterator it = mTempFiles.begin(); it != mTempFiles.end();
  748. it++)
  749. {
  750. TQFile::remove(*it);
  751. }
  752. mTempFiles.clear();
  753. for (TQStringList::Iterator it = mTempDirs.begin(); it != mTempDirs.end();
  754. it++)
  755. {
  756. TQDir(*it).rmdir(*it);
  757. }
  758. mTempDirs.clear();
  759. }
  760. //-----------------------------------------------------------------------------
  761. bool KMReaderWin::event(TQEvent *e)
  762. {
  763. if (e->type() == TQEvent::ApplicationPaletteChange)
  764. {
  765. delete mCSSHelper;
  766. mCSSHelper = new KMail::CSSHelper( TQPaintDeviceMetrics( mViewer->view() ) );
  767. if (message())
  768. message()->readConfig();
  769. update( true ); // Force update
  770. return true;
  771. }
  772. return TQWidget::event(e);
  773. }
  774. //-----------------------------------------------------------------------------
  775. void KMReaderWin::readConfig(void)
  776. {
  777. const TDEConfigGroup mdnGroup( KMKernel::config(), "MDN" );
  778. /*should be: const*/ TDEConfigGroup reader( KMKernel::config(), "Reader" );
  779. delete mCSSHelper;
  780. mCSSHelper = new KMail::CSSHelper( TQPaintDeviceMetrics( mViewer->view() ) );
  781. mNoMDNsWhenEncrypted = mdnGroup.readBoolEntry( "not-send-when-encrypted", true );
  782. mUseFixedFont = reader.readBoolEntry( "useFixedFont", false );
  783. if ( mToggleFixFontAction )
  784. mToggleFixFontAction->setChecked( mUseFixedFont );
  785. mHtmlMail = reader.readBoolEntry( "htmlMail", false );
  786. mHtmlLoadExternal = reader.readBoolEntry( "htmlLoadExternal", false );
  787. setHeaderStyleAndStrategy( HeaderStyle::create( reader.readEntry( "header-style", "fancy" ) ),
  788. HeaderStrategy::create( reader.readEntry( "header-set-displayed", "rich" ) ) );
  789. TDERadioAction *raction = actionForHeaderStyle( headerStyle(), headerStrategy() );
  790. if ( raction )
  791. raction->setChecked( true );
  792. setAttachmentStrategy( AttachmentStrategy::create( reader.readEntry( "attachment-strategy", "smart" ) ) );
  793. raction = actionForAttachmentStrategy( attachmentStrategy() );
  794. if ( raction )
  795. raction->setChecked( true );
  796. // if the user uses OpenPGP then the color bar defaults to enabled
  797. // else it defaults to disabled
  798. mShowColorbar = reader.readBoolEntry( "showColorbar", Kpgp::Module::getKpgp()->usePGP() );
  799. // if the value defaults to enabled and KMail (with color bar) is used for
  800. // the first time the config dialog doesn't know this if we don't save the
  801. // value now
  802. reader.writeEntry( "showColorbar", mShowColorbar );
  803. mMimeTreeAtBottom = reader.readEntry( "MimeTreeLocation", "bottom" ) != "top";
  804. const TQString s = reader.readEntry( "MimeTreeMode", "smart" );
  805. if ( s == "never" )
  806. mMimeTreeMode = 0;
  807. else if ( s == "always" )
  808. mMimeTreeMode = 2;
  809. else
  810. mMimeTreeMode = 1;
  811. const int mimeH = reader.readNumEntry( "MimePaneHeight", 100 );
  812. const int messageH = reader.readNumEntry( "MessagePaneHeight", 180 );
  813. mSplitterSizes.clear();
  814. if ( mMimeTreeAtBottom )
  815. mSplitterSizes << messageH << mimeH;
  816. else
  817. mSplitterSizes << mimeH << messageH;
  818. adjustLayout();
  819. readGlobalOverrideCodec();
  820. if (message())
  821. update();
  822. KMMessage::readConfig();
  823. }
  824. void KMReaderWin::adjustLayout() {
  825. if ( mMimeTreeAtBottom )
  826. mSplitter->moveToLast( mMimePartTree );
  827. else
  828. mSplitter->moveToFirst( mMimePartTree );
  829. mSplitter->setSizes( mSplitterSizes );
  830. if ( mMimeTreeMode == 2 && mMsgDisplay )
  831. mMimePartTree->show();
  832. else
  833. mMimePartTree->hide();
  834. if ( mShowColorbar && mMsgDisplay )
  835. mColorBar->show();
  836. else
  837. mColorBar->hide();
  838. }
  839. void KMReaderWin::saveSplitterSizes( TDEConfigBase & c ) const {
  840. if ( !mSplitter || !mMimePartTree )
  841. return;
  842. if ( mMimePartTree->isHidden() )
  843. return; // don't rely on TQSplitter maintaining sizes for hidden widgets.
  844. c.writeEntry( "MimePaneHeight", mSplitter->sizes()[ mMimeTreeAtBottom ? 1 : 0 ] );
  845. c.writeEntry( "MessagePaneHeight", mSplitter->sizes()[ mMimeTreeAtBottom ? 0 : 1 ] );
  846. }
  847. //-----------------------------------------------------------------------------
  848. void KMReaderWin::writeConfig( bool sync ) const {
  849. TDEConfigGroup reader( KMKernel::config(), "Reader" );
  850. reader.writeEntry( "useFixedFont", mUseFixedFont );
  851. if ( headerStyle() )
  852. reader.writeEntry( "header-style", headerStyle()->name() );
  853. if ( headerStrategy() )
  854. reader.writeEntry( "header-set-displayed", headerStrategy()->name() );
  855. if ( attachmentStrategy() )
  856. reader.writeEntry( "attachment-strategy", attachmentStrategy()->name() );
  857. saveSplitterSizes( reader );
  858. if ( sync )
  859. kmkernel->slotRequestConfigSync();
  860. }
  861. //-----------------------------------------------------------------------------
  862. void KMReaderWin::initHtmlWidget(void)
  863. {
  864. mViewer->widget()->setFocusPolicy(TQ_WheelFocus);
  865. // Let's better be paranoid and disable plugins (it defaults to enabled):
  866. mViewer->setPluginsEnabled(false);
  867. mViewer->setJScriptEnabled(false); // just make this explicit
  868. mViewer->setJavaEnabled(false); // just make this explicit
  869. mViewer->setMetaRefreshEnabled(false);
  870. mViewer->setURLCursor(KCursor::handCursor());
  871. // Espen 2000-05-14: Getting rid of thick ugly frames
  872. mViewer->view()->setLineWidth(0);
  873. // register our own event filter for shift-click
  874. mViewer->view()->viewport()->installEventFilter( this );
  875. if ( !htmlWriter() )
  876. #ifdef KMAIL_READER_HTML_DEBUG
  877. mHtmlWriter = new TeeHtmlWriter( new FileHtmlWriter( TQString() ),
  878. new KHtmlPartHtmlWriter( mViewer, 0 ) );
  879. #else
  880. mHtmlWriter = new KHtmlPartHtmlWriter( mViewer, 0 );
  881. #endif
  882. connect(mViewer->browserExtension(),
  883. TQT_SIGNAL(openURLRequest(const KURL &, const KParts::URLArgs &)),this,
  884. TQT_SLOT(slotUrlOpen(const KURL &)));
  885. connect(mViewer->browserExtension(),
  886. TQT_SIGNAL(createNewWindow(const KURL &, const KParts::URLArgs &)),this,
  887. TQT_SLOT(slotUrlOpen(const KURL &)));
  888. connect(mViewer,TQT_SIGNAL(popupMenu(const TQString &, const TQPoint &)),
  889. TQT_SLOT(slotUrlPopup(const TQString &, const TQPoint &)));
  890. connect( kmkernel->imProxy(), TQT_SIGNAL( sigContactPresenceChanged( const TQString & ) ),
  891. TQT_TQOBJECT(this), TQT_SLOT( contactStatusChanged( const TQString & ) ) );
  892. connect( kmkernel->imProxy(), TQT_SIGNAL( sigPresenceInfoExpired() ),
  893. TQT_TQOBJECT(this), TQT_SLOT( updateReaderWin() ) );
  894. }
  895. void KMReaderWin::contactStatusChanged( const TQString &uid)
  896. {
  897. // kdDebug( 5006 ) << k_funcinfo << " got a presence change for " << uid << endl;
  898. // get the list of nodes for this contact from the htmlView
  899. DOM::NodeList presenceNodes = mViewer->htmlDocument()
  900. .getElementsByName( DOM::DOMString( TQString::fromLatin1("presence-") + uid ) );
  901. for ( unsigned int i = 0; i < presenceNodes.length(); ++i ) {
  902. DOM::Node n = presenceNodes.item( i );
  903. kdDebug( 5006 ) << "name is " << n.nodeName().string() << endl;
  904. kdDebug( 5006 ) << "value of content was " << n.firstChild().nodeValue().string() << endl;
  905. TQString newPresence = kmkernel->imProxy()->presenceString( uid );
  906. if ( newPresence.isNull() ) // TDEHTML crashes if you setNodeValue( TQString() )
  907. newPresence = TQString::fromLatin1( "ENOIMRUNNING" );
  908. n.firstChild().setNodeValue( newPresence );
  909. // kdDebug( 5006 ) << "value of content is now " << n.firstChild().nodeValue().string() << endl;
  910. }
  911. // kdDebug( 5006 ) << "and we updated the above presence nodes" << uid << endl;
  912. }
  913. void KMReaderWin::setAttachmentStrategy( const AttachmentStrategy * strategy ) {
  914. mAttachmentStrategy = strategy ? strategy : AttachmentStrategy::smart();
  915. update( true );
  916. }
  917. void KMReaderWin::setHeaderStyleAndStrategy( const HeaderStyle * style,
  918. const HeaderStrategy * strategy ) {
  919. mHeaderStyle = style ? style : HeaderStyle::fancy();
  920. mHeaderStrategy = strategy ? strategy : HeaderStrategy::rich();
  921. if ( mHeaderOnlyAttachmentsAction ) {
  922. const bool styleHasAttachmentQuickList = mHeaderStyle == HeaderStyle::fancy() ||
  923. mHeaderStyle == HeaderStyle::enterprise();
  924. mHeaderOnlyAttachmentsAction->setEnabled( styleHasAttachmentQuickList );
  925. if ( !styleHasAttachmentQuickList && mAttachmentStrategy == AttachmentStrategy::headerOnly() ) {
  926. // Style changed to something without an attachment quick list, need to change attachment
  927. // strategy
  928. setAttachmentStrategy( AttachmentStrategy::smart() );
  929. }
  930. }
  931. update( true );
  932. }
  933. //-----------------------------------------------------------------------------
  934. void KMReaderWin::setOverrideEncoding( const TQString & encoding )
  935. {
  936. if ( encoding == mOverrideEncoding )
  937. return;
  938. mOverrideEncoding = encoding;
  939. if ( mSelectEncodingAction ) {
  940. if ( encoding.isEmpty() ) {
  941. mSelectEncodingAction->setCurrentItem( 0 );
  942. }
  943. else {
  944. TQStringList encodings = mSelectEncodingAction->items();
  945. uint i = 0;
  946. for ( TQStringList::const_iterator it = encodings.begin(), end = encodings.end(); it != end; ++it, ++i ) {
  947. if ( TDEGlobal::charsets()->encodingForName( *it ) == encoding ) {
  948. mSelectEncodingAction->setCurrentItem( i );
  949. break;
  950. }
  951. }
  952. if ( i == encodings.size() ) {
  953. // the value of encoding is unknown => use Auto
  954. kdWarning(5006) << "Unknown override character encoding \"" << encoding
  955. << "\". Using Auto instead." << endl;
  956. mSelectEncodingAction->setCurrentItem( 0 );
  957. mOverrideEncoding = TQString();
  958. }
  959. }
  960. }
  961. update( true );
  962. }
  963. void KMReaderWin::setPrintFont( const TQFont& font )
  964. {
  965. mCSSHelper->setPrintFont( font );
  966. }
  967. //-----------------------------------------------------------------------------
  968. const TQTextCodec * KMReaderWin::overrideCodec() const
  969. {
  970. if ( mOverrideEncoding.isEmpty() || mOverrideEncoding == "Auto" ) // Auto
  971. return 0;
  972. else
  973. return KMMsgBase::codecForName( mOverrideEncoding.latin1() );
  974. }
  975. //-----------------------------------------------------------------------------
  976. void KMReaderWin::slotSetEncoding()
  977. {
  978. if ( mSelectEncodingAction->currentItem() == 0 ) // Auto
  979. mOverrideEncoding = TQString();
  980. else
  981. mOverrideEncoding = TDEGlobal::charsets()->encodingForName( mSelectEncodingAction->currentText() );
  982. update( true );
  983. }
  984. //-----------------------------------------------------------------------------
  985. void KMReaderWin::readGlobalOverrideCodec()
  986. {
  987. // if the global character encoding wasn't changed then there's nothing to do
  988. if ( GlobalSettings::self()->overrideCharacterEncoding() == mOldGlobalOverrideEncoding )
  989. return;
  990. setOverrideEncoding( GlobalSettings::self()->overrideCharacterEncoding() );
  991. mOldGlobalOverrideEncoding = GlobalSettings::self()->overrideCharacterEncoding();
  992. }
  993. //-----------------------------------------------------------------------------
  994. void KMReaderWin::setOriginalMsg( unsigned long serNumOfOriginalMessage, int nodeIdOffset )
  995. {
  996. mSerNumOfOriginalMessage = serNumOfOriginalMessage;
  997. mNodeIdOffset = nodeIdOffset;
  998. }
  999. //-----------------------------------------------------------------------------
  1000. void KMReaderWin::setMsg( KMMessage* aMsg, bool force, bool updateOnly )
  1001. {
  1002. if ( aMsg ) {
  1003. kdDebug(5006) << "(" << aMsg->getMsgSerNum() << ", last " << mLastSerNum << ") " << aMsg->subject() << " "
  1004. << aMsg->fromStrip() << ", readyToShow " << (aMsg->readyToShow()) << endl;
  1005. }
  1006. // Reset message-transient state
  1007. if ( aMsg && aMsg->getMsgSerNum() != mLastSerNum && !updateOnly ){
  1008. mLevelQuote = GlobalSettings::self()->collapseQuoteLevelSpin()-1;
  1009. mShowRawToltecMail = !GlobalSettings::self()->showToltecReplacementText();
  1010. clearBodyPartMementos();
  1011. }
  1012. if ( mPrinting )
  1013. mLevelQuote = -1;
  1014. bool complete = true;
  1015. if ( aMsg &&
  1016. !aMsg->readyToShow() &&
  1017. (aMsg->getMsgSerNum() != mLastSerNum) &&
  1018. !aMsg->isComplete() )
  1019. complete = false;
  1020. // If not forced and there is aMsg and aMsg is same as mMsg then return
  1021. if (!force && aMsg && mLastSerNum != 0 && aMsg->getMsgSerNum() == mLastSerNum)
  1022. return;
  1023. // (de)register as observer
  1024. if (aMsg && message())
  1025. message()->detach( this );
  1026. if (aMsg)
  1027. aMsg->attach( this );
  1028. mAtmUpdate = false;
  1029. mDelayedMarkTimer.stop();
  1030. mMessage = 0;
  1031. if ( !aMsg ) {
  1032. mWaitingForSerNum = 0; // otherwise it has been set
  1033. mLastSerNum = 0;
  1034. } else {
  1035. mLastSerNum = aMsg->getMsgSerNum();
  1036. // Check if the serial number can be used to find the assoc KMMessage
  1037. // If so, keep only the serial number (and not mMessage), to avoid a dangling mMessage
  1038. // when going to another message in the mainwindow.
  1039. // Otherwise, keep only mMessage, this is fine for standalone KMReaderMainWins since
  1040. // we're working on a copy of the KMMessage, which we own.
  1041. if (message() != aMsg) {
  1042. mMessage = aMsg;
  1043. mLastSerNum = 0;
  1044. }
  1045. }
  1046. if (aMsg) {
  1047. aMsg->setOverrideCodec( overrideCodec() );
  1048. aMsg->setDecodeHTML( htmlMail() );
  1049. // FIXME: workaround to disable DND for IMAP load-on-demand
  1050. if ( !aMsg->isComplete() )
  1051. mViewer->setDNDEnabled( false );
  1052. else
  1053. mViewer->setDNDEnabled( true );
  1054. }
  1055. // only display the msg if it is complete
  1056. // otherwise we'll get flickering with progressively loaded messages
  1057. if ( complete )
  1058. {
  1059. // Avoid flicker, somewhat of a cludge
  1060. if (force) {
  1061. // stop the timer to avoid calling updateReaderWin twice
  1062. mUpdateReaderWinTimer.stop();
  1063. updateReaderWin();
  1064. }
  1065. else if (mUpdateReaderWinTimer.isActive())
  1066. mUpdateReaderWinTimer.changeInterval( delay );
  1067. else
  1068. mUpdateReaderWinTimer.start( 0, true );
  1069. }
  1070. if ( aMsg && (aMsg->isUnread() || aMsg->isNew()) && GlobalSettings::self()->delayedMarkAsRead() ) {
  1071. if ( GlobalSettings::self()->delayedMarkTime() != 0 )
  1072. mDelayedMarkTimer.start( GlobalSettings::self()->delayedMarkTime() * 1000, true );
  1073. else
  1074. slotTouchMessage();
  1075. }
  1076. mHeaderRefreshTimer.start( 1000, false );
  1077. }
  1078. //-----------------------------------------------------------------------------
  1079. void KMReaderWin::clearCache()
  1080. {
  1081. mUpdateReaderWinTimer.stop();
  1082. clear();
  1083. mDelayedMarkTimer.stop();
  1084. mLastSerNum = 0;
  1085. mWaitingForSerNum = 0;
  1086. mMessage = 0;
  1087. }
  1088. // enter items for the "Important changes" list here:
  1089. static const char * const kmailChanges[] = {
  1090. ""
  1091. };
  1092. static const int numKMailChanges =
  1093. sizeof kmailChanges / sizeof *kmailChanges;
  1094. // enter items for the "new features" list here, so the main body of
  1095. // the welcome page can be left untouched (probably much easier for
  1096. // the translators). Note that the <li>...</li> tags are added
  1097. // automatically below:
  1098. static const char * const kmailNewFeatures[] = {
  1099. I18N_NOOP("Full namespace support for IMAP"),
  1100. I18N_NOOP("Offline mode"),
  1101. I18N_NOOP("Sieve script management and editing"),
  1102. I18N_NOOP("Account specific filtering"),
  1103. I18N_NOOP("Filtering of incoming mail for online IMAP accounts"),
  1104. I18N_NOOP("Online IMAP folders can be used when filtering into folders"),
  1105. I18N_NOOP("Automatically delete older mails on POP servers")
  1106. };
  1107. static const int numKMailNewFeatures =
  1108. sizeof kmailNewFeatures / sizeof *kmailNewFeatures;
  1109. //-----------------------------------------------------------------------------
  1110. //static
  1111. TQString KMReaderWin::newFeaturesMD5()
  1112. {
  1113. TQCString str;
  1114. for ( int i = 0 ; i < numKMailChanges ; ++i )
  1115. str += kmailChanges[i];
  1116. for ( int i = 0 ; i < numKMailNewFeatures ; ++i )
  1117. str += kmailNewFeatures[i];
  1118. KMD5 md5( str );
  1119. return md5.base64Digest();
  1120. }
  1121. //-----------------------------------------------------------------------------
  1122. void KMReaderWin::displaySplashPage( const TQString &info )
  1123. {
  1124. mMsgDisplay = false;
  1125. adjustLayout();
  1126. TQString location = locate("data", "kmail/about/main.html");
  1127. TQString content = KPIM::kFileToString(location);
  1128. content = content.arg( locate( "data", "libtdepim/about/kde_infopage.css" ) );
  1129. if ( kapp->reverseLayout() )
  1130. content = content.arg( "@import \"%1\";" ).arg( locate( "data", "libtdepim/about/kde_infopage_rtl.css" ) );
  1131. else
  1132. content = content.arg( "" );
  1133. mViewer->begin(KURL( location ));
  1134. TQString fontSize = TQString::number( pointsToPixel( mCSSHelper->bodyFont().pointSize() ) );
  1135. TQString appTitle = i18n("KMail");
  1136. TQString catchPhrase = ""; //not enough space for a catch phrase at default window size i18n("Part of the Kontact Suite");
  1137. TQString quickDescription = i18n("The email client for the Trinity Desktop Environment.");
  1138. mViewer->write(content.arg(fontSize).arg(appTitle).arg(catchPhrase).arg(quickDescription).arg(info));
  1139. mViewer->end();
  1140. }
  1141. void KMReaderWin::displayBusyPage()
  1142. {
  1143. TQString info =
  1144. i18n( "<h2 style='margin-top: 0px;'>Retrieving Folder Contents</h2><p>Please wait . . .</p>&nbsp;" );
  1145. displaySplashPage( info );
  1146. }
  1147. void KMReaderWin::displayOfflinePage()
  1148. {
  1149. TQString info =
  1150. i18n( "<h2 style='margin-top: 0px;'>Offline</h2><p>KMail is currently in offline mode. "
  1151. "Click <a href=\"kmail:goOnline\">here</a> to go online . . .</p>&nbsp;" );
  1152. displaySplashPage( info );
  1153. }
  1154. //-----------------------------------------------------------------------------
  1155. void KMReaderWin::displayAboutPage()
  1156. {
  1157. TQString info =
  1158. i18n("%1: KMail version; %2: help:// URL; %3: homepage URL; "
  1159. "%4: prior KMail version; %5: prior TDE version; "
  1160. "%6: generated list of new features; "
  1161. "%7: First-time user text (only shown on first start); "
  1162. "%8: generated list of important changes; "
  1163. "--- end of comment ---",
  1164. "<h2 style='margin-top: 0px;'>Welcome to KMail %1</h2><p>KMail is the email client for the K "
  1165. "Desktop Environment. It is designed to be fully compatible with "
  1166. "Internet mailing standards including MIME, SMTP, POP3 and IMAP."
  1167. "</p>\n"
  1168. "<ul><li>KMail has many powerful features which are described in the "
  1169. "<a href=\"%2\">documentation</a></li>\n"
  1170. "<li>The <a href=\"%3\">KMail homepage</A> offers information about "
  1171. "new versions of KMail</li></ul>\n"
  1172. "%8\n" // important changes
  1173. "<p>Some of the new features in this release of KMail include "
  1174. "(compared to KMail %4, which is part of TDE %5):</p>\n"
  1175. "<ul>\n%6</ul>\n"
  1176. "%7\n"
  1177. "<p>We hope that you will enjoy KMail.</p>\n"
  1178. "<p>Thank you,</p>\n"
  1179. "<p style='margin-bottom: 0px'>&nbsp; &nbsp; The KMail Team</p>")
  1180. .arg(KMAIL_VERSION) // KMail version
  1181. .arg("help:/kmail/index.html") // KMail help:// URL
  1182. .arg("http://kontact.kde.org/kmail/") // KMail homepage URL
  1183. .arg("1.8").arg("3.4"); // prior KMail and TDE version
  1184. TQString featureItems;
  1185. for ( int i = 0 ; i < numKMailNewFeatures ; i++ )
  1186. featureItems += i18n("<li>%1</li>\n").arg( i18n( kmailNewFeatures[i] ) );
  1187. info = info.arg( featureItems );
  1188. if( kmkernel->firstStart() ) {
  1189. info = info.arg( i18n("<p>Please take a moment to fill in the KMail "
  1190. "configuration panel at Settings-&gt;Configure "
  1191. "KMail.\n"
  1192. "You need to create at least a default identity and "
  1193. "an incoming as well as outgoing mail account."
  1194. "</p>\n") );
  1195. } else {
  1196. info = info.arg( TQString() );
  1197. }
  1198. if ( ( numKMailChanges > 1 ) || ( numKMailChanges == 1 && strlen(kmailChanges[0]) > 0 ) ) {
  1199. TQString changesText =
  1200. i18n("<p><span style='font-size:125%; font-weight:bold;'>"
  1201. "Important changes</span> (compared to KMail %1):</p>\n")
  1202. .arg("1.8");
  1203. changesText += "<ul>\n";
  1204. for ( int i = 0 ; i < numKMailChanges ; i++ )
  1205. changesText += i18n("<li>%1</li>\n").arg( i18n( kmailChanges[i] ) );
  1206. changesText += "</ul>\n";
  1207. info = info.arg( changesText );
  1208. }
  1209. else
  1210. info = info.arg(""); // remove the %8
  1211. displaySplashPage( info );
  1212. }
  1213. void KMReaderWin::enableMsgDisplay() {
  1214. mMsgDisplay = true;
  1215. adjustLayout();
  1216. }
  1217. //-----------------------------------------------------------------------------
  1218. void KMReaderWin::updateReaderWin()
  1219. {
  1220. if (!mMsgDisplay) return;
  1221. mViewer->setOnlyLocalReferences(!htmlLoadExternal());
  1222. htmlWriter()->reset();
  1223. KMFolder* folder = 0;
  1224. if (message(&folder))
  1225. {
  1226. if ( mShowColorbar )
  1227. mColorBar->show();
  1228. else
  1229. mColorBar->hide();
  1230. displayMessage();
  1231. }
  1232. else
  1233. {
  1234. mColorBar->hide();
  1235. mMimePartTree->hide();
  1236. mMimePartTree->clear();
  1237. htmlWriter()->begin( mCSSHelper->cssDefinitions( isFixedFont() ) );
  1238. htmlWriter()->write( mCSSHelper->htmlHead( isFixedFont() ) + "</body></html>" );
  1239. htmlWriter()->end();
  1240. }
  1241. if (mSavedRelativePosition)
  1242. {
  1243. TQScrollView * scrollview = static_cast<TQScrollView *>(mViewer->widget());
  1244. scrollview->setContentsPos( 0,
  1245. tqRound( scrollview->contentsHeight() * mSavedRelativePosition ) );
  1246. mSavedRelativePosition = 0;
  1247. }
  1248. }
  1249. //-----------------------------------------------------------------------------
  1250. int KMReaderWin::pointsToPixel(int pointSize) const
  1251. {
  1252. const TQPaintDeviceMetrics pdm(mViewer->view());
  1253. return (pointSize * pdm.logicalDpiY() + 36) / 72;
  1254. }
  1255. //-----------------------------------------------------------------------------
  1256. void KMReaderWin::showHideMimeTree( bool isPlainTextTopLevel ) {
  1257. if ( mMimeTreeMode == 2 ||
  1258. ( mMimeTreeMode == 1 && !isPlainTextTopLevel ) )
  1259. mMimePartTree->show();
  1260. else {
  1261. // don't rely on TQSplitter maintaining sizes for hidden widgets:
  1262. TDEConfigGroup reader( KMKernel::config(), "Reader" );
  1263. saveSplitterSizes( reader );
  1264. mMimePartTree->hide();
  1265. }
  1266. }
  1267. void KMReaderWin::displayMessage() {
  1268. KMMessage * msg = message();
  1269. mMimePartTree->clear();
  1270. showHideMimeTree( !msg || // treat no message as "text/plain"
  1271. ( msg->type() == DwMime::kTypeText
  1272. && msg->subtype() == DwMime::kSubtypePlain ) );
  1273. if ( !msg )
  1274. return;
  1275. msg->setOverrideCodec( overrideCodec() );
  1276. htmlWriter()->begin( mCSSHelper->cssDefinitions( isFixedFont() ) );
  1277. htmlWriter()->queue( mCSSHelper->htmlHead( isFixedFont() ) );
  1278. if (!parent())
  1279. setCaption(msg->subject());
  1280. removeTempFiles();
  1281. mColorBar->setNeutralMode();
  1282. parseMsg(msg);
  1283. if( mColorBar->isNeutral() )
  1284. mColorBar->setNormalMode();
  1285. htmlWriter()->queue("</body></html>");
  1286. htmlWriter()->flush();
  1287. TQTimer::singleShot( 1, TQT_TQOBJECT(this), TQT_SLOT(injectAttachments()) );
  1288. }
  1289. static bool message_was_saved_decrypted_before( const KMMessage * msg ) {
  1290. if ( !msg )
  1291. return false;
  1292. //kdDebug(5006) << "msgId = " << msg->msgId() << endl;
  1293. return msg->msgId().stripWhiteSpace().startsWith( "<DecryptedMsg." );
  1294. }
  1295. //-----------------------------------------------------------------------------
  1296. void KMReaderWin::parseMsg(KMMessage* aMsg)
  1297. {
  1298. KMMessagePart msgPart;
  1299. TQCString subtype, contDisp;
  1300. TQByteArray str;
  1301. assert(aMsg!=0);
  1302. aMsg->setIsBeingParsed( true );
  1303. if ( mRootNode && !mRootNode->processed() )
  1304. {
  1305. kdWarning() << "The root node is not yet processed! Danger!\n";
  1306. return;
  1307. } else
  1308. delete mRootNode;
  1309. mRootNode = partNode::fromMessage( aMsg, this );
  1310. const TQCString mainCntTypeStr = mRootNode->typeString() + '/' + mRootNode->subTypeString();
  1311. TQString cntDesc = aMsg->subject();
  1312. if( cntDesc.isEmpty() )
  1313. cntDesc = i18n("( body part )");
  1314. TDEIO::filesize_t cntSize = aMsg->msgSize();
  1315. TQString cntEnc;
  1316. if( aMsg->contentTransferEncodingStr().isEmpty() )
  1317. cntEnc = "7bit";
  1318. else
  1319. cntEnc = aMsg->contentTransferEncodingStr();
  1320. // fill the MIME part tree viewer
  1321. mRootNode->fillMimePartTree( 0,
  1322. mMimePartTree,
  1323. cntDesc,
  1324. mainCntTypeStr,
  1325. cntEnc,
  1326. cntSize );
  1327. partNode* vCardNode = mRootNode->findType( DwMime::kTypeText, DwMime::kSubtypeXVCard );
  1328. bool hasVCard = false;
  1329. if( vCardNode ) {
  1330. // ### FIXME: We should only do this if the vCard belongs to the sender,
  1331. // ### i.e. if the sender's email address is contained in the vCard.
  1332. TDEABC::VCardConverter t;
  1333. #if defined(KABC_VCARD_ENCODING_FIX)
  1334. const TQByteArray vcard = vCardNode->msgPart().bodyDecodedBinary();
  1335. if ( !t.parseVCardsRaw( vcard.data() ).empty() ) {
  1336. #else
  1337. const TQString vcard = vCardNode->msgPart().bodyToUnicode( overrideCodec() );
  1338. if ( !t.parseVCards( vcard ).empty() ) {
  1339. #endif
  1340. hasVCard = true;
  1341. writeMessagePartToTempFile( &vCardNode->msgPart(), vCardNode->nodeId() );
  1342. }
  1343. }
  1344. if ( !mRootNode || !mRootNode->isToltecMessage() || mShowRawToltecMail ) {
  1345. htmlWriter()->queue( writeMsgHeader(aMsg, hasVCard ? vCardNode : 0, true ) );
  1346. }
  1347. // show message content
  1348. ObjectTreeParser otp( this );
  1349. otp.setAllowAsync( true );
  1350. otp.setShowRawToltecMail( mShowRawToltecMail );
  1351. otp.parseObjectTree( mRootNode );
  1352. // store encrypted/signed status information in the KMMessage
  1353. // - this can only be done *after* calling parseObjectTree()
  1354. KMMsgEncryptionState encryptionState = mRootNode->overallEncryptionState();
  1355. KMMsgSignatureState signatureState = mRootNode->overallSignatureState();
  1356. // Don't crash when switching message while GPG passphrase entry dialog is shown #53185
  1357. if (aMsg != message()) {
  1358. displayMessage();
  1359. return;
  1360. }
  1361. aMsg->setEncryptionState( encryptionState );
  1362. // Don't reset the signature state to "not signed" (e.g. if one canceled the
  1363. // decryption of a signed messages which has already been decrypted before).
  1364. if ( signatureState != KMMsgNotSigned ||
  1365. aMsg->signatureState() == KMMsgSignatureStateUnknown ) {
  1366. aMsg->setSignatureState( signatureState );
  1367. }
  1368. bool emitReplaceMsgByUnencryptedVersion = false;
  1369. const TDEConfigGroup reader( KMKernel::config(), "Reader" );
  1370. if ( reader.readBoolEntry( "store-displayed-messages-unencrypted", false ) ) {
  1371. // Hack to make sure the S/MIME CryptPlugs follows the strict requirement
  1372. // of german government:
  1373. // --> All received encrypted messages *must* be stored in unencrypted form
  1374. // after they have been decrypted once the user has read them.
  1375. // ( "Aufhebung der Verschluesselung nach dem Lesen" )
  1376. //
  1377. // note: Since there is no configuration option for this, we do that for
  1378. // all kinds of encryption now - *not* just for S/MIME.
  1379. // This could be changed in the objectTreeToDecryptedMsg() function
  1380. // by deciding when (or when not, resp.) to set the 'dataNode' to
  1381. // something different than 'curNode'.
  1382. kdDebug(5006) << "\n\n\nKMReaderWin::parseMsg() - special post-encryption handling:\n1." << endl;
  1383. kdDebug(5006) << "(aMsg == msg) = " << (aMsg == message()) << endl;
  1384. kdDebug(5006) << "aMsg->parent() && aMsg->parent() != kmkernel->outboxFolder() = " << (aMsg->parent() && aMsg->parent() != kmkernel->outboxFolder()) << endl;
  1385. kdDebug(5006) << "message_was_saved_decrypted_before( aMsg ) = " << message_was_saved_decrypted_before( aMsg ) << endl;
  1386. kdDebug(5006) << "this->decryptMessage() = " << decryptMessage() << endl;
  1387. kdDebug(5006) << "otp.hasPendingAsyncJobs() = " << otp.hasPendingAsyncJobs() << endl;
  1388. kdDebug(5006) << " (KMMsgFullyEncrypted == encryptionState) = " << (KMMsgFullyEncrypted == encryptionState) << endl;
  1389. kdDebug(5006) << "|| (KMMsgPartiallyEncrypted == encryptionState) = " << (KMMsgPartiallyEncrypted == encryptionState) << endl;
  1390. // only proceed if we were called the normal way - not by
  1391. // double click on the message (==not running in a separate window)
  1392. if( (aMsg == message())
  1393. // don't remove encryption in the outbox folder :)
  1394. && ( aMsg->parent() && aMsg->parent() != kmkernel->outboxFolder() )
  1395. // only proceed if this message was not saved encryptedly before
  1396. && !message_was_saved_decrypted_before( aMsg )
  1397. // only proceed if the message has actually been decrypted
  1398. && decryptMessage()
  1399. // only proceed if no pending async jobs are running:
  1400. && !otp.hasPendingAsyncJobs()
  1401. // only proceed if this message is (at least partially) encrypted
  1402. && ( (KMMsgFullyEncrypted == encryptionState)
  1403. || (KMMsgPartiallyEncrypted == encryptionState) ) ) {
  1404. kdDebug(5006) << "KMReaderWin - calling objectTreeToDecryptedMsg()" << endl;
  1405. NewByteArray decryptedData;
  1406. // note: The following call may change the message's headers.
  1407. objectTreeToDecryptedMsg( mRootNode, decryptedData, *aMsg );
  1408. // add a \0 to the data
  1409. decryptedData.appendNULL();
  1410. TQCString resultString( decryptedData.data() );
  1411. kdDebug(5006) << "KMReaderWin - resulting data:" << resultString << endl;
  1412. if( !resultString.isEmpty() ) {
  1413. kdDebug(5006) << "KMReaderWin - composing unencrypted message" << endl;
  1414. // try this:
  1415. aMsg->setBody( resultString );
  1416. KMMessage* unencryptedMessage = new KMMessage( *aMsg );
  1417. unencryptedMessage->setParent( 0 );
  1418. // because this did not work:
  1419. /*
  1420. DwMessage dwMsg( aMsg->asDwString() );
  1421. dwMsg.Body() = DwBody( DwString( resultString.data() ) );
  1422. dwMsg.Body().Parse();
  1423. KMMessage* unencryptedMessage = new KMMessage( &dwMsg );
  1424. */
  1425. //kdDebug(5006) << "KMReaderWin - resulting message:" << unencryptedMessage->asString() << endl;
  1426. kdDebug(5006) << "KMReaderWin - attach unencrypted message to aMsg" << endl;
  1427. aMsg->setUnencryptedMsg( unencryptedMessage );
  1428. emitReplaceMsgByUnencryptedVersion = true;
  1429. }
  1430. }
  1431. }
  1432. // save current main Content-Type before deleting mRootNode
  1433. const int rootNodeCntType = mRootNode ? mRootNode->type() : DwMime::kTypeText;
  1434. const int rootNodeCntSubtype = mRootNode ? mRootNode->subType() : DwMime::kSubtypePlain;
  1435. // store message id to avoid endless recursions
  1436. setIdOfLastViewedMessage( aMsg->msgId() );
  1437. if( emitReplaceMsgByUnencryptedVersion ) {
  1438. kdDebug(5006) << "KMReaderWin - invoce saving in decrypted form:" << endl;
  1439. emit replaceMsgByUnencryptedVersion();
  1440. } else {
  1441. kdDebug(5006) << "KMReaderWin - finished parsing and displaying of message." << endl;
  1442. showHideMimeTree( rootNodeCntType == DwMime::kTypeText &&
  1443. rootNodeCntSubtype == DwMime::kSubtypePlain );
  1444. }
  1445. aMsg->setIsBeingParsed( false );
  1446. }
  1447. //-----------------------------------------------------------------------------
  1448. void KMReaderWin::updateHeader()
  1449. {
  1450. /*
  1451. * TODO: mess around with TDEHTML DOM some more and figure out how to
  1452. * replace the entire header div w/out flickering to hell and back
  1453. *
  1454. * DOM::NodeList divs(mViewer->document().documentElement().getElementsByTagName("div"));
  1455. * static_cast<DOM::HTMLDivElement>(divs.item(0)).setInnerHTML(writeMsgHeader());
  1456. */
  1457. KMMessage* currentMessage = message();
  1458. if (currentMessage &&
  1459. mHeaderStyle == HeaderStyle::fancy() &&
  1460. currentMessage->parent())
  1461. {
  1462. int i;
  1463. int divNumber = -1;
  1464. DOM::NodeList divs(mViewer->document().documentElement().getElementsByTagName("div"));
  1465. DOM::NodeList headerDivs(static_cast<DOM::HTMLDivElement>(divs.item(0)).getElementsByTagName("div"));
  1466. for (i=0; i<((int)headerDivs.length()); i++) {
  1467. if (static_cast<DOM::HTMLDivElement>(headerDivs.item(i)).id().string() == "sendersCurrentTime") {
  1468. divNumber = i;
  1469. break;
  1470. }
  1471. }
  1472. if (divNumber >= 0) {
  1473. DOM::HTMLDivElement elem = static_cast<DOM::HTMLDivElement>(headerDivs.item(i));
  1474. // HACK
  1475. // Get updated time information
  1476. TQString latestHeader = headerStyle()->format( currentMessage, headerStrategy(), "", mPrinting, false );
  1477. int startPos = latestHeader.find("<div id=\"sendersCurrentTime\" style=\"");
  1478. if (startPos >= 0) {
  1479. latestHeader = latestHeader.mid(startPos);
  1480. int endPos = latestHeader.find("</div>");
  1481. if (endPos >= 0) {
  1482. endPos = endPos + 6;
  1483. latestHeader.truncate(endPos);
  1484. TQString divText = latestHeader;
  1485. TQString divStyle = latestHeader;
  1486. divText = divText.mid(divText.find(">")+1);
  1487. divText.truncate(divText.find("</div>"));
  1488. divStyle = divStyle.mid(TQString("<div id=\"sendersCurrentTime\" style=\"").length());
  1489. divStyle.truncate(divStyle.find("\""));
  1490. elem.setInnerHTML(divText);
  1491. elem.setAttribute("style", divStyle);
  1492. elem.applyChanges();
  1493. }
  1494. }
  1495. }
  1496. }
  1497. }
  1498. //-----------------------------------------------------------------------------
  1499. TQString KMReaderWin::writeMsgHeader( KMMessage* aMsg, partNode *vCardNode, bool topLevel )
  1500. {
  1501. kdFatal( !headerStyle(), 5006 )
  1502. << "trying to writeMsgHeader() without a header style set!" << endl;
  1503. kdFatal( !headerStrategy(), 5006 )
  1504. << "trying to writeMsgHeader() without a header strategy set!" << endl;
  1505. TQString href;
  1506. if ( vCardNode )
  1507. href = vCardNode->asHREF( "body" );
  1508. return headerStyle()->format( aMsg, headerStrategy(), href, mPrinting, topLevel );
  1509. }
  1510. //-----------------------------------------------------------------------------
  1511. TQString KMReaderWin::writeMessagePartToTempFile( KMMessagePart* aMsgPart,
  1512. int aPartNum )
  1513. {
  1514. TQString fileName = aMsgPart->fileName();
  1515. if( fileName.isEmpty() )
  1516. fileName = aMsgPart->name();
  1517. //--- Sven's save attachments to /tmp start ---
  1518. TQString fname = createTempDir( TQString::number( aPartNum ) );
  1519. if ( fname.isEmpty() )
  1520. return TQString();
  1521. // strip off a leading path
  1522. int slashPos = fileName.findRev( '/' );
  1523. if( -1 != slashPos )
  1524. fileName = fileName.mid( slashPos + 1 );
  1525. if( fileName.isEmpty() )
  1526. fileName = "unnamed";
  1527. fname += "/" + fileName;
  1528. TQByteArray data = aMsgPart->bodyDecodedBinary();
  1529. size_t size = data.size();
  1530. if ( aMsgPart->type() == DwMime::kTypeText && size) {
  1531. // convert CRLF to LF before writing text attachments to disk
  1532. size = KMail::Util::crlf2lf( data.data(), size );
  1533. }
  1534. if( !KPIM::kBytesToFile( data.data(), size, fname, false, false, false ) )
  1535. return TQString();
  1536. mTempFiles.append( fname );
  1537. // make file read-only so that nobody gets the impression that he might
  1538. // edit attached files (cf. bug #52813)
  1539. ::chmod( TQFile::encodeName( fname ), S_IRUSR );
  1540. return fname;
  1541. }
  1542. TQString KMReaderWin::createTempDir( const TQString &param )
  1543. {
  1544. KTempFile *tempFile = new KTempFile( TQString(), "." + param );
  1545. tempFile->setAutoDelete( true );
  1546. TQString fname = tempFile->name();
  1547. delete tempFile;
  1548. if( ::access( TQFile::encodeName( fname ), W_OK ) != 0 )
  1549. // Not there or not writable
  1550. if( ::mkdir( TQFile::encodeName( fname ), 0 ) != 0
  1551. || ::chmod( TQFile::encodeName( fname ), S_IRWXU ) != 0 )
  1552. return TQString(); //failed create
  1553. assert( !fname.isNull() );
  1554. mTempDirs.append( fname );
  1555. return fname;
  1556. }
  1557. //-----------------------------------------------------------------------------
  1558. void KMReaderWin::showVCard( KMMessagePart *msgPart )
  1559. {
  1560. #if defined(KABC_VCARD_ENCODING_FIX)
  1561. const TQByteArray vCard = msgPart->bodyDecodedBinary();
  1562. #else
  1563. const TQString vCard = msgPart->bodyToUnicode( overrideCodec() );
  1564. #endif
  1565. VCardViewer *vcv = new VCardViewer( this, vCard, "vCardDialog" );
  1566. vcv->show();
  1567. }
  1568. //-----------------------------------------------------------------------------
  1569. void KMReaderWin::printMsg()
  1570. {
  1571. if (!message()) return;
  1572. mViewer->view()->print();
  1573. }
  1574. //-----------------------------------------------------------------------------
  1575. int KMReaderWin::msgPartFromUrl(const KURL &aUrl)
  1576. {
  1577. if (aUrl.isEmpty()) return -1;
  1578. if (!aUrl.isLocalFile()) return -1;
  1579. TQString path = aUrl.path();
  1580. uint right = path.findRev('/');
  1581. uint left = path.findRev('.', right);
  1582. bool ok;
  1583. int res = path.mid(left + 1, right - left - 1).toInt(&ok);
  1584. return (ok) ? res : -1;
  1585. }
  1586. //-----------------------------------------------------------------------------
  1587. void KMReaderWin::resizeEvent(TQResizeEvent *)
  1588. {
  1589. if( !mResizeTimer.isActive() )
  1590. {
  1591. //
  1592. // Combine all resize operations that are requested as long a
  1593. // the timer runs.
  1594. //
  1595. mResizeTimer.start( 100, true );
  1596. }
  1597. }
  1598. //-----------------------------------------------------------------------------
  1599. void KMReaderWin::slotDelayedResize()
  1600. {
  1601. mSplitter->setGeometry(0, 0, width(), height());
  1602. }
  1603. //-----------------------------------------------------------------------------
  1604. void KMReaderWin::slotTouchMessage()
  1605. {
  1606. if ( !message() )
  1607. return;
  1608. if ( !message()->isNew() && !message()->isUnread() )
  1609. return;
  1610. SerNumList serNums;
  1611. serNums.append( message()->getMsgSerNum() );
  1612. KMCommand *command = new KMSeStatusCommand( KMMsgStatusRead, serNums );
  1613. command->start();
  1614. // should we send an MDN?
  1615. if ( mNoMDNsWhenEncrypted &&
  1616. message()->encryptionState() != KMMsgNotEncrypted &&
  1617. message()->encryptionState() != KMMsgEncryptionStateUnknown )
  1618. return;
  1619. KMFolder *folder = message()->parent();
  1620. if (folder &&
  1621. (folder->isOutbox() || folder->isSent() || folder->isTrash() ||
  1622. folder->isDrafts() || folder->isTemplates() ) )
  1623. return;
  1624. if ( KMMessage * receipt = message()->createMDN( MDN::ManualAction,
  1625. MDN::Displayed,
  1626. true /* allow GUI */ ) )
  1627. if ( !kmkernel->msgSender()->send( receipt ) ) // send or queue
  1628. KMessageBox::error( this, i18n("Could not send MDN.") );
  1629. }
  1630. //-----------------------------------------------------------------------------
  1631. void KMReaderWin::closeEvent(TQCloseEvent *e)
  1632. {
  1633. TQWidget::closeEvent(e);
  1634. writeConfig();
  1635. }
  1636. bool foundSMIMEData( const TQString aUrl,
  1637. TQString& displayName,
  1638. TQString& libName,
  1639. TQString& keyId )
  1640. {
  1641. static TQString showCertMan("showCertificate#");
  1642. displayName = "";
  1643. libName = "";
  1644. keyId = "";
  1645. int i1 = aUrl.find( showCertMan );
  1646. if( -1 < i1 ) {
  1647. i1 += showCertMan.length();
  1648. int i2 = aUrl.find(" ### ", i1);
  1649. if( i1 < i2 )
  1650. {
  1651. displayName = aUrl.mid( i1, i2-i1 );
  1652. i1 = i2+5;
  1653. i2 = aUrl.find(" ### ", i1);
  1654. if( i1 < i2 )
  1655. {
  1656. libName = aUrl.mid( i1, i2-i1 );
  1657. i2 += 5;
  1658. keyId = aUrl.mid( i2 );
  1659. /*
  1660. int len = aUrl.length();
  1661. if( len > i2+1 ) {
  1662. keyId = aUrl.mid( i2, 2 );
  1663. i2 += 2;
  1664. while( len > i2+1 ) {
  1665. keyId += ':';
  1666. keyId += aUrl.mid( i2, 2 );
  1667. i2 += 2;
  1668. }
  1669. }
  1670. */
  1671. }
  1672. }
  1673. }
  1674. return !keyId.isEmpty();
  1675. }
  1676. //-----------------------------------------------------------------------------
  1677. void KMReaderWin::slotUrlOn(const TQString &aUrl)
  1678. {
  1679. const KURL url(aUrl);
  1680. if ( url.protocol() == "kmail" || url.protocol() == "x-kmail" || url.protocol() == "attachment"
  1681. || (url.protocol().isEmpty() && url.path().isEmpty()) ) {
  1682. mViewer->setDNDEnabled( false );
  1683. } else {
  1684. mViewer->setDNDEnabled( true );
  1685. }
  1686. if ( aUrl.stripWhiteSpace().isEmpty() ) {
  1687. KPIM::BroadcastStatus::instance()->reset();
  1688. mHoveredUrl = KURL();
  1689. mLastClickImagePath = TQString();
  1690. return;
  1691. }
  1692. mHoveredUrl = url;
  1693. const TQString msg = URLHandlerManager::instance()->statusBarMessage( url, this );
  1694. kdWarning( msg.isEmpty(), 5006 ) << "KMReaderWin::slotUrlOn(): Unhandled URL hover!" << endl;
  1695. KPIM::BroadcastStatus::instance()->setTransienStatusMsg( msg );
  1696. }
  1697. //-----------------------------------------------------------------------------
  1698. void KMReaderWin::slotUrlOpen(const KURL &aUrl, const KParts::URLArgs &)
  1699. {
  1700. mClickedUrl = aUrl;
  1701. if ( URLHandlerManager::instance()->handleClick( aUrl, this ) )
  1702. return;
  1703. kdWarning( 5006 ) << "KMReaderWin::slotOpenUrl(): Unhandled URL click!" << endl;
  1704. emit urlClicked( aUrl, Qt::LeftButton );
  1705. }
  1706. //-----------------------------------------------------------------------------
  1707. void KMReaderWin::slotUrlPopup(const TQString &aUrl, const TQPoint& aPos)
  1708. {
  1709. const KURL url( aUrl );
  1710. mClickedUrl = url;
  1711. if ( url.protocol() == "mailto" ) {
  1712. mCopyURLAction->setText( i18n( "Copy Email Address" ) );
  1713. } else {
  1714. mCopyURLAction->setText( i18n( "Copy Link Address" ) );
  1715. }
  1716. if ( URLHandlerManager::instance()->handleContextMenuRequest( url, aPos, this ) )
  1717. return;
  1718. if ( message() ) {
  1719. kdWarning( 5006 ) << "KMReaderWin::slotUrlPopup(): Unhandled URL right-click!" << endl;
  1720. emitPopupMenu( url, aPos );
  1721. }
  1722. }
  1723. // Checks if the given node has a parent node that is a DIV which has an ID attribute
  1724. // with the value specified here
  1725. static bool hasParentDivWithId( const DOM::Node &start, const TQString &id )
  1726. {
  1727. if ( start.isNull() )
  1728. return false;
  1729. if ( start.nodeName().string() == "div" ) {
  1730. for ( unsigned int i = 0; i < start.attributes().length(); i++ ) {
  1731. if ( start.attributes().item( i ).nodeName().string() == "id" &&
  1732. start.attributes().item( i ).nodeValue().string() == id )
  1733. return true;
  1734. }
  1735. }
  1736. if ( !start.parentNode().isNull() )
  1737. return hasParentDivWithId( start.parentNode(), id );
  1738. else return false;
  1739. }
  1740. //-----------------------------------------------------------------------------
  1741. void KMReaderWin::showAttachmentPopup( int id, const TQString & name, const TQPoint & p )
  1742. {
  1743. mAtmCurrent = id;
  1744. mAtmCurrentName = name;
  1745. TDEPopupMenu *menu = new TDEPopupMenu();
  1746. menu->insertItem(SmallIcon("fileopen"),i18n("to open", "Open"), 1);
  1747. menu->insertItem(i18n("Open With..."), 2);
  1748. menu->insertItem(i18n("to view something", "View"), 3);
  1749. menu->insertItem(SmallIcon("filesaveas"),i18n("Save As..."), 4);
  1750. menu->insertItem(SmallIcon("editcopy"), i18n("Copy"), 9 );
  1751. const bool canChange = message()->parent() ? !message()->parent()->isReadOnly() : false;
  1752. if ( GlobalSettings::self()->allowAttachmentEditing() && canChange )
  1753. menu->insertItem(SmallIcon("edit"), i18n("Edit Attachment"), 8 );
  1754. if ( GlobalSettings::self()->allowAttachmentDeletion() && canChange )
  1755. menu->insertItem(SmallIcon("editdelete"), i18n("Delete Attachment"), 7 );
  1756. if ( name.endsWith( ".xia", false ) &&
  1757. Kleo::CryptoBackendFactory::instance()->protocol( "Chiasmus" ) )
  1758. menu->insertItem( i18n( "Decrypt With Chiasmus..." ), 6 );
  1759. menu->insertItem(i18n("Properties"), 5);
  1760. const bool attachmentInHeader = hasParentDivWithId( mViewer->nodeUnderMouse(), "attachmentInjectionPoint" );
  1761. const bool hasScrollbar = mViewer->view()->verticalScrollBar()->isVisible();
  1762. if ( attachmentInHeader && hasScrollbar ) {
  1763. menu->insertItem( i18n("Scroll To"), 10 );
  1764. }
  1765. connect(menu, TQT_SIGNAL(activated(int)), TQT_TQOBJECT(this), TQT_SLOT(slotHandleAttachment(int)));
  1766. menu->exec( p ,0 );
  1767. delete menu;
  1768. }
  1769. //-----------------------------------------------------------------------------
  1770. void KMReaderWin::setStyleDependantFrameWidth()
  1771. {
  1772. if ( !mBox )
  1773. return;
  1774. // set the width of the frame to a reasonable value for the current GUI style
  1775. int frameWidth;
  1776. if( style().isA("KeramikStyle") )
  1777. frameWidth = style().pixelMetric( TQStyle::PM_DefaultFrameWidth ) - 1;
  1778. else
  1779. frameWidth = style().pixelMetric( TQStyle::PM_DefaultFrameWidth );
  1780. if ( frameWidth < 0 )
  1781. frameWidth = 0;
  1782. if ( frameWidth != mBox->lineWidth() )
  1783. mBox->setLineWidth( frameWidth );
  1784. }
  1785. //-----------------------------------------------------------------------------
  1786. void KMReaderWin::styleChange( TQStyle& oldStyle )
  1787. {
  1788. setStyleDependantFrameWidth();
  1789. TQWidget::styleChange( oldStyle );
  1790. }
  1791. //-----------------------------------------------------------------------------
  1792. void KMReaderWin::slotHandleAttachment( int choice )
  1793. {
  1794. mAtmUpdate = true;
  1795. partNode* node = mRootNode ? mRootNode->findId( mAtmCurrent ) : 0;
  1796. if ( mAtmCurrentName.isEmpty() && node )
  1797. mAtmCurrentName = tempFileUrlFromPartNode( node ).path();
  1798. if ( choice < 7 ) {
  1799. KMHandleAttachmentCommand* command = new KMHandleAttachmentCommand(
  1800. node, message(), mAtmCurrent, mAtmCurrentName,
  1801. KMHandleAttachmentCommand::AttachmentAction( choice ), 0, this );
  1802. connect( command, TQT_SIGNAL( showAttachment( int, const TQString& ) ),
  1803. TQT_TQOBJECT(this), TQT_SLOT( slotAtmView( int, const TQString& ) ) );
  1804. command->start();
  1805. } else if ( choice == 7 ) {
  1806. slotDeleteAttachment( node );
  1807. } else if ( choice == 8 ) {
  1808. slotEditAttachment( node );
  1809. } else if ( choice == 9 ) {
  1810. if ( !node ) return;
  1811. KURL::List urls;
  1812. KURL url = tempFileUrlFromPartNode( node );
  1813. if (!url.isValid() ) return;
  1814. urls.append( url );
  1815. KURLDrag* drag = new KURLDrag( urls, this );
  1816. TQApplication::clipboard()->setData( drag, TQClipboard::Clipboard );
  1817. } else if ( choice == 10 ) { // Scroll To
  1818. scrollToAttachment( node );
  1819. }
  1820. }
  1821. //-----------------------------------------------------------------------------
  1822. void KMReaderWin::slotFind()
  1823. {
  1824. mViewer->findText();
  1825. }
  1826. //-----------------------------------------------------------------------------
  1827. void KMReaderWin::slotFindNext()
  1828. {
  1829. mViewer->findTextNext();
  1830. }
  1831. //-----------------------------------------------------------------------------
  1832. void KMReaderWin::slotToggleFixedFont()
  1833. {
  1834. mUseFixedFont = !mUseFixedFont;
  1835. saveRelativePosition();
  1836. update(true);
  1837. }
  1838. //-----------------------------------------------------------------------------
  1839. void KMReaderWin::slotCopySelectedText()
  1840. {
  1841. kapp->clipboard()->setText( mViewer->selectedText() );
  1842. }
  1843. //-----------------------------------------------------------------------------
  1844. void KMReaderWin::atmViewMsg( KMMessagePart* aMsgPart, int nodeId )
  1845. {
  1846. assert(aMsgPart!=0);
  1847. KMMessage* msg = new KMMessage;
  1848. msg->fromString(aMsgPart->bodyDecoded());
  1849. assert(msg != 0);
  1850. msg->setMsgSerNum( 0 ); // because lookups will fail
  1851. // some information that is needed for imap messages with LOD
  1852. msg->setParent( message()->parent() );
  1853. msg->setUID(message()->UID());
  1854. msg->setReadyToShow(true);
  1855. KMReaderMainWin *win = new KMReaderMainWin();
  1856. win->showMsg( overrideEncoding(), msg, message()->getMsgSerNum(), nodeId );
  1857. win->show();
  1858. }
  1859. void KMReaderWin::setMsgPart( partNode * node ) {
  1860. htmlWriter()->reset();
  1861. mColorBar->hide();
  1862. htmlWriter()->begin( mCSSHelper->cssDefinitions( isFixedFont() ) );
  1863. htmlWriter()->write( mCSSHelper->htmlHead( isFixedFont() ) );
  1864. // end ###
  1865. if ( node ) {
  1866. ObjectTreeParser otp( this, 0, true );
  1867. otp.parseObjectTree( node );
  1868. }
  1869. // ### this, too
  1870. htmlWriter()->queue( "</body></html>" );
  1871. htmlWriter()->flush();
  1872. }
  1873. //-----------------------------------------------------------------------------
  1874. void KMReaderWin::setMsgPart( KMMessagePart* aMsgPart, bool aHTML,
  1875. const TQString& aFileName, const TQString& pname )
  1876. {
  1877. KCursorSaver busy(KBusyPtr::busy());
  1878. if (kasciistricmp(aMsgPart->typeStr(), "message")==0) {
  1879. // if called from compose win
  1880. KMMessage* msg = new KMMessage;
  1881. assert(aMsgPart!=0);
  1882. msg->fromString(aMsgPart->bodyDecoded());
  1883. mMainWindow->setCaption(msg->subject());
  1884. setMsg(msg, true);
  1885. setAutoDelete(true);
  1886. } else if (kasciistricmp(aMsgPart->typeStr(), "text")==0) {
  1887. if (kasciistricmp(aMsgPart->subtypeStr(), "x-vcard") == 0) {
  1888. showVCard( aMsgPart );
  1889. return;
  1890. }
  1891. htmlWriter()->begin( mCSSHelper->cssDefinitions( isFixedFont() ) );
  1892. htmlWriter()->queue( mCSSHelper->htmlHead( isFixedFont() ) );
  1893. if (aHTML && (kasciistricmp(aMsgPart->subtypeStr(), "html")==0)) { // HTML
  1894. // ### this is broken. It doesn't stip off the HTML header and footer!
  1895. htmlWriter()->queue( aMsgPart->bodyToUnicode( overrideCodec() ) );
  1896. mColorBar->setHtmlMode();
  1897. } else { // plain text
  1898. const TQCString str = aMsgPart->bodyDecoded();
  1899. ObjectTreeParser otp( this );
  1900. otp.writeBodyStr( str,
  1901. overrideCodec() ? overrideCodec() : aMsgPart->codec(),
  1902. message() ? message()->from() : TQString() );
  1903. }
  1904. htmlWriter()->queue("</body></html>");
  1905. htmlWriter()->flush();
  1906. mMainWindow->setCaption(i18n("View Attachment: %1").arg(pname));
  1907. } else if (kasciistricmp(aMsgPart->typeStr(), "image")==0 ||
  1908. (kasciistricmp(aMsgPart->typeStr(), "application")==0 &&
  1909. kasciistricmp(aMsgPart->subtypeStr(), "postscript")==0))
  1910. {
  1911. if (aFileName.isEmpty()) return; // prevent crash
  1912. // Open the window with a size so the image fits in (if possible):
  1913. TQImageIO *iio = new TQImageIO();
  1914. iio->setFileName(aFileName);
  1915. if( iio->read() ) {
  1916. TQImage img = iio->image();
  1917. TQRect desk = TDEGlobalSettings::desktopGeometry(mMainWindow);
  1918. // determine a reasonable window size
  1919. int width, height;
  1920. if( img.width() < 50 )
  1921. width = 70;
  1922. else if( img.width()+20 < desk.width() )
  1923. width = img.width()+20;
  1924. else
  1925. width = desk.width();
  1926. if( img.height() < 50 )
  1927. height = 70;
  1928. else if( img.height()+20 < desk.height() )
  1929. height = img.height()+20;
  1930. else
  1931. height = desk.height();
  1932. mMainWindow->resize( width, height );
  1933. }
  1934. // Just write the img tag to HTML:
  1935. htmlWriter()->begin( mCSSHelper->cssDefinitions( isFixedFont() ) );
  1936. htmlWriter()->write( mCSSHelper->htmlHead( isFixedFont() ) );
  1937. htmlWriter()->write( "<img src=\"file:" +
  1938. KURL::encode_string( aFileName ) +
  1939. "\" border=\"0\">\n"
  1940. "</body></html>\n" );
  1941. htmlWriter()->end();
  1942. setCaption( i18n("View Attachment: %1").arg( pname ) );
  1943. show();
  1944. delete iio;
  1945. } else {
  1946. htmlWriter()->begin( mCSSHelper->cssDefinitions( isFixedFont() ) );
  1947. htmlWriter()->queue( mCSSHelper->htmlHead( isFixedFont() ) );
  1948. htmlWriter()->queue( "<pre>" );
  1949. TQString str = aMsgPart->bodyDecoded();
  1950. // A TQString cannot handle binary data. So if it's shorter than the
  1951. // attachment, we assume the attachment is binary:
  1952. if( str.length() < (unsigned) aMsgPart->decodedSize() ) {
  1953. str.prepend( i18n("[KMail: Attachment contains binary data. Trying to show first character.]",
  1954. "[KMail: Attachment contains binary data. Trying to show first %n characters.]",
  1955. str.length()) + TQChar('\n') );
  1956. }
  1957. htmlWriter()->queue( TQStyleSheet::escape( str ) );
  1958. htmlWriter()->queue( "</pre>" );
  1959. htmlWriter()->queue("</body></html>");
  1960. htmlWriter()->flush();
  1961. mMainWindow->setCaption(i18n("View Attachment: %1").arg(pname));
  1962. }
  1963. // ---Sven's view text, html and image attachments in html widget end ---
  1964. }
  1965. //-----------------------------------------------------------------------------
  1966. void KMReaderWin::slotAtmView( int id, const TQString& name )
  1967. {
  1968. partNode* node = mRootNode ? mRootNode->findId( id ) : 0;
  1969. if( node ) {
  1970. mAtmCurrent = id;
  1971. mAtmCurrentName = name;
  1972. if ( mAtmCurrentName.isEmpty() )
  1973. mAtmCurrentName = tempFileUrlFromPartNode( node ).path();
  1974. KMMessagePart& msgPart = node->msgPart();
  1975. TQString pname = msgPart.fileName();
  1976. if (pname.isEmpty()) pname=msgPart.name();
  1977. if (pname.isEmpty()) pname=msgPart.contentDescription();
  1978. if (pname.isEmpty()) pname="unnamed";
  1979. // image Attachment is saved already
  1980. if (kasciistricmp(msgPart.typeStr(), "message")==0) {
  1981. atmViewMsg( &msgPart,id );
  1982. } else if ((kasciistricmp(msgPart.typeStr(), "text")==0) &&
  1983. (kasciistricmp(msgPart.subtypeStr(), "x-vcard")==0)) {
  1984. setMsgPart( &msgPart, htmlMail(), name, pname );
  1985. } else {
  1986. KMReaderMainWin *win = new KMReaderMainWin(&msgPart, htmlMail(),
  1987. name, pname, overrideEncoding() );
  1988. win->show();
  1989. }
  1990. }
  1991. }
  1992. //-----------------------------------------------------------------------------
  1993. void KMReaderWin::openAttachment( int id, const TQString & name )
  1994. {
  1995. mAtmCurrentName = name;
  1996. mAtmCurrent = id;
  1997. TQString str, pname, cmd, fileName;
  1998. partNode* node = mRootNode ? mRootNode->findId( id ) : 0;
  1999. if( !node ) {
  2000. kdWarning(5006) << "KMReaderWin::openAttachment - could not find node " << id << endl;
  2001. return;
  2002. }
  2003. if ( mAtmCurrentName.isEmpty() )
  2004. mAtmCurrentName = tempFileUrlFromPartNode( node ).path();
  2005. KMMessagePart& msgPart = node->msgPart();
  2006. if (kasciistricmp(msgPart.typeStr(), "message")==0)
  2007. {
  2008. atmViewMsg( &msgPart, id );
  2009. return;
  2010. }
  2011. TQCString contentTypeStr( msgPart.typeStr() + '/' + msgPart.subtypeStr() );
  2012. KPIM::kAsciiToLower( contentTypeStr.data() );
  2013. if ( qstrcmp( contentTypeStr, "text/x-vcard" ) == 0 ) {
  2014. showVCard( &msgPart );
  2015. return;
  2016. }
  2017. // determine the MIME type of the attachment
  2018. KMimeType::Ptr mimetype;
  2019. // prefer the value of the Content-Type header
  2020. mimetype = KMimeType::mimeType( TQString::fromLatin1( contentTypeStr ) );
  2021. if ( mimetype->name() == "application/octet-stream" ) {
  2022. // consider the filename if Content-Type is application/octet-stream
  2023. mimetype = KMimeType::findByPath( name, 0, true /* no disk access */ );
  2024. }
  2025. if ( ( mimetype->name() == "application/octet-stream" )
  2026. && msgPart.isComplete() ) {
  2027. // consider the attachment's contents if neither the Content-Type header
  2028. // nor the filename give us a clue
  2029. mimetype = KMimeType::findByFileContent( name );
  2030. }
  2031. KService::Ptr offer =
  2032. KServiceTypeProfile::preferredService( mimetype->name(), "Application" );
  2033. TQString open_text;
  2034. TQString filenameText = msgPart.fileName();
  2035. if ( filenameText.isEmpty() )
  2036. filenameText = msgPart.name();
  2037. if ( offer ) {
  2038. open_text = i18n("&Open with '%1'").arg( offer->name() );
  2039. } else {
  2040. open_text = i18n("&Open With...");
  2041. }
  2042. const TQString text = i18n("Open attachment '%1'?\n"
  2043. "Note that opening an attachment may compromise "
  2044. "your system's security.")
  2045. .arg( filenameText );
  2046. const int choice = KMessageBox::questionYesNoCancel( this, text,
  2047. i18n("Open Attachment?"), KStdGuiItem::saveAs(), open_text,
  2048. TQString::fromLatin1("askSave") + mimetype->name() ); // dontAskAgainName
  2049. if( choice == KMessageBox::Yes ) { // Save
  2050. mAtmUpdate = true;
  2051. KMHandleAttachmentCommand* command = new KMHandleAttachmentCommand( node,
  2052. message(), mAtmCurrent, mAtmCurrentName, KMHandleAttachmentCommand::Save,
  2053. offer, this );
  2054. connect( command, TQT_SIGNAL( showAttachment( int, const TQString& ) ),
  2055. TQT_TQOBJECT(this), TQT_SLOT( slotAtmView( int, const TQString& ) ) );
  2056. command->start();
  2057. }
  2058. else if( choice == KMessageBox::No ) { // Open
  2059. KMHandleAttachmentCommand::AttachmentAction action = ( offer ?
  2060. KMHandleAttachmentCommand::Open : KMHandleAttachmentCommand::OpenWith );
  2061. mAtmUpdate = true;
  2062. KMHandleAttachmentCommand* command = new KMHandleAttachmentCommand( node,
  2063. message(), mAtmCurrent, mAtmCurrentName, action, offer, this );
  2064. connect( command, TQT_SIGNAL( showAttachment( int, const TQString& ) ),
  2065. TQT_TQOBJECT(this), TQT_SLOT( slotAtmView( int, const TQString& ) ) );
  2066. command->start();
  2067. } else { // Cancel
  2068. kdDebug(5006) << "Canceled opening attachment" << endl;
  2069. }
  2070. }
  2071. //-----------------------------------------------------------------------------
  2072. void KMReaderWin::slotScrollUp()
  2073. {
  2074. static_cast<TQScrollView *>(mViewer->widget())->scrollBy(0, -10);
  2075. }
  2076. //-----------------------------------------------------------------------------
  2077. void KMReaderWin::slotScrollDown()
  2078. {
  2079. static_cast<TQScrollView *>(mViewer->widget())->scrollBy(0, 10);
  2080. }
  2081. bool KMReaderWin::atBottom() const
  2082. {
  2083. const TQScrollView *view = static_cast<const TQScrollView *>(mViewer->widget());
  2084. return view->contentsY() + view->visibleHeight() >= view->contentsHeight();
  2085. }
  2086. //-----------------------------------------------------------------------------
  2087. void KMReaderWin::slotJumpDown()
  2088. {
  2089. TQScrollView *view = static_cast<TQScrollView *>(mViewer->widget());
  2090. int offs = (view->clipper()->height() < 30) ? view->clipper()->height() : 30;
  2091. view->scrollBy( 0, view->clipper()->height() - offs );
  2092. }
  2093. //-----------------------------------------------------------------------------
  2094. void KMReaderWin::slotScrollPrior()
  2095. {
  2096. static_cast<TQScrollView *>(mViewer->widget())->scrollBy(0, -(int)(height()*0.8));
  2097. }
  2098. //-----------------------------------------------------------------------------
  2099. void KMReaderWin::slotScrollNext()
  2100. {
  2101. static_cast<TQScrollView *>(mViewer->widget())->scrollBy(0, (int)(height()*0.8));
  2102. }
  2103. //-----------------------------------------------------------------------------
  2104. void KMReaderWin::slotDocumentChanged()
  2105. {
  2106. }
  2107. //-----------------------------------------------------------------------------
  2108. void KMReaderWin::slotTextSelected(bool)
  2109. {
  2110. TQString temp = mViewer->selectedText();
  2111. kapp->clipboard()->setText(temp);
  2112. }
  2113. //-----------------------------------------------------------------------------
  2114. void KMReaderWin::selectAll()
  2115. {
  2116. mViewer->selectAll();
  2117. }
  2118. //-----------------------------------------------------------------------------
  2119. TQString KMReaderWin::copyText()
  2120. {
  2121. TQString temp = mViewer->selectedText();
  2122. return temp;
  2123. }
  2124. //-----------------------------------------------------------------------------
  2125. void KMReaderWin::slotDocumentDone()
  2126. {
  2127. // mSbVert->setValue(0);
  2128. }
  2129. //-----------------------------------------------------------------------------
  2130. void KMReaderWin::setHtmlOverride(bool override)
  2131. {
  2132. mHtmlOverride = override;
  2133. if (message())
  2134. message()->setDecodeHTML(htmlMail());
  2135. }
  2136. //-----------------------------------------------------------------------------
  2137. void KMReaderWin::setHtmlLoadExtOverride(bool override)
  2138. {
  2139. mHtmlLoadExtOverride = override;
  2140. //if (message())
  2141. // message()->setDecodeHTML(htmlMail());
  2142. }
  2143. //-----------------------------------------------------------------------------
  2144. bool KMReaderWin::htmlMail()
  2145. {
  2146. return ((mHtmlMail && !mHtmlOverride) || (!mHtmlMail && mHtmlOverride));
  2147. }
  2148. //-----------------------------------------------------------------------------
  2149. bool KMReaderWin::htmlLoadExternal()
  2150. {
  2151. return ((mHtmlLoadExternal && !mHtmlLoadExtOverride) ||
  2152. (!mHtmlLoadExternal && mHtmlLoadExtOverride));
  2153. }
  2154. //-----------------------------------------------------------------------------
  2155. void KMReaderWin::saveRelativePosition()
  2156. {
  2157. const TQScrollView * scrollview = static_cast<TQScrollView *>( mViewer->widget() );
  2158. mSavedRelativePosition =
  2159. static_cast<float>( scrollview->contentsY() ) / scrollview->contentsHeight();
  2160. }
  2161. //-----------------------------------------------------------------------------
  2162. void KMReaderWin::update( bool force )
  2163. {
  2164. KMMessage* msg = message();
  2165. if ( msg )
  2166. setMsg( msg, force, true /* updateOnly */ );
  2167. }
  2168. //-----------------------------------------------------------------------------
  2169. KMMessage* KMReaderWin::message( KMFolder** aFolder ) const
  2170. {
  2171. KMFolder* tmpFolder;
  2172. KMFolder*& folder = aFolder ? *aFolder : tmpFolder;
  2173. folder = 0;
  2174. if (mMessage)
  2175. return mMessage;
  2176. if (mLastSerNum) {
  2177. KMMessage *message = 0;
  2178. int index;
  2179. KMMsgDict::instance()->getLocation( mLastSerNum, &folder, &index );
  2180. if (folder )
  2181. message = folder->getMsg( index );
  2182. if (!message)
  2183. kdWarning(5006) << "Attempt to reference invalid serial number " << mLastSerNum << "\n" << endl;
  2184. return message;
  2185. }
  2186. return 0;
  2187. }
  2188. //-----------------------------------------------------------------------------
  2189. void KMReaderWin::slotUrlClicked()
  2190. {
  2191. KMMainWidget *mainWidget = dynamic_cast<KMMainWidget*>(mMainWindow);
  2192. uint identity = 0;
  2193. if ( message() && message()->parent() ) {
  2194. identity = message()->parent()->identity();
  2195. }
  2196. KMCommand *command = new KMUrlClickedCommand( mClickedUrl, identity, this,
  2197. false, mainWidget );
  2198. command->start();
  2199. }
  2200. //-----------------------------------------------------------------------------
  2201. void KMReaderWin::slotMailtoCompose()
  2202. {
  2203. KMCommand *command = new KMMailtoComposeCommand( mClickedUrl, message() );
  2204. command->start();
  2205. }
  2206. //-----------------------------------------------------------------------------
  2207. void KMReaderWin::slotMailtoForward()
  2208. {
  2209. KMCommand *command = new KMMailtoForwardCommand( mMainWindow, mClickedUrl,
  2210. message() );
  2211. command->start();
  2212. }
  2213. //-----------------------------------------------------------------------------
  2214. void KMReaderWin::slotMailtoAddAddrBook()
  2215. {
  2216. KMCommand *command = new KMMailtoAddAddrBookCommand( mClickedUrl,
  2217. mMainWindow);
  2218. command->start();
  2219. }
  2220. //-----------------------------------------------------------------------------
  2221. void KMReaderWin::slotMailtoOpenAddrBook()
  2222. {
  2223. KMCommand *command = new KMMailtoOpenAddrBookCommand( mClickedUrl,
  2224. mMainWindow );
  2225. command->start();
  2226. }
  2227. //-----------------------------------------------------------------------------
  2228. void KMReaderWin::slotUrlCopy()
  2229. {
  2230. // we don't necessarily need a mainWidget for KMUrlCopyCommand so
  2231. // it doesn't matter if the dynamic_cast fails.
  2232. KMCommand *command =
  2233. new KMUrlCopyCommand( mClickedUrl,
  2234. dynamic_cast<KMMainWidget*>( mMainWindow ) );
  2235. command->start();
  2236. }
  2237. //-----------------------------------------------------------------------------
  2238. void KMReaderWin::slotUrlOpen( const KURL &url )
  2239. {
  2240. if ( !url.isEmpty() )
  2241. mClickedUrl = url;
  2242. KMCommand *command = new KMUrlOpenCommand( mClickedUrl, this );
  2243. command->start();
  2244. }
  2245. //-----------------------------------------------------------------------------
  2246. void KMReaderWin::slotAddBookmarks()
  2247. {
  2248. KMCommand *command = new KMAddBookmarksCommand( mClickedUrl, this );
  2249. command->start();
  2250. }
  2251. //-----------------------------------------------------------------------------
  2252. void KMReaderWin::slotUrlSave()
  2253. {
  2254. KMCommand *command = new KMUrlSaveCommand( mClickedUrl, mMainWindow );
  2255. command->start();
  2256. }
  2257. //-----------------------------------------------------------------------------
  2258. void KMReaderWin::slotMailtoReply()
  2259. {
  2260. KMCommand *command = new KMMailtoReplyCommand( mMainWindow, mClickedUrl,
  2261. message(), copyText() );
  2262. command->start();
  2263. }
  2264. //-----------------------------------------------------------------------------
  2265. partNode * KMReaderWin::partNodeFromUrl( const KURL & url ) {
  2266. return mRootNode ? mRootNode->findId( msgPartFromUrl( url ) ) : 0 ;
  2267. }
  2268. partNode * KMReaderWin::partNodeForId( int id ) {
  2269. return mRootNode ? mRootNode->findId( id ) : 0 ;
  2270. }
  2271. KURL KMReaderWin::tempFileUrlFromPartNode( const partNode * node )
  2272. {
  2273. if (!node) return KURL();
  2274. TQStringList::const_iterator it = mTempFiles.begin();
  2275. TQStringList::const_iterator end = mTempFiles.end();
  2276. while ( it != end ) {
  2277. TQString path = *it;
  2278. it++;
  2279. uint right = path.findRev('/');
  2280. uint left = path.findRev('.', right);
  2281. bool ok;
  2282. int res = path.mid(left + 1, right - left - 1).toInt(&ok);
  2283. if ( res == node->nodeId() )
  2284. return KURL( path );
  2285. }
  2286. return KURL();
  2287. }
  2288. //-----------------------------------------------------------------------------
  2289. void KMReaderWin::slotSaveAttachments()
  2290. {
  2291. mAtmUpdate = true;
  2292. KMSaveAttachmentsCommand *saveCommand = new KMSaveAttachmentsCommand( mMainWindow,
  2293. message() );
  2294. saveCommand->start();
  2295. }
  2296. //-----------------------------------------------------------------------------
  2297. void KMReaderWin::saveAttachment( const KURL &tempFileName )
  2298. {
  2299. mAtmCurrent = msgPartFromUrl( tempFileName );
  2300. mAtmCurrentName = mClickedUrl.path();
  2301. slotHandleAttachment( KMHandleAttachmentCommand::Save ); // save
  2302. }
  2303. //-----------------------------------------------------------------------------
  2304. void KMReaderWin::slotSaveMsg()
  2305. {
  2306. KMSaveMsgCommand *saveCommand = new KMSaveMsgCommand( mMainWindow, message() );
  2307. if (saveCommand->url().isEmpty())
  2308. delete saveCommand;
  2309. else
  2310. saveCommand->start();
  2311. }
  2312. //-----------------------------------------------------------------------------
  2313. void KMReaderWin::slotIMChat()
  2314. {
  2315. KMCommand *command = new KMIMChatCommand( mClickedUrl, message() );
  2316. command->start();
  2317. }
  2318. //-----------------------------------------------------------------------------
  2319. static TQString linkForNode( const DOM::Node &node )
  2320. {
  2321. try {
  2322. if ( node.isNull() )
  2323. return TQString();
  2324. const DOM::NamedNodeMap attributes = node.attributes();
  2325. if ( !attributes.isNull() ) {
  2326. const DOM::Node href = attributes.getNamedItem( DOM::DOMString( "href" ) );
  2327. if ( !href.isNull() ) {
  2328. return href.nodeValue().string();
  2329. }
  2330. }
  2331. if ( !node.parentNode().isNull() ) {
  2332. return linkForNode( node.parentNode() );
  2333. } else {
  2334. return TQString();
  2335. }
  2336. } catch ( DOM::DOMException &e ) {
  2337. kdWarning(5006) << "Got an exception when trying to determine link under cursor!" << endl;
  2338. return TQString();
  2339. }
  2340. }
  2341. //-----------------------------------------------------------------------------
  2342. bool KMReaderWin::eventFilter( TQObject *, TQEvent *e )
  2343. {
  2344. if ( e->type() == TQEvent::MouseButtonPress ) {
  2345. TQMouseEvent* me = TQT_TQMOUSEEVENT(e);
  2346. if ( me->button() == Qt::LeftButton && ( me->state() & ShiftButton ) ) {
  2347. // special processing for shift+click
  2348. URLHandlerManager::instance()->handleShiftClick( mHoveredUrl, this );
  2349. return true;
  2350. }
  2351. if ( me->button() == Qt::LeftButton ) {
  2352. TQString imagePath;
  2353. const DOM::Node nodeUnderMouse = mViewer->nodeUnderMouse();
  2354. if ( !nodeUnderMouse.isNull() ) {
  2355. const DOM::NamedNodeMap attributes = nodeUnderMouse.attributes();
  2356. if ( !attributes.isNull() ) {
  2357. const DOM::Node src = attributes.getNamedItem( DOM::DOMString( "src" ) );
  2358. if ( !src.isNull() ) {
  2359. imagePath = src.nodeValue().string();
  2360. }
  2361. }
  2362. }
  2363. mCanStartDrag = URLHandlerManager::instance()->willHandleDrag( mHoveredUrl, imagePath, this );
  2364. mLastClickPosition = me->pos();
  2365. mLastClickImagePath = imagePath;
  2366. }
  2367. }
  2368. if ( e->type() == TQEvent::MouseButtonRelease ) {
  2369. mCanStartDrag = false;
  2370. }
  2371. if ( e->type() == TQEvent::MouseMove ) {
  2372. TQMouseEvent* me = TQT_TQMOUSEEVENT( e );
  2373. // Handle this ourselves instead of connecting to mViewer::onURL(), since TDEHTML misses some
  2374. // notifications in case we started a drag ourselves
  2375. slotUrlOn( linkForNode( mViewer->nodeUnderMouse() ) );
  2376. if ( ( mLastClickPosition - me->pos() ).manhattanLength() > TDEGlobalSettings::dndEventDelay() ) {
  2377. if ( mCanStartDrag && ( !( mHoveredUrl.isEmpty() && mLastClickImagePath.isEmpty() ) ) ) {
  2378. if ( URLHandlerManager::instance()->handleDrag( mHoveredUrl, mLastClickImagePath, this ) ) {
  2379. mCanStartDrag = false;
  2380. slotUrlOn( TQString() );
  2381. // HACK: Send a mouse release event to the TDEHTMLView, as otherwise that will be missed in
  2382. // case we started a drag. If the event is missed, the HTML view gets into a wrong
  2383. // state, in which funny things like unsolicited drags start to happen.
  2384. TQMouseEvent mouseEvent( TQEvent::MouseButtonRelease, me->pos(), Qt::NoButton, Qt::NoButton );
  2385. TQT_TQOBJECT( mViewer->view() )->eventFilter( mViewer->view()->viewport(),
  2386. &mouseEvent );
  2387. return true;
  2388. }
  2389. }
  2390. }
  2391. }
  2392. // standard event processing
  2393. return false;
  2394. }
  2395. void KMReaderWin::fillCommandInfo( partNode *node, KMMessage **msg, int *nodeId )
  2396. {
  2397. Q_ASSERT( msg && nodeId );
  2398. if ( mSerNumOfOriginalMessage != 0 ) {
  2399. KMFolder *folder = 0;
  2400. int index = -1;
  2401. KMMsgDict::instance()->getLocation( mSerNumOfOriginalMessage, &folder, &index );
  2402. if ( folder && index != -1 )
  2403. *msg = folder->getMsg( index );
  2404. if ( !( *msg ) ) {
  2405. kdWarning( 5006 ) << "Unable to find the original message, aborting attachment deletion!" << endl;
  2406. return;
  2407. }
  2408. *nodeId = node->nodeId() + mNodeIdOffset;
  2409. }
  2410. else {
  2411. *nodeId = node->nodeId();
  2412. *msg = message();
  2413. }
  2414. }
  2415. void KMReaderWin::slotDeleteAttachment(partNode * node)
  2416. {
  2417. if ( KMessageBox::warningContinueCancel( this,
  2418. i18n("Deleting an attachment might invalidate any digital signature on this message."),
  2419. i18n("Delete Attachment"), KStdGuiItem::del(), "DeleteAttachmentSignatureWarning" )
  2420. != KMessageBox::Continue ) {
  2421. return;
  2422. }
  2423. int nodeId = -1;
  2424. KMMessage *msg = 0;
  2425. fillCommandInfo( node, &msg, &nodeId );
  2426. if ( msg && nodeId != -1 ) {
  2427. KMDeleteAttachmentCommand* command = new KMDeleteAttachmentCommand( nodeId, msg, this );
  2428. command->start();
  2429. connect( command, TQT_SIGNAL( completed( KMCommand * ) ),
  2430. TQT_TQOBJECT(this), TQT_SLOT( updateReaderWin() ) );
  2431. connect( command, TQT_SIGNAL( completed( KMCommand * ) ),
  2432. TQT_TQOBJECT(this), TQT_SLOT( disconnectMsgAdded() ) );
  2433. // ### HACK: Since the command will do delete + add, a new message will arrive. However, we don't
  2434. // want the selection to change. Therefore, as soon as a new message arrives, select it, and then
  2435. // disconnect.
  2436. // Of course the are races, another message can arrive before ours, but we take the risk.
  2437. // And it won't work properly with multiple main windows
  2438. const KMHeaders * const headers = KMKernel::self()->getKMMainWidget()->headers();
  2439. connect( headers, TQT_SIGNAL( msgAddedToListView( TQListViewItem* ) ),
  2440. TQT_TQOBJECT(this), TQT_SLOT( msgAdded( TQListViewItem* ) ) );
  2441. }
  2442. // If we are operating on a copy of parts of the message, make sure to update the copy as well.
  2443. if ( mSerNumOfOriginalMessage != 0 && message() ) {
  2444. message()->deleteBodyPart( node->nodeId() );
  2445. update( true );
  2446. }
  2447. }
  2448. void KMReaderWin::msgAdded( TQListViewItem *item )
  2449. {
  2450. // A new message was added to the message list view. Select it.
  2451. // This is only connected right after we started a attachment delete command, so we expect a new
  2452. // message. Disconnect right afterwards, we only want this particular message to be selected.
  2453. disconnectMsgAdded();
  2454. KMHeaders * const headers = KMKernel::self()->getKMMainWidget()->headers();
  2455. headers->setCurrentItem( item );
  2456. headers->clearSelection();
  2457. headers->setSelected( item, true );
  2458. }
  2459. void KMReaderWin::disconnectMsgAdded()
  2460. {
  2461. const KMHeaders *const headers = KMKernel::self()->getKMMainWidget()->headers();
  2462. disconnect( headers, TQT_SIGNAL( msgAddedToListView( TQListViewItem* ) ),
  2463. TQT_TQOBJECT(this), TQT_SLOT( msgAdded( TQListViewItem* ) ) );
  2464. }
  2465. void KMReaderWin::slotEditAttachment(partNode * node)
  2466. {
  2467. if ( KMessageBox::warningContinueCancel( this,
  2468. i18n("Modifying an attachment might invalidate any digital signature on this message."),
  2469. i18n("Edit Attachment"), KGuiItem( i18n("Edit"), "edit" ), "EditAttachmentSignatureWarning" )
  2470. != KMessageBox::Continue ) {
  2471. return;
  2472. }
  2473. int nodeId = -1;
  2474. KMMessage *msg = 0;
  2475. fillCommandInfo( node, &msg, &nodeId );
  2476. if ( msg && nodeId != -1 ) {
  2477. KMEditAttachmentCommand* command = new KMEditAttachmentCommand( nodeId, msg, this );
  2478. command->start();
  2479. }
  2480. // FIXME: If we are operating on a copy of parts of the message, make sure to update the copy as well.
  2481. }
  2482. KMail::CSSHelper* KMReaderWin::cssHelper()
  2483. {
  2484. return mCSSHelper;
  2485. }
  2486. bool KMReaderWin::decryptMessage() const
  2487. {
  2488. if ( !GlobalSettings::self()->alwaysDecrypt() )
  2489. return mDecrytMessageOverwrite;
  2490. return true;
  2491. }
  2492. void KMReaderWin::scrollToAttachment( const partNode *node )
  2493. {
  2494. DOM::Document doc = mViewer->htmlDocument();
  2495. // The anchors for this are created in ObjectTreeParser::parseObjectTree()
  2496. mViewer->gotoAnchor( TQString::fromLatin1( "att%1" ).arg( node->nodeId() ) );
  2497. // Remove any old color markings which might be there
  2498. const partNode *root = node->topLevelParent();
  2499. for ( int i = 0; i <= root->totalChildCount() + 1; i++ ) {
  2500. DOM::Element attachmentDiv = doc.getElementById( TQString( "attachmentDiv%1" ).arg( i + 1 ) );
  2501. if ( !attachmentDiv.isNull() )
  2502. attachmentDiv.removeAttribute( "style" );
  2503. }
  2504. // Don't mark hidden nodes, that would just produce a strange yellow line
  2505. if ( node->isDisplayedHidden() )
  2506. return;
  2507. // Now, color the div of the attachment in yellow, so that the user sees what happened.
  2508. // We created a special marked div for this in writeAttachmentMarkHeader() in ObjectTreeParser,
  2509. // find and modify that now.
  2510. DOM::Element attachmentDiv = doc.getElementById( TQString( "attachmentDiv%1" ).arg( node->nodeId() ) );
  2511. if ( attachmentDiv.isNull() ) {
  2512. kdWarning( 5006 ) << "Could not find attachment div for attachment " << node->nodeId() << endl;
  2513. return;
  2514. }
  2515. attachmentDiv.setAttribute( "style", TQString( "border:2px solid %1" )
  2516. .arg( cssHelper()->pgpWarnColor().name() ) );
  2517. // Update rendering, otherwise the rendering is not updated when the user clicks on an attachment
  2518. // that causes scrolling and the open attachment dialog
  2519. doc.updateRendering();
  2520. }
  2521. void KMReaderWin::injectAttachments()
  2522. {
  2523. // inject attachments in header view
  2524. // we have to do that after the otp has run so we also see encrypted parts
  2525. DOM::Document doc = mViewer->htmlDocument();
  2526. DOM::Element injectionPoint = doc.getElementById( "attachmentInjectionPoint" );
  2527. if ( injectionPoint.isNull() )
  2528. return;
  2529. TQString imgpath( locate("data","kmail/pics/") );
  2530. TQString visibility;
  2531. TQString urlHandle;
  2532. TQString imgSrc;
  2533. if( !showAttachmentQuicklist() ) {
  2534. urlHandle.append( "kmail:showAttachmentQuicklist" );
  2535. imgSrc.append( "attachmentQuicklistClosed.png" );
  2536. } else {
  2537. urlHandle.append( "kmail:hideAttachmentQuicklist" );
  2538. imgSrc.append( "attachmentQuicklistOpened.png" );
  2539. }
  2540. TQString html = renderAttachments( mRootNode, TQApplication::palette().active().background() );
  2541. if ( html.isEmpty() )
  2542. return;
  2543. TQString link("");
  2544. if ( headerStyle() == HeaderStyle::fancy() ) {
  2545. link += "<div style=\"text-align: left;\"><a href=\"" + urlHandle + "\"><img src=\"" +
  2546. imgpath + imgSrc + "\"/></a></div>";
  2547. html.prepend( link );
  2548. html.prepend( TQString::fromLatin1( "<div style=\"float:left;\">%1&nbsp;</div>" ).
  2549. arg( i18n( "Attachments:" ) ) );
  2550. } else {
  2551. link += "<div style=\"text-align: right;\"><a href=\"" + urlHandle + "\"><img src=\"" +
  2552. imgpath + imgSrc + "\"/></a></div>";
  2553. html.prepend( link );
  2554. }
  2555. assert( injectionPoint.tagName() == "div" );
  2556. static_cast<DOM::HTMLElement>( injectionPoint ).setInnerHTML( html );
  2557. }
  2558. static TQColor nextColor( const TQColor & c )
  2559. {
  2560. int h, s, v;
  2561. c.hsv( &h, &s, &v );
  2562. return TQColor( (h + 50) % 360, TQMAX(s, 64), v, TQColor::Hsv );
  2563. }
  2564. TQString KMReaderWin::renderAttachments(partNode * node, const TQColor &bgColor )
  2565. {
  2566. if ( !node )
  2567. return TQString();
  2568. TQString html;
  2569. if ( node->firstChild() ) {
  2570. TQString subHtml = renderAttachments( node->firstChild(), nextColor( bgColor ) );
  2571. if ( !subHtml.isEmpty() ) {
  2572. TQString visibility;
  2573. if ( !showAttachmentQuicklist() ) {
  2574. visibility.append( "display:none;" );
  2575. }
  2576. TQString margin;
  2577. if ( node != mRootNode || headerStyle() != HeaderStyle::enterprise() )
  2578. margin = "padding:2px; margin:2px; ";
  2579. TQString align = "left";
  2580. if ( headerStyle() == HeaderStyle::enterprise() )
  2581. align = "right";
  2582. if ( node->msgPart().typeStr().lower() == "message" || node == mRootNode )
  2583. html += TQString::fromLatin1("<div style=\"background:%1; %2"
  2584. "vertical-align:middle; float:%3; %4\">").arg( bgColor.name() ).arg( margin )
  2585. .arg( align ).arg( visibility );
  2586. html += subHtml;
  2587. if ( node->msgPart().typeStr().lower() == "message" || node == mRootNode )
  2588. html += "</div>";
  2589. }
  2590. } else {
  2591. partNode::AttachmentDisplayInfo info = node->attachmentDisplayInfo();
  2592. if ( info.displayInHeader ) {
  2593. html += "<div style=\"float:left;\">";
  2594. html += TQString::fromLatin1( "<span style=\"white-space:nowrap; border-width: 0px; border-left-width: 5px; border-color: %1; 2px; border-left-style: solid;\">" ).arg( bgColor.name() );
  2595. TQString fileName = writeMessagePartToTempFile( &node->msgPart(), node->nodeId() );
  2596. TQString href = node->asHREF( "header" );
  2597. html += TQString::fromLatin1( "<a href=\"" ) + href +
  2598. TQString::fromLatin1( "\">" );
  2599. html += "<img style=\"vertical-align:middle;\" src=\"" + info.icon + "\"/>&nbsp;";
  2600. if ( headerStyle() == HeaderStyle::enterprise() ) {
  2601. TQFont bodyFont = mCSSHelper->bodyFont( isFixedFont() );
  2602. TQFontMetrics fm( bodyFont );
  2603. html += KStringHandler::rPixelSqueeze( info.label, fm, 140 );
  2604. } else if ( headerStyle() == HeaderStyle::fancy() ) {
  2605. TQFont bodyFont = mCSSHelper->bodyFont( isFixedFont() );
  2606. TQFontMetrics fm( bodyFont );
  2607. html += KStringHandler::rPixelSqueeze( info.label, fm, 640 );
  2608. } else {
  2609. html += info.label;
  2610. }
  2611. html += "</a></span></div> ";
  2612. }
  2613. }
  2614. html += renderAttachments( node->nextSibling(), nextColor ( bgColor ) );
  2615. return html;
  2616. }
  2617. using namespace KMail::Interface;
  2618. void KMReaderWin::setBodyPartMemento( const partNode * node, const TQCString & which, BodyPartMemento * memento )
  2619. {
  2620. const TQCString index = node->path() + ':' + which.lower();
  2621. const std::map<TQCString,BodyPartMemento*>::iterator it = mBodyPartMementoMap.lower_bound( index );
  2622. if ( it != mBodyPartMementoMap.end() && it->first == index ) {
  2623. if ( memento && memento == it->second )
  2624. return;
  2625. delete it->second;
  2626. if ( memento ) {
  2627. it->second = memento;
  2628. }
  2629. else {
  2630. mBodyPartMementoMap.erase( it );
  2631. }
  2632. } else {
  2633. if ( memento ) {
  2634. mBodyPartMementoMap.insert( it, std::make_pair( index, memento ) );
  2635. }
  2636. }
  2637. if ( Observable * o = memento ? memento->asObservable() : 0 )
  2638. o->attach( this );
  2639. }
  2640. BodyPartMemento * KMReaderWin::bodyPartMemento( const partNode * node, const TQCString & which ) const
  2641. {
  2642. const TQCString index = node->path() + ':' + which.lower();
  2643. const std::map<TQCString,BodyPartMemento*>::const_iterator it = mBodyPartMementoMap.find( index );
  2644. if ( it == mBodyPartMementoMap.end() ) {
  2645. return 0;
  2646. }
  2647. else {
  2648. return it->second;
  2649. }
  2650. }
  2651. static void detach_and_delete( BodyPartMemento * memento, KMReaderWin * obs ) {
  2652. if ( Observable * const o = memento ? memento->asObservable() : 0 )
  2653. o->detach( obs );
  2654. delete memento;
  2655. }
  2656. void KMReaderWin::clearBodyPartMementos()
  2657. {
  2658. for ( std::map<TQCString,BodyPartMemento*>::const_iterator it = mBodyPartMementoMap.begin(), end = mBodyPartMementoMap.end() ; it != end ; ++it )
  2659. // Detach the memento from the reader. When cancelling it, it might trigger an update of the
  2660. // reader, which we are not interested in, and which is dangerous, since half the mementos are
  2661. // already deleted.
  2662. // https://issues.kolab.org/issue4187
  2663. detach_and_delete( it->second, this );
  2664. mBodyPartMementoMap.clear();
  2665. }
  2666. #include "kmreaderwin.moc"