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.

kmcommands.cpp 109KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598
  1. /* -*- mode: C++; c-file-style: "gnu" -*-
  2. This file is part of KMail, the KDE mail client.
  3. Copyright (c) 2002 Don Sanders <sanders@kde.org>
  4. KMail is free software; you can redistribute it and/or modify it
  5. under the terms of the GNU General Public License, version 2, as
  6. published by the Free Software Foundation.
  7. KMail is distributed in the hope that it will be useful, but
  8. WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  10. General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, write to the Free Software
  13. Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  14. */
  15. //
  16. // This file implements various "command" classes. These command classes
  17. // are based on the command design pattern.
  18. //
  19. // Historically various operations were implemented as slots of KMMainWin.
  20. // This proved inadequate as KMail has multiple top level windows
  21. // (KMMainWin, KMReaderMainWin, SearchWindow, KMComposeWin) that may
  22. // benefit from using these operations. It is desirable that these
  23. // classes can operate without depending on or altering the state of
  24. // a KMMainWin, in fact it is possible no KMMainWin object even exists.
  25. //
  26. // Now these operations have been rewritten as KMCommand based classes,
  27. // making them independent of KMMainWin.
  28. //
  29. // The base command class KMCommand is async, which is a difference
  30. // from the conventional command pattern. As normal derived classes implement
  31. // the execute method, but client classes call start() instead of
  32. // calling execute() directly. start() initiates async operations,
  33. // and on completion of these operations calls execute() and then deletes
  34. // the command. (So the client must not construct commands on the stack).
  35. //
  36. // The type of async operation supported by KMCommand is retrieval
  37. // of messages from an IMAP server.
  38. #include "kmcommands.h"
  39. #ifdef HAVE_CONFIG_H
  40. #include <config.h>
  41. #endif
  42. #include <errno.h>
  43. #include <mimelib/enum.h>
  44. #include <mimelib/field.h>
  45. #include <mimelib/mimepp.h>
  46. #include <mimelib/string.h>
  47. #include <tdeapplication.h>
  48. #include <dcopclient.h>
  49. #include <tqtextcodec.h>
  50. #include <tqpopupmenu.h>
  51. #include <tqeventloop.h>
  52. #include <libemailfunctions/email.h>
  53. #include <kdcopservicestarter.h>
  54. #include <kdebug.h>
  55. #include <tdefiledialog.h>
  56. #include <tdeabc/stdaddressbook.h>
  57. #include <tdeabc/addresseelist.h>
  58. #include <kdirselectdialog.h>
  59. #include <tdelocale.h>
  60. #include <tdemessagebox.h>
  61. #include <tdeparts/browserextension.h>
  62. #include <kprogress.h>
  63. #include <krun.h>
  64. #include <kbookmarkmanager.h>
  65. #include <kstandarddirs.h>
  66. #include <tdetempfile.h>
  67. #include <tdeimproxy.h>
  68. #include <kuserprofile.h>
  69. // TDEIO headers
  70. #include <tdeio/job.h>
  71. #include <tdeio/netaccess.h>
  72. #include <libkpimidentities/identitymanager.h>
  73. #include "actionscheduler.h"
  74. using KMail::ActionScheduler;
  75. #include "mailinglist-magic.h"
  76. #include "kmaddrbook.h"
  77. #include <kaddrbook.h>
  78. #include "composer.h"
  79. #include "kmfiltermgr.h"
  80. #include "kmfoldermbox.h"
  81. #include "kmfolderimap.h"
  82. #include "kmfoldermgr.h"
  83. #include "kmheaders.h"
  84. #include "headeritem.h"
  85. #include "kmmainwidget.h"
  86. #include "kmmsgdict.h"
  87. #include "messagesender.h"
  88. #include "kmmsgpartdlg.h"
  89. #include "undostack.h"
  90. #include "kcursorsaver.h"
  91. #include "partNode.h"
  92. #include "objecttreeparser.h"
  93. #include "csshelper.h"
  94. using KMail::ObjectTreeParser;
  95. using KMail::FolderJob;
  96. #include "chiasmuskeyselector.h"
  97. #include "mailsourceviewer.h"
  98. using KMail::MailSourceViewer;
  99. #include "kmreadermainwin.h"
  100. #include "secondarywindow.h"
  101. using KMail::SecondaryWindow;
  102. #include "redirectdialog.h"
  103. using KMail::RedirectDialog;
  104. #include "util.h"
  105. #include "templateparser.h"
  106. #include "editorwatcher.h"
  107. #include "korghelper.h"
  108. #include "broadcaststatus.h"
  109. #include "globalsettings.h"
  110. #include <libtdepim/tdefileio.h>
  111. #include "kcalendariface_stub.h"
  112. #include "progressmanager.h"
  113. using KPIM::ProgressManager;
  114. using KPIM::ProgressItem;
  115. #include <kmime_mdn.h>
  116. using namespace KMime;
  117. #include <kleo/specialjob.h>
  118. #include <kleo/cryptobackend.h>
  119. #include <kleo/cryptobackendfactory.h>
  120. #include <tqclipboard.h>
  121. #include <memory>
  122. class LaterDeleterWithCommandCompletion : public KMail::Util::LaterDeleter
  123. {
  124. public:
  125. LaterDeleterWithCommandCompletion( KMCommand* command )
  126. :LaterDeleter( command ), m_result( KMCommand::Failed )
  127. {
  128. }
  129. ~LaterDeleterWithCommandCompletion()
  130. {
  131. setResult( m_result );
  132. KMCommand *command = static_cast<KMCommand*>( m_object );
  133. emit command->completed( command );
  134. }
  135. void setResult( KMCommand::Result v ) { m_result = v; }
  136. private:
  137. KMCommand::Result m_result;
  138. };
  139. KMCommand::KMCommand( TQWidget *parent )
  140. : mProgressDialog( 0 ), mResult( Undefined ), mDeletesItself( false ),
  141. mEmitsCompletedItself( false ), mParent( parent )
  142. {
  143. }
  144. KMCommand::KMCommand( TQWidget *parent, const TQPtrList<KMMsgBase> &msgList )
  145. : mProgressDialog( 0 ), mResult( Undefined ), mDeletesItself( false ),
  146. mEmitsCompletedItself( false ), mParent( parent ), mMsgList( msgList )
  147. {
  148. }
  149. KMCommand::KMCommand( TQWidget *parent, KMMsgBase *msgBase )
  150. : mProgressDialog( 0 ), mResult( Undefined ), mDeletesItself( false ),
  151. mEmitsCompletedItself( false ), mParent( parent )
  152. {
  153. mMsgList.append( msgBase );
  154. }
  155. KMCommand::KMCommand( TQWidget *parent, KMMessage *msg )
  156. : mProgressDialog( 0 ), mResult( Undefined ), mDeletesItself( false ),
  157. mEmitsCompletedItself( false ), mParent( parent )
  158. {
  159. if (msg)
  160. mMsgList.append( &msg->toMsgBase() );
  161. }
  162. KMCommand::~KMCommand()
  163. {
  164. TQValueListIterator<TQGuardedPtr<KMFolder> > fit;
  165. for ( fit = mFolders.begin(); fit != mFolders.end(); ++fit ) {
  166. if (!(*fit))
  167. continue;
  168. (*fit)->close("kmcommand");
  169. }
  170. }
  171. KMCommand::Result KMCommand::result()
  172. {
  173. if ( mResult == Undefined )
  174. kdDebug(5006) << k_funcinfo << "mResult is Undefined" << endl;
  175. return mResult;
  176. }
  177. void KMCommand::start()
  178. {
  179. TQTimer::singleShot( 0, this, TQT_SLOT( slotStart() ) );
  180. }
  181. const TQPtrList<KMMessage> KMCommand::retrievedMsgs() const
  182. {
  183. return mRetrievedMsgs;
  184. }
  185. KMMessage *KMCommand::retrievedMessage() const
  186. {
  187. return mRetrievedMsgs.getFirst();
  188. }
  189. TQWidget *KMCommand::parentWidget() const
  190. {
  191. return mParent;
  192. }
  193. int KMCommand::mCountJobs = 0;
  194. void KMCommand::slotStart()
  195. {
  196. connect( this, TQT_SIGNAL( messagesTransfered( KMCommand::Result ) ),
  197. this, TQT_SLOT( slotPostTransfer( KMCommand::Result ) ) );
  198. kmkernel->filterMgr()->ref();
  199. if (mMsgList.find(0) != -1) {
  200. emit messagesTransfered( Failed );
  201. return;
  202. }
  203. if ((mMsgList.count() == 1) &&
  204. (mMsgList.getFirst()->isMessage()) &&
  205. (mMsgList.getFirst()->parent() == 0))
  206. {
  207. // Special case of operating on message that isn't in a folder
  208. mRetrievedMsgs.append((KMMessage*)mMsgList.getFirst());
  209. emit messagesTransfered( OK );
  210. return;
  211. }
  212. for ( KMMsgBase *mb = mMsgList.first(); mb; mb = mMsgList.next() ) {
  213. if ( mb ) {
  214. if ( !mb->parent() ) {
  215. emit messagesTransfered( Failed );
  216. return;
  217. } else {
  218. keepFolderOpen( mb->parent() );
  219. }
  220. }
  221. }
  222. // transfer the selected messages first
  223. transferSelectedMsgs();
  224. }
  225. void KMCommand::slotPostTransfer( KMCommand::Result result )
  226. {
  227. disconnect( this, TQT_SIGNAL( messagesTransfered( KMCommand::Result ) ),
  228. this, TQT_SLOT( slotPostTransfer( KMCommand::Result ) ) );
  229. if ( result == OK )
  230. result = execute();
  231. mResult = result;
  232. TQPtrListIterator<KMMessage> it( mRetrievedMsgs );
  233. KMMessage* msg;
  234. while ( (msg = it.current()) != 0 )
  235. {
  236. ++it;
  237. if (msg->parent())
  238. msg->setTransferInProgress(false);
  239. }
  240. kmkernel->filterMgr()->deref();
  241. if ( !emitsCompletedItself() )
  242. emit completed( this );
  243. if ( !deletesItself() )
  244. deleteLater();
  245. }
  246. void KMCommand::transferSelectedMsgs()
  247. {
  248. // make sure no other transfer is active
  249. if (KMCommand::mCountJobs > 0) {
  250. emit messagesTransfered( Failed );
  251. return;
  252. }
  253. bool complete = true;
  254. KMCommand::mCountJobs = 0;
  255. mCountMsgs = 0;
  256. mRetrievedMsgs.clear();
  257. mCountMsgs = mMsgList.count();
  258. uint totalSize = 0;
  259. // the KProgressDialog for the user-feedback. Only enable it if it's needed.
  260. // For some commands like KMSeStatusCommand it's not needed. Note, that
  261. // for some reason the KProgressDialog eats the MouseReleaseEvent (if a
  262. // command is executed after the MousePressEvent), cf. bug #71761.
  263. if ( mCountMsgs > 0 ) {
  264. mProgressDialog = new KProgressDialog(mParent, "transferProgress",
  265. i18n("Please wait"),
  266. i18n("Please wait while the message is transferred",
  267. "Please wait while the %n messages are transferred", mMsgList.count()),
  268. true);
  269. mProgressDialog->setMinimumDuration(1000);
  270. }
  271. for (KMMsgBase *mb = mMsgList.first(); mb; mb = mMsgList.next())
  272. {
  273. // check if all messages are complete
  274. KMMessage *thisMsg = 0;
  275. if ( mb->isMessage() )
  276. thisMsg = static_cast<KMMessage*>(mb);
  277. else
  278. {
  279. KMFolder *folder = mb->parent();
  280. int idx = folder->find(mb);
  281. if (idx < 0) continue;
  282. thisMsg = folder->getMsg(idx);
  283. }
  284. if (!thisMsg) continue;
  285. if ( thisMsg->transferInProgress() &&
  286. thisMsg->parent()->folderType() == KMFolderTypeImap )
  287. {
  288. thisMsg->setTransferInProgress( false, true );
  289. thisMsg->parent()->ignoreJobsForMessage( thisMsg );
  290. }
  291. if ( thisMsg->parent() && !thisMsg->isComplete() &&
  292. ( !mProgressDialog || !mProgressDialog->wasCancelled() ) )
  293. {
  294. kdDebug(5006)<<"### INCOMPLETE\n";
  295. // the message needs to be transferred first
  296. complete = false;
  297. KMCommand::mCountJobs++;
  298. FolderJob *job = thisMsg->parent()->createJob(thisMsg);
  299. job->setCancellable( false );
  300. totalSize += thisMsg->msgSizeServer();
  301. // emitted when the message was transferred successfully
  302. connect(job, TQT_SIGNAL(messageRetrieved(KMMessage*)),
  303. this, TQT_SLOT(slotMsgTransfered(KMMessage*)));
  304. // emitted when the job is destroyed
  305. connect(job, TQT_SIGNAL(finished()),
  306. this, TQT_SLOT(slotJobFinished()));
  307. connect(job, TQT_SIGNAL(progress(unsigned long, unsigned long)),
  308. this, TQT_SLOT(slotProgress(unsigned long, unsigned long)));
  309. // msg musn't be deleted
  310. thisMsg->setTransferInProgress(true);
  311. job->start();
  312. } else {
  313. thisMsg->setTransferInProgress(true);
  314. mRetrievedMsgs.append(thisMsg);
  315. }
  316. }
  317. if (complete)
  318. {
  319. delete mProgressDialog;
  320. mProgressDialog = 0;
  321. emit messagesTransfered( OK );
  322. } else {
  323. // wait for the transfer and tell the progressBar the necessary steps
  324. if ( mProgressDialog ) {
  325. connect(mProgressDialog, TQT_SIGNAL(cancelClicked()),
  326. this, TQT_SLOT(slotTransferCancelled()));
  327. mProgressDialog->progressBar()->setTotalSteps(totalSize);
  328. }
  329. }
  330. }
  331. void KMCommand::slotMsgTransfered(KMMessage* msg)
  332. {
  333. if ( mProgressDialog && mProgressDialog->wasCancelled() ) {
  334. emit messagesTransfered( Canceled );
  335. return;
  336. }
  337. // save the complete messages
  338. mRetrievedMsgs.append(msg);
  339. }
  340. void KMCommand::slotProgress( unsigned long done, unsigned long /*total*/ )
  341. {
  342. mProgressDialog->progressBar()->setProgress( done );
  343. }
  344. void KMCommand::slotJobFinished()
  345. {
  346. // the job is finished (with / without error)
  347. KMCommand::mCountJobs--;
  348. if ( mProgressDialog && mProgressDialog->wasCancelled() ) return;
  349. if ( (mCountMsgs - static_cast<int>(mRetrievedMsgs.count())) > KMCommand::mCountJobs )
  350. {
  351. // the message wasn't retrieved before => error
  352. if ( mProgressDialog )
  353. mProgressDialog->hide();
  354. slotTransferCancelled();
  355. return;
  356. }
  357. // update the progressbar
  358. if ( mProgressDialog ) {
  359. mProgressDialog->setLabel(i18n("Please wait while the message is transferred",
  360. "Please wait while the %n messages are transferred", KMCommand::mCountJobs));
  361. }
  362. if (KMCommand::mCountJobs == 0)
  363. {
  364. // all done
  365. delete mProgressDialog;
  366. mProgressDialog = 0;
  367. emit messagesTransfered( OK );
  368. }
  369. }
  370. void KMCommand::slotTransferCancelled()
  371. {
  372. // kill the pending jobs
  373. TQValueListIterator<TQGuardedPtr<KMFolder> > fit;
  374. for ( fit = mFolders.begin(); fit != mFolders.end(); ++fit ) {
  375. if (!(*fit))
  376. continue;
  377. KMFolder *folder = *fit;
  378. KMFolderImap *imapFolder = dynamic_cast<KMFolderImap*>(folder);
  379. if (imapFolder && imapFolder->account()) {
  380. imapFolder->account()->killAllJobs();
  381. }
  382. }
  383. KMCommand::mCountJobs = 0;
  384. mCountMsgs = 0;
  385. // unget the transfered messages
  386. TQPtrListIterator<KMMessage> it( mRetrievedMsgs );
  387. KMMessage* msg;
  388. while ( (msg = it.current()) != 0 )
  389. {
  390. KMFolder *folder = msg->parent();
  391. ++it;
  392. if (!folder)
  393. continue;
  394. msg->setTransferInProgress(false);
  395. int idx = folder->find(msg);
  396. if (idx > 0) folder->unGetMsg(idx);
  397. }
  398. mRetrievedMsgs.clear();
  399. emit messagesTransfered( Canceled );
  400. }
  401. void KMCommand::keepFolderOpen( KMFolder *folder )
  402. {
  403. folder->open( "kmcommand" );
  404. mFolders.append( folder );
  405. }
  406. KMMailtoComposeCommand::KMMailtoComposeCommand( const KURL &url,
  407. KMMessage *msg )
  408. :mUrl( url ), mMessage( msg )
  409. {
  410. }
  411. KMCommand::Result KMMailtoComposeCommand::execute()
  412. {
  413. KMMessage *msg = new KMMessage;
  414. uint id = 0;
  415. if ( mMessage && mMessage->parent() )
  416. id = mMessage->parent()->identity();
  417. msg->initHeader(id);
  418. msg->setCharset("utf-8");
  419. msg->setTo( KMMessage::decodeMailtoUrl( mUrl.path() ) );
  420. KMail::Composer * win = KMail::makeComposer( msg, id );
  421. win->setCharset("", true);
  422. win->setFocusToSubject();
  423. win->show();
  424. return OK;
  425. }
  426. KMMailtoReplyCommand::KMMailtoReplyCommand( TQWidget *parent,
  427. const KURL &url, KMMessage *msg, const TQString &selection )
  428. :KMCommand( parent, msg ), mUrl( url ), mSelection( selection )
  429. {
  430. }
  431. KMCommand::Result KMMailtoReplyCommand::execute()
  432. {
  433. //TODO : consider factoring createReply into this method.
  434. KMMessage *msg = retrievedMessage();
  435. if ( !msg || !msg->codec() ) {
  436. return Failed;
  437. }
  438. KMMessage *rmsg = msg->createReply( KMail::ReplyNone, mSelection );
  439. rmsg->setTo( KMMessage::decodeMailtoUrl( mUrl.path() ) );
  440. KMail::Composer * win = KMail::makeComposer( rmsg, 0 );
  441. win->setCharset(msg->codec()->mimeName(), true);
  442. win->setReplyFocus();
  443. win->show();
  444. return OK;
  445. }
  446. KMMailtoForwardCommand::KMMailtoForwardCommand( TQWidget *parent,
  447. const KURL &url, KMMessage *msg )
  448. :KMCommand( parent, msg ), mUrl( url )
  449. {
  450. }
  451. KMCommand::Result KMMailtoForwardCommand::execute()
  452. {
  453. //TODO : consider factoring createForward into this method.
  454. KMMessage *msg = retrievedMessage();
  455. if ( !msg || !msg->codec() ) {
  456. return Failed;
  457. }
  458. KMMessage *fmsg = msg->createForward();
  459. fmsg->setTo( KMMessage::decodeMailtoUrl( mUrl.path() ) );
  460. KMail::Composer * win = KMail::makeComposer( fmsg );
  461. win->setCharset(msg->codec()->mimeName(), true);
  462. win->show();
  463. return OK;
  464. }
  465. KMAddBookmarksCommand::KMAddBookmarksCommand( const KURL &url, TQWidget *parent )
  466. : KMCommand( parent ), mUrl( url )
  467. {
  468. }
  469. KMCommand::Result KMAddBookmarksCommand::execute()
  470. {
  471. TQString filename = locateLocal( "data", TQString::fromLatin1("konqueror/bookmarks.xml") );
  472. KBookmarkManager *bookManager = KBookmarkManager::managerForFile( filename,
  473. false );
  474. KBookmarkGroup group = bookManager->root();
  475. group.addBookmark( bookManager, mUrl.path(), KURL( mUrl ) );
  476. if( bookManager->save() ) {
  477. bookManager->emitChanged( group );
  478. }
  479. return OK;
  480. }
  481. KMMailtoAddAddrBookCommand::KMMailtoAddAddrBookCommand( const KURL &url,
  482. TQWidget *parent )
  483. : KMCommand( parent ), mUrl( url )
  484. {
  485. }
  486. KMCommand::Result KMMailtoAddAddrBookCommand::execute()
  487. {
  488. KAddrBookExternal::addEmail( KMMessage::decodeMailtoUrl( mUrl.path() ),
  489. parentWidget() );
  490. return OK;
  491. }
  492. KMMailtoOpenAddrBookCommand::KMMailtoOpenAddrBookCommand( const KURL &url,
  493. TQWidget *parent )
  494. : KMCommand( parent ), mUrl( url )
  495. {
  496. }
  497. KMCommand::Result KMMailtoOpenAddrBookCommand::execute()
  498. {
  499. KAddrBookExternal::openEmail( KMMessage::decodeMailtoUrl( mUrl.path() ),
  500. parentWidget() );
  501. return OK;
  502. }
  503. KMUrlCopyCommand::KMUrlCopyCommand( const KURL &url, KMMainWidget *mainWidget )
  504. :mUrl( url ), mMainWidget( mainWidget )
  505. {
  506. }
  507. KMCommand::Result KMUrlCopyCommand::execute()
  508. {
  509. TQClipboard* clip = TQApplication::clipboard();
  510. if (mUrl.protocol() == "mailto") {
  511. // put the url into the mouse selection and the clipboard
  512. TQString address = KMMessage::decodeMailtoUrl( mUrl.path() );
  513. clip->setSelectionMode( true );
  514. clip->setText( address );
  515. clip->setSelectionMode( false );
  516. clip->setText( address );
  517. KPIM::BroadcastStatus::instance()->setStatusMsg( i18n( "Address copied to clipboard." ));
  518. } else {
  519. // put the url into the mouse selection and the clipboard
  520. clip->setSelectionMode( true );
  521. clip->setText( mUrl.url() );
  522. clip->setSelectionMode( false );
  523. clip->setText( mUrl.url() );
  524. KPIM::BroadcastStatus::instance()->setStatusMsg( i18n( "URL copied to clipboard." ));
  525. }
  526. return OK;
  527. }
  528. KMUrlOpenCommand::KMUrlOpenCommand( const KURL &url, KMReaderWin *readerWin )
  529. :mUrl( url ), mReaderWin( readerWin )
  530. {
  531. }
  532. KMCommand::Result KMUrlOpenCommand::execute()
  533. {
  534. if ( !mUrl.isEmpty() )
  535. mReaderWin->slotUrlOpen( mUrl, KParts::URLArgs() );
  536. return OK;
  537. }
  538. KMUrlSaveCommand::KMUrlSaveCommand( const KURL &url, TQWidget *parent )
  539. : KMCommand( parent ), mUrl( url )
  540. {
  541. }
  542. KMCommand::Result KMUrlSaveCommand::execute()
  543. {
  544. if ( mUrl.isEmpty() )
  545. return OK;
  546. KURL saveUrl = KFileDialog::getSaveURL(mUrl.fileName(), TQString(),
  547. parentWidget() );
  548. if ( saveUrl.isEmpty() )
  549. return Canceled;
  550. if ( TDEIO::NetAccess::exists( saveUrl, false, parentWidget() ) )
  551. {
  552. if (KMessageBox::warningContinueCancel(0,
  553. i18n("<qt>File <b>%1</b> exists.<br>Do you want to replace it?</qt>")
  554. .arg(saveUrl.prettyURL()), i18n("Save to File"), i18n("&Replace"))
  555. != KMessageBox::Continue)
  556. return Canceled;
  557. }
  558. TDEIO::Job *job = TDEIO::file_copy(mUrl, saveUrl, -1, true);
  559. connect(job, TQT_SIGNAL(result(TDEIO::Job*)), TQT_SLOT(slotUrlSaveResult(TDEIO::Job*)));
  560. setEmitsCompletedItself( true );
  561. return OK;
  562. }
  563. void KMUrlSaveCommand::slotUrlSaveResult( TDEIO::Job *job )
  564. {
  565. if ( job->error() ) {
  566. job->showErrorDialog();
  567. setResult( Failed );
  568. emit completed( this );
  569. }
  570. else {
  571. setResult( OK );
  572. emit completed( this );
  573. }
  574. }
  575. KMEditMsgCommand::KMEditMsgCommand( TQWidget *parent, KMMessage *msg )
  576. :KMCommand( parent, msg )
  577. {
  578. }
  579. KMCommand::Result KMEditMsgCommand::execute()
  580. {
  581. KMMessage *msg = retrievedMessage();
  582. if ( !msg || !msg->parent() ||
  583. ( !kmkernel->folderIsDraftOrOutbox( msg->parent() ) &&
  584. !kmkernel->folderIsTemplates( msg->parent() ) ) )
  585. return Failed;
  586. // Remember the old parent, we need it a bit further down to be able
  587. // to put the unchanged messsage back in the original folder if the nth
  588. // edit is discarded, for n > 1.
  589. KMFolder *parent = msg->parent();
  590. if ( parent )
  591. parent->take( parent->find( msg ) );
  592. KMail::Composer * win = KMail::makeComposer();
  593. msg->setTransferInProgress(false); // From here on on, the composer owns the message.
  594. win->setMsg(msg, false, true);
  595. win->setFolder( parent );
  596. win->show();
  597. return OK;
  598. }
  599. KMUseTemplateCommand::KMUseTemplateCommand( TQWidget *parent, KMMessage *msg )
  600. :KMCommand( parent, msg )
  601. {
  602. }
  603. KMCommand::Result KMUseTemplateCommand::execute()
  604. {
  605. KMMessage *msg = retrievedMessage();
  606. if ( !msg || !msg->parent() ||
  607. !kmkernel->folderIsTemplates( msg->parent() ) )
  608. return Failed;
  609. // Take a copy of the original message, which remains unchanged.
  610. KMMessage *newMsg = new KMMessage( new DwMessage( *msg->asDwMessage() ) );
  611. newMsg->setComplete( msg->isComplete() );
  612. // these fields need to be regenerated for the new message
  613. newMsg->removeHeaderField("Date");
  614. newMsg->removeHeaderField("Message-ID");
  615. KMail::Composer *win = KMail::makeComposer();
  616. newMsg->setTransferInProgress( false ); // From here on on, the composer owns the message.
  617. win->setMsg( newMsg, false, true );
  618. win->show();
  619. return OK;
  620. }
  621. KMShowMsgSrcCommand::KMShowMsgSrcCommand( TQWidget *parent,
  622. KMMessage *msg, bool fixedFont )
  623. :KMCommand( parent, msg ), mFixedFont( fixedFont )
  624. {
  625. // remember complete state
  626. mMsgWasComplete = msg->isComplete();
  627. }
  628. KMCommand::Result KMShowMsgSrcCommand::execute()
  629. {
  630. KMMessage *msg = retrievedMessage();
  631. if ( !msg || !msg->codec() ) {
  632. return Failed;
  633. }
  634. if ( msg->isComplete() && !mMsgWasComplete )
  635. msg->notify(); // notify observers as msg was transfered
  636. TQString str = msg->codec()->toUnicode( msg->asString() );
  637. MailSourceViewer *viewer = new MailSourceViewer(); // deletes itself upon close
  638. viewer->setCaption( i18n("Message as Plain Text") );
  639. viewer->setText(str);
  640. if( mFixedFont )
  641. viewer->setFont(TDEGlobalSettings::fixedFont());
  642. // Well, there is no widget to be seen here, so we have to use TQCursor::pos()
  643. // Update: (GS) I'm not going to make this code behave according to Xinerama
  644. // configuration because this is quite the hack.
  645. if (TQApplication::desktop()->isVirtualDesktop()) {
  646. int scnum = TQApplication::desktop()->screenNumber(TQCursor::pos());
  647. viewer->resize(TQApplication::desktop()->screenGeometry(scnum).width()/2,
  648. 2*TQApplication::desktop()->screenGeometry(scnum).height()/3);
  649. } else {
  650. viewer->resize(TQApplication::desktop()->geometry().width()/2,
  651. 2*TQApplication::desktop()->geometry().height()/3);
  652. }
  653. viewer->show();
  654. return OK;
  655. }
  656. static KURL subjectToUrl( const TQString & subject )
  657. {
  658. // We need to replace colons with underscores since those cause problems with KFileDialog (bug
  659. // in KFileDialog though) and also on Windows filesystems.
  660. // We also look at the special case of ": ", since converting that to "_ " would look strange,
  661. // simply "_" looks better.
  662. // We also don't allow filenames starting with a dot, since then the file is hidden and the poor
  663. // user can't find it anymore.
  664. // Don't allow filenames starting with a tilde either, since that will cause the file dialog to
  665. // discard the filename entirely.
  666. // https://issues.kolab.org/issue3805
  667. const TQString filter = i18n( "*.mbox|email messages (*.mbox)\n*|all files (*)" );
  668. TQString cleanSubject = subject.stripWhiteSpace()
  669. .replace( TQDir::separator(), '_' )
  670. .replace( ": ", "_" )
  671. .replace( ':', '_' )
  672. .replace( '.', '_' )
  673. .replace( '~', '_' );
  674. return KFileDialog::getSaveURL( cleanSubject, filter );
  675. }
  676. KMSaveMsgCommand::KMSaveMsgCommand( TQWidget *parent, KMMessage * msg )
  677. : KMCommand( parent ),
  678. mMsgListIndex( 0 ),
  679. mStandAloneMessage( 0 ),
  680. mOffset( 0 ),
  681. mTotalSize( msg ? msg->msgSize() : 0 )
  682. {
  683. if ( !msg ) return;
  684. setDeletesItself( true );
  685. // If the mail has a serial number, operate on sernums, if it does not
  686. // we need to work with the pointer, but can be reasonably sure it won't
  687. // go away, since it'll be an encapsulated message or one that was opened
  688. // from an .eml file.
  689. if ( msg->getMsgSerNum() != 0 ) {
  690. mMsgList.append( msg->getMsgSerNum() );
  691. if ( msg->parent() ) {
  692. msg->parent()->open( "kmsavemsgcommand" );
  693. }
  694. } else {
  695. mStandAloneMessage = msg;
  696. }
  697. mUrl = subjectToUrl( msg->cleanSubject() );
  698. }
  699. KMSaveMsgCommand::KMSaveMsgCommand( TQWidget *parent,
  700. const TQPtrList<KMMsgBase> &msgList )
  701. : KMCommand( parent ),
  702. mMsgListIndex( 0 ),
  703. mStandAloneMessage( 0 ),
  704. mOffset( 0 ),
  705. mTotalSize( 0 )
  706. {
  707. if (!msgList.getFirst())
  708. return;
  709. setDeletesItself( true );
  710. KMMsgBase *msgBase = msgList.getFirst();
  711. // We operate on serNums and not the KMMsgBase pointers, as those can
  712. // change, or become invalid when changing the current message, switching
  713. // folders, etc.
  714. TQPtrListIterator<KMMsgBase> it(msgList);
  715. while ( it.current() ) {
  716. mMsgList.append( (*it)->getMsgSerNum() );
  717. mTotalSize += (*it)->msgSize();
  718. if ((*it)->parent() != 0)
  719. (*it)->parent()->open("kmcommand");
  720. ++it;
  721. }
  722. mMsgListIndex = 0;
  723. mUrl = subjectToUrl( msgBase->cleanSubject() );
  724. }
  725. KURL KMSaveMsgCommand::url()
  726. {
  727. return mUrl;
  728. }
  729. KMCommand::Result KMSaveMsgCommand::execute()
  730. {
  731. mJob = TDEIO::put( mUrl, S_IRUSR|S_IWUSR, false, false );
  732. mJob->slotTotalSize( mTotalSize );
  733. mJob->setAsyncDataEnabled( true );
  734. mJob->setReportDataSent( true );
  735. connect(mJob, TQT_SIGNAL(dataReq(TDEIO::Job*, TQByteArray &)),
  736. TQT_SLOT(slotSaveDataReq()));
  737. connect(mJob, TQT_SIGNAL(result(TDEIO::Job*)),
  738. TQT_SLOT(slotSaveResult(TDEIO::Job*)));
  739. setEmitsCompletedItself( true );
  740. return OK;
  741. }
  742. void KMSaveMsgCommand::slotSaveDataReq()
  743. {
  744. int remainingBytes = mData.size() - mOffset;
  745. if ( remainingBytes > 0 ) {
  746. // eat leftovers first
  747. if ( remainingBytes > MAX_CHUNK_SIZE )
  748. remainingBytes = MAX_CHUNK_SIZE;
  749. TQByteArray data;
  750. data.duplicate( mData.data() + mOffset, remainingBytes );
  751. mJob->sendAsyncData( data );
  752. mOffset += remainingBytes;
  753. return;
  754. }
  755. // No leftovers, process next message.
  756. if ( mMsgListIndex < mMsgList.size() ) {
  757. KMMessage *msg = 0;
  758. int idx = -1;
  759. KMFolder * p = 0;
  760. KMMsgDict::instance()->getLocation( mMsgList[mMsgListIndex], &p, &idx );
  761. assert( p );
  762. assert( idx >= 0 );
  763. //kdDebug() << "SERNUM: " << mMsgList[mMsgListIndex] << " idx: " << idx << " folder: " << p->prettyURL() << endl;
  764. const bool alreadyGot = p->isMessage( idx );
  765. msg = p->getMsg(idx);
  766. if ( msg ) {
  767. // Only unGet the message if it isn't already got.
  768. if ( !alreadyGot ) {
  769. mUngetMsgs.append( msg );
  770. }
  771. if ( msg->transferInProgress() ) {
  772. TQByteArray data = TQByteArray();
  773. mJob->sendAsyncData( data );
  774. }
  775. msg->setTransferInProgress( true );
  776. if ( msg->isComplete() ) {
  777. slotMessageRetrievedForSaving( msg );
  778. } else {
  779. // retrieve Message first
  780. if ( msg->parent() && !msg->isComplete() ) {
  781. FolderJob *job = msg->parent()->createJob( msg );
  782. job->setCancellable( false );
  783. connect(job, TQT_SIGNAL( messageRetrieved( KMMessage* ) ),
  784. this, TQT_SLOT( slotMessageRetrievedForSaving( KMMessage* ) ) );
  785. job->start();
  786. }
  787. }
  788. } else {
  789. mJob->slotError( TDEIO::ERR_ABORTED,
  790. i18n("The message was removed while saving it. "
  791. "It has not been saved.") );
  792. }
  793. } else {
  794. if ( mStandAloneMessage ) {
  795. // do the special case of a standalone message
  796. slotMessageRetrievedForSaving( mStandAloneMessage );
  797. mStandAloneMessage = 0;
  798. } else {
  799. // No more messages. Tell the putjob we are done.
  800. TQByteArray data = TQByteArray();
  801. mJob->sendAsyncData( data );
  802. }
  803. }
  804. }
  805. void KMSaveMsgCommand::slotMessageRetrievedForSaving(KMMessage *msg)
  806. {
  807. if ( msg ) {
  808. mData = KMFolderMbox::escapeFrom( msg->asDwString() );
  809. KMail::Util::insert( mData, 0, msg->mboxMessageSeparator() );
  810. KMail::Util::append( mData, "\n" );
  811. msg->setTransferInProgress(false);
  812. mOffset = 0;
  813. TQByteArray data;
  814. int size;
  815. // Unless it is great than 64 k send the whole message. tdeio buffers for us.
  816. if( mData.size() > (unsigned int) MAX_CHUNK_SIZE )
  817. size = MAX_CHUNK_SIZE;
  818. else
  819. size = mData.size();
  820. data.duplicate( mData, size );
  821. mJob->sendAsyncData( data );
  822. mOffset += size;
  823. }
  824. ++mMsgListIndex;
  825. // Get rid of the message.
  826. if ( msg && msg->parent() && msg->getMsgSerNum() &&
  827. mUngetMsgs.contains( msg ) ) {
  828. int idx = -1;
  829. KMFolder * p = 0;
  830. KMMsgDict::instance()->getLocation( msg, &p, &idx );
  831. assert( p == msg->parent() ); assert( idx >= 0 );
  832. p->unGetMsg( idx );
  833. p->close("kmcommand");
  834. }
  835. }
  836. void KMSaveMsgCommand::slotSaveResult(TDEIO::Job *job)
  837. {
  838. if (job->error())
  839. {
  840. if (job->error() == TDEIO::ERR_FILE_ALREADY_EXIST)
  841. {
  842. if (KMessageBox::warningContinueCancel(0,
  843. i18n("File %1 exists.\nDo you want to replace it?")
  844. .arg(mUrl.prettyURL()), i18n("Save to File"), i18n("&Replace"))
  845. == KMessageBox::Continue) {
  846. mOffset = 0;
  847. mJob = TDEIO::put( mUrl, S_IRUSR|S_IWUSR, true, false );
  848. mJob->slotTotalSize( mTotalSize );
  849. mJob->setAsyncDataEnabled( true );
  850. mJob->setReportDataSent( true );
  851. connect(mJob, TQT_SIGNAL(dataReq(TDEIO::Job*, TQByteArray &)),
  852. TQT_SLOT(slotSaveDataReq()));
  853. connect(mJob, TQT_SIGNAL(result(TDEIO::Job*)),
  854. TQT_SLOT(slotSaveResult(TDEIO::Job*)));
  855. }
  856. }
  857. else
  858. {
  859. job->showErrorDialog();
  860. setResult( Failed );
  861. emit completed( this );
  862. deleteLater();
  863. }
  864. } else {
  865. setResult( OK );
  866. emit completed( this );
  867. deleteLater();
  868. }
  869. }
  870. //-----------------------------------------------------------------------------
  871. KMOpenMsgCommand::KMOpenMsgCommand( TQWidget *parent, const KURL & url,
  872. const TQString & encoding )
  873. : KMCommand( parent ),
  874. mUrl( url ),
  875. mEncoding( encoding )
  876. {
  877. setDeletesItself( true );
  878. }
  879. KMCommand::Result KMOpenMsgCommand::execute()
  880. {
  881. if ( mUrl.isEmpty() ) {
  882. mUrl = KFileDialog::getOpenURL( ":OpenMessage", "message/rfc822 application/mbox",
  883. parentWidget(), i18n("Open Message") );
  884. }
  885. if ( mUrl.isEmpty() ) {
  886. setDeletesItself( false );
  887. return Canceled;
  888. }
  889. mJob = TDEIO::get( mUrl, false, false );
  890. mJob->setReportDataSent( true );
  891. connect( mJob, TQT_SIGNAL( data( TDEIO::Job *, const TQByteArray & ) ),
  892. this, TQT_SLOT( slotDataArrived( TDEIO::Job*, const TQByteArray & ) ) );
  893. connect( mJob, TQT_SIGNAL( result( TDEIO::Job * ) ),
  894. TQT_SLOT( slotResult( TDEIO::Job * ) ) );
  895. setEmitsCompletedItself( true );
  896. return OK;
  897. }
  898. void KMOpenMsgCommand::slotDataArrived( TDEIO::Job *, const TQByteArray & data )
  899. {
  900. if ( data.isEmpty() )
  901. return;
  902. mMsgString.append( data.data(), data.size() );
  903. }
  904. void KMOpenMsgCommand::slotResult( TDEIO::Job *job )
  905. {
  906. if ( job->error() ) {
  907. // handle errors
  908. job->showErrorDialog();
  909. setResult( Failed );
  910. emit completed( this );
  911. }
  912. else {
  913. int startOfMessage = 0;
  914. if ( mMsgString.compare( 0, 5, "From ", 5 ) == 0 ) {
  915. startOfMessage = mMsgString.find( '\n' );
  916. if ( startOfMessage == -1 ) {
  917. KMessageBox::sorry( parentWidget(),
  918. i18n( "The file does not contain a message." ) );
  919. setResult( Failed );
  920. emit completed( this );
  921. // Emulate closing of a secondary window so that KMail exits in case it
  922. // was started with the --view command line option. Otherwise an
  923. // invisible KMail would keep running.
  924. SecondaryWindow *win = new SecondaryWindow();
  925. win->close();
  926. win->deleteLater();
  927. deleteLater();
  928. return;
  929. }
  930. startOfMessage += 1; // the message starts after the '\n'
  931. }
  932. // check for multiple messages in the file
  933. bool multipleMessages = true;
  934. int endOfMessage = mMsgString.find( "\nFrom " );
  935. if ( endOfMessage == -1 ) {
  936. endOfMessage = mMsgString.length();
  937. multipleMessages = false;
  938. }
  939. DwMessage *dwMsg = new DwMessage;
  940. dwMsg->FromString( mMsgString.substr( startOfMessage,
  941. endOfMessage - startOfMessage ) );
  942. dwMsg->Parse();
  943. // check whether we have a message ( no headers => this isn't a message )
  944. if ( dwMsg->Headers().NumFields() == 0 ) {
  945. KMessageBox::sorry( parentWidget(),
  946. i18n( "The file does not contain a message." ) );
  947. delete dwMsg; dwMsg = 0;
  948. setResult( Failed );
  949. emit completed( this );
  950. // Emulate closing of a secondary window (see above).
  951. SecondaryWindow *win = new SecondaryWindow();
  952. win->close();
  953. win->deleteLater();
  954. deleteLater();
  955. return;
  956. }
  957. KMMessage *msg = new KMMessage( dwMsg );
  958. msg->setReadyToShow( true );
  959. KMReaderMainWin *win = new KMReaderMainWin();
  960. win->showMsg( mEncoding, msg );
  961. win->show();
  962. if ( multipleMessages )
  963. KMessageBox::information( win,
  964. i18n( "The file contains multiple messages. "
  965. "Only the first message is shown." ) );
  966. setResult( OK );
  967. emit completed( this );
  968. }
  969. deleteLater();
  970. }
  971. //-----------------------------------------------------------------------------
  972. //TODO: ReplyTo, NoQuoteReplyTo, ReplyList, ReplyToAll, ReplyAuthor
  973. // are all similar and should be factored
  974. KMReplyToCommand::KMReplyToCommand( TQWidget *parent, KMMessage *msg,
  975. const TQString &selection )
  976. : KMCommand( parent, msg ), mSelection( selection )
  977. {
  978. }
  979. KMCommand::Result KMReplyToCommand::execute()
  980. {
  981. KCursorSaver busy(KBusyPtr::busy());
  982. KMMessage *msg = retrievedMessage();
  983. if ( !msg || !msg->codec() ) {
  984. return Failed;
  985. }
  986. // Find the account that held the original message
  987. TQString accountName;
  988. KMFolder* parentFolder = msg->parent();
  989. if (parentFolder) {
  990. KMFolderDir* parentFolderDir = parentFolder->parent();
  991. while (parentFolderDir) {
  992. TQString prettyURL = parentFolderDir->prettyURL();
  993. if (prettyURL != "") {
  994. accountName = prettyURL;
  995. }
  996. parentFolderDir = parentFolderDir->parent();
  997. }
  998. }
  999. KMMessage *reply = msg->createReply( KMail::ReplySmart, mSelection, false, true, TQString(), accountName );
  1000. KMail::Composer * win = KMail::makeComposer( reply );
  1001. win->setCharset( msg->codec()->mimeName(), true );
  1002. win->setReplyFocus();
  1003. win->show();
  1004. return OK;
  1005. }
  1006. KMNoQuoteReplyToCommand::KMNoQuoteReplyToCommand( TQWidget *parent,
  1007. KMMessage *msg )
  1008. : KMCommand( parent, msg )
  1009. {
  1010. }
  1011. KMCommand::Result KMNoQuoteReplyToCommand::execute()
  1012. {
  1013. KCursorSaver busy(KBusyPtr::busy());
  1014. KMMessage *msg = retrievedMessage();
  1015. if ( !msg || !msg->codec() ) {
  1016. return Failed;
  1017. }
  1018. KMMessage *reply = msg->createReply( KMail::ReplySmart, "", true);
  1019. KMail::Composer * win = KMail::makeComposer( reply );
  1020. win->setCharset(msg->codec()->mimeName(), true);
  1021. win->setReplyFocus(false);
  1022. win->show();
  1023. return OK;
  1024. }
  1025. KMReplyListCommand::KMReplyListCommand( TQWidget *parent,
  1026. KMMessage *msg, const TQString &selection )
  1027. : KMCommand( parent, msg ), mSelection( selection )
  1028. {
  1029. }
  1030. KMCommand::Result KMReplyListCommand::execute()
  1031. {
  1032. KCursorSaver busy(KBusyPtr::busy());
  1033. KMMessage *msg = retrievedMessage();
  1034. if ( !msg || !msg->codec() ) {
  1035. return Failed;
  1036. }
  1037. KMMessage *reply = msg->createReply( KMail::ReplyList, mSelection);
  1038. KMail::Composer * win = KMail::makeComposer( reply );
  1039. win->setCharset(msg->codec()->mimeName(), true);
  1040. win->setReplyFocus(false);
  1041. win->show();
  1042. return OK;
  1043. }
  1044. KMReplyToAllCommand::KMReplyToAllCommand( TQWidget *parent,
  1045. KMMessage *msg, const TQString &selection )
  1046. :KMCommand( parent, msg ), mSelection( selection )
  1047. {
  1048. }
  1049. KMCommand::Result KMReplyToAllCommand::execute()
  1050. {
  1051. KCursorSaver busy(KBusyPtr::busy());
  1052. KMMessage *msg = retrievedMessage();
  1053. if ( !msg || !msg->codec() ) {
  1054. return Failed;
  1055. }
  1056. KMMessage *reply = msg->createReply( KMail::ReplyAll, mSelection );
  1057. KMail::Composer * win = KMail::makeComposer( reply );
  1058. win->setCharset( msg->codec()->mimeName(), true );
  1059. win->setReplyFocus();
  1060. win->show();
  1061. return OK;
  1062. }
  1063. KMReplyAuthorCommand::KMReplyAuthorCommand( TQWidget *parent, KMMessage *msg,
  1064. const TQString &selection )
  1065. : KMCommand( parent, msg ), mSelection( selection )
  1066. {
  1067. }
  1068. KMCommand::Result KMReplyAuthorCommand::execute()
  1069. {
  1070. KCursorSaver busy(KBusyPtr::busy());
  1071. KMMessage *msg = retrievedMessage();
  1072. if ( !msg || !msg->codec() ) {
  1073. return Failed;
  1074. }
  1075. KMMessage *reply = msg->createReply( KMail::ReplyAuthor, mSelection );
  1076. KMail::Composer * win = KMail::makeComposer( reply );
  1077. win->setCharset( msg->codec()->mimeName(), true );
  1078. win->setReplyFocus();
  1079. win->show();
  1080. return OK;
  1081. }
  1082. KMForwardInlineCommand::KMForwardInlineCommand( TQWidget *parent,
  1083. const TQPtrList<KMMsgBase> &msgList, uint identity )
  1084. : KMCommand( parent, msgList ),
  1085. mIdentity( identity )
  1086. {
  1087. }
  1088. KMForwardInlineCommand::KMForwardInlineCommand( TQWidget *parent,
  1089. KMMessage *msg, uint identity )
  1090. : KMCommand( parent, msg ),
  1091. mIdentity( identity )
  1092. {
  1093. }
  1094. KMCommand::Result KMForwardInlineCommand::execute()
  1095. {
  1096. TQPtrList<KMMessage> msgList = retrievedMsgs();
  1097. if (msgList.count() >= 2) { // Multiple forward
  1098. uint id = 0;
  1099. TQPtrList<KMMessage> linklist;
  1100. for ( KMMessage *msg = msgList.first(); msg; msg = msgList.next() ) {
  1101. // set the identity
  1102. if (id == 0)
  1103. id = msg->headerField( "X-KMail-Identity" ).stripWhiteSpace().toUInt();
  1104. // msgText += msg->createForwardBody();
  1105. linklist.append( msg );
  1106. }
  1107. if ( id == 0 )
  1108. id = mIdentity; // use folder identity if no message had an id set
  1109. KMMessage *fwdMsg = new KMMessage;
  1110. fwdMsg->initHeader( id );
  1111. fwdMsg->setAutomaticFields( true );
  1112. fwdMsg->setCharset( "utf-8" );
  1113. // fwdMsg->setBody( msgText );
  1114. for ( KMMessage *msg = linklist.first(); msg; msg = linklist.next() ) {
  1115. TemplateParser parser( fwdMsg, TemplateParser::Forward );
  1116. parser.setSelection( msg->body() ); // FIXME: Why is this needed?
  1117. parser.process( msg, 0, true );
  1118. fwdMsg->link( msg, KMMsgStatusForwarded );
  1119. }
  1120. KCursorSaver busy( KBusyPtr::busy() );
  1121. KMail::Composer * win = KMail::makeComposer( fwdMsg, id );
  1122. win->setCharset("");
  1123. win->show();
  1124. } else { // forward a single message at most
  1125. KMMessage *msg = msgList.getFirst();
  1126. if ( !msg || !msg->codec() )
  1127. return Failed;
  1128. KCursorSaver busy( KBusyPtr::busy() );
  1129. KMMessage *fwdMsg = msg->createForward();
  1130. uint id = msg->headerField( "X-KMail-Identity" ).stripWhiteSpace().toUInt();
  1131. if ( id == 0 )
  1132. id = mIdentity;
  1133. {
  1134. KMail::Composer * win = KMail::makeComposer( fwdMsg, id );
  1135. win->setCharset( fwdMsg->codec()->mimeName(), true );
  1136. win->show();
  1137. }
  1138. }
  1139. return OK;
  1140. }
  1141. KMForwardAttachedCommand::KMForwardAttachedCommand( TQWidget *parent,
  1142. const TQPtrList<KMMsgBase> &msgList, uint identity, KMail::Composer *win )
  1143. : KMCommand( parent, msgList ), mIdentity( identity ),
  1144. mWin( TQGuardedPtr<KMail::Composer>( win ))
  1145. {
  1146. }
  1147. KMForwardAttachedCommand::KMForwardAttachedCommand( TQWidget *parent,
  1148. KMMessage * msg, uint identity, KMail::Composer *win )
  1149. : KMCommand( parent, msg ), mIdentity( identity ),
  1150. mWin( TQGuardedPtr< KMail::Composer >( win ))
  1151. {
  1152. }
  1153. KMCommand::Result KMForwardAttachedCommand::execute()
  1154. {
  1155. TQPtrList<KMMessage> msgList = retrievedMsgs();
  1156. KMMessage *fwdMsg = new KMMessage;
  1157. if (msgList.count() >= 2) {
  1158. // don't respect X-KMail-Identity headers because they might differ for
  1159. // the selected mails
  1160. fwdMsg->initHeader(mIdentity);
  1161. }
  1162. else if (msgList.count() == 1) {
  1163. KMMessage *msg = msgList.getFirst();
  1164. fwdMsg->initFromMessage(msg);
  1165. fwdMsg->setSubject( msg->forwardSubject() );
  1166. }
  1167. fwdMsg->setAutomaticFields(true);
  1168. KCursorSaver busy(KBusyPtr::busy());
  1169. if (!mWin)
  1170. mWin = KMail::makeComposer(fwdMsg, mIdentity);
  1171. // iterate through all the messages to be forwarded
  1172. for (KMMessage *msg = msgList.first(); msg; msg = msgList.next()) {
  1173. // remove headers that shouldn't be forwarded
  1174. msg->removePrivateHeaderFields();
  1175. msg->removeHeaderField("BCC");
  1176. // set the part
  1177. KMMessagePart *msgPart = new KMMessagePart;
  1178. msgPart->setTypeStr("message");
  1179. msgPart->setSubtypeStr("rfc822");
  1180. msgPart->setCharset(msg->charset());
  1181. msgPart->setName("forwarded message");
  1182. msgPart->setContentDescription(msg->from()+": "+msg->subject());
  1183. msgPart->setContentDisposition( "inline" );
  1184. // THIS HAS TO BE AFTER setCte()!!!!
  1185. msgPart->setMessageBody( KMail::Util::ByteArray( msg->asDwString() ) );
  1186. msgPart->setCharset("");
  1187. fwdMsg->link(msg, KMMsgStatusForwarded);
  1188. mWin->addAttach(msgPart);
  1189. }
  1190. mWin->show();
  1191. return OK;
  1192. }
  1193. KMForwardDigestCommand::KMForwardDigestCommand( TQWidget *parent,
  1194. const TQPtrList<KMMsgBase> &msgList, uint identity, KMail::Composer *win )
  1195. : KMCommand( parent, msgList ), mIdentity( identity ),
  1196. mWin( TQGuardedPtr<KMail::Composer>( win ))
  1197. {
  1198. }
  1199. KMForwardDigestCommand::KMForwardDigestCommand( TQWidget *parent,
  1200. KMMessage * msg, uint identity, KMail::Composer *win )
  1201. : KMCommand( parent, msg ), mIdentity( identity ),
  1202. mWin( TQGuardedPtr< KMail::Composer >( win ))
  1203. {
  1204. }
  1205. KMCommand::Result KMForwardDigestCommand::execute()
  1206. {
  1207. TQPtrList<KMMessage> msgList = retrievedMsgs();
  1208. if ( msgList.count() < 2 )
  1209. return Undefined; // must have more than 1 for a digest
  1210. uint id = 0;
  1211. KMMessage *fwdMsg = new KMMessage;
  1212. KMMessagePart *msgPart = new KMMessagePart;
  1213. TQString msgPartText;
  1214. int msgCnt = 0; // incase there are some we can't forward for some reason
  1215. // dummy header initialization; initialization with the correct identity
  1216. // is done below
  1217. fwdMsg->initHeader( id );
  1218. fwdMsg->setAutomaticFields( true );
  1219. fwdMsg->mMsg->Headers().ContentType().CreateBoundary( 1 );
  1220. TQCString boundary( fwdMsg->mMsg->Headers().ContentType().Boundary().c_str() );
  1221. msgPartText = i18n("\nThis is a MIME digest forward. The content of the"
  1222. " message is contained in the attachment(s).\n\n\n");
  1223. // iterate through all the messages to be forwarded
  1224. for ( KMMessage *msg = msgList.first(); msg; msg = msgList.next() ) {
  1225. // set the identity
  1226. if ( id == 0 )
  1227. id = msg->headerField( "X-KMail-Identity" ).stripWhiteSpace().toUInt();
  1228. // set the part header
  1229. msgPartText += "--";
  1230. msgPartText += TQString::fromLatin1( boundary );
  1231. msgPartText += "\nContent-Type: MESSAGE/RFC822";
  1232. msgPartText += TQString( "; CHARSET=%1" ).arg( TQString(msg->charset()) );
  1233. msgPartText += '\n';
  1234. DwHeaders dwh;
  1235. dwh.MessageId().CreateDefault();
  1236. msgPartText += TQString( "Content-ID: %1\n" ).arg( dwh.MessageId().AsString().c_str() );
  1237. msgPartText += TQString( "Content-Description: %1" ).arg( msg->subject() );
  1238. if ( !msg->subject().contains( "(fwd)" ) )
  1239. msgPartText += " (fwd)";
  1240. msgPartText += "\n\n";
  1241. // remove headers that shouldn't be forwarded
  1242. msg->removePrivateHeaderFields();
  1243. msg->removeHeaderField( "BCC" );
  1244. // set the part
  1245. msgPartText += msg->headerAsString();
  1246. msgPartText += '\n';
  1247. msgPartText += msg->body();
  1248. msgPartText += '\n'; // eot
  1249. msgCnt++;
  1250. fwdMsg->link( msg, KMMsgStatusForwarded );
  1251. }
  1252. if ( id == 0 )
  1253. id = mIdentity; // use folder identity if no message had an id set
  1254. fwdMsg->initHeader( id );
  1255. msgPartText += "--";
  1256. msgPartText += TQString::fromLatin1( boundary );
  1257. msgPartText += "--\n";
  1258. TQCString tmp;
  1259. msgPart->setTypeStr( "MULTIPART" );
  1260. tmp.sprintf( "Digest; boundary=\"%s\"", boundary.data() );
  1261. msgPart->setSubtypeStr( tmp );
  1262. msgPart->setName( "unnamed" );
  1263. msgPart->setCte( DwMime::kCte7bit ); // does it have to be 7bit?
  1264. msgPart->setContentDescription( TQString( "Digest of %1 messages." ).arg( msgCnt ) );
  1265. // THIS HAS TO BE AFTER setCte()!!!!
  1266. msgPart->setBodyEncoded( TQCString( msgPartText.ascii() ) );
  1267. KCursorSaver busy( KBusyPtr::busy() );
  1268. KMail::Composer * win = KMail::makeComposer( fwdMsg, id );
  1269. win->addAttach( msgPart );
  1270. win->show();
  1271. return OK;
  1272. }
  1273. KMRedirectCommand::KMRedirectCommand( TQWidget *parent,
  1274. KMMessage *msg )
  1275. : KMCommand( parent, msg )
  1276. {
  1277. }
  1278. KMCommand::Result KMRedirectCommand::execute()
  1279. {
  1280. KMMessage *msg = retrievedMessage();
  1281. if ( !msg || !msg->codec() )
  1282. return Failed;
  1283. RedirectDialog dlg( parentWidget(), "redirect", true,
  1284. kmkernel->msgSender()->sendImmediate() );
  1285. if (dlg.exec()==TQDialog::Rejected) return Failed;
  1286. KMMessage *newMsg = msg->createRedirect( dlg.to() );
  1287. KMFilterAction::sendMDN( msg, KMime::MDN::Dispatched );
  1288. const KMail::MessageSender::SendMethod method = dlg.sendImmediate()
  1289. ? KMail::MessageSender::SendImmediate
  1290. : KMail::MessageSender::SendLater;
  1291. if ( !kmkernel->msgSender()->send( newMsg, method ) ) {
  1292. kdDebug(5006) << "KMRedirectCommand: could not redirect message (sending failed)" << endl;
  1293. return Failed; // error: couldn't send
  1294. }
  1295. return OK;
  1296. }
  1297. KMCustomReplyToCommand::KMCustomReplyToCommand( TQWidget *parent, KMMessage *msg,
  1298. const TQString &selection,
  1299. const TQString &tmpl )
  1300. : KMCommand( parent, msg ), mSelection( selection ), mTemplate( tmpl )
  1301. {
  1302. }
  1303. KMCommand::Result KMCustomReplyToCommand::execute()
  1304. {
  1305. KCursorSaver busy(KBusyPtr::busy());
  1306. KMMessage *msg = retrievedMessage();
  1307. if ( !msg || !msg->codec() ) {
  1308. return Failed;
  1309. }
  1310. KMMessage *reply = msg->createReply( KMail::ReplySmart, mSelection,
  1311. false, true, mTemplate );
  1312. KMail::Composer * win = KMail::makeComposer( reply );
  1313. win->setCharset( msg->codec()->mimeName(), true );
  1314. win->setReplyFocus();
  1315. win->show();
  1316. return OK;
  1317. }
  1318. KMCustomReplyAllToCommand::KMCustomReplyAllToCommand( TQWidget *parent, KMMessage *msg,
  1319. const TQString &selection,
  1320. const TQString &tmpl )
  1321. : KMCommand( parent, msg ), mSelection( selection ), mTemplate( tmpl )
  1322. {
  1323. }
  1324. KMCommand::Result KMCustomReplyAllToCommand::execute()
  1325. {
  1326. KCursorSaver busy(KBusyPtr::busy());
  1327. KMMessage *msg = retrievedMessage();
  1328. if ( !msg || !msg->codec() ) {
  1329. return Failed;
  1330. }
  1331. KMMessage *reply = msg->createReply( KMail::ReplyAll, mSelection,
  1332. false, true, mTemplate );
  1333. KMail::Composer * win = KMail::makeComposer( reply );
  1334. win->setCharset( msg->codec()->mimeName(), true );
  1335. win->setReplyFocus();
  1336. win->show();
  1337. return OK;
  1338. }
  1339. KMCustomForwardCommand::KMCustomForwardCommand( TQWidget *parent,
  1340. const TQPtrList<KMMsgBase> &msgList, uint identity, const TQString &tmpl )
  1341. : KMCommand( parent, msgList ),
  1342. mIdentity( identity ), mTemplate( tmpl )
  1343. {
  1344. }
  1345. KMCustomForwardCommand::KMCustomForwardCommand( TQWidget *parent,
  1346. KMMessage *msg, uint identity, const TQString &tmpl )
  1347. : KMCommand( parent, msg ),
  1348. mIdentity( identity ), mTemplate( tmpl )
  1349. {
  1350. }
  1351. KMCommand::Result KMCustomForwardCommand::execute()
  1352. {
  1353. TQPtrList<KMMessage> msgList = retrievedMsgs();
  1354. if (msgList.count() >= 2) { // Multiple forward
  1355. uint id = 0;
  1356. TQPtrList<KMMessage> linklist;
  1357. for ( KMMessage *msg = msgList.first(); msg; msg = msgList.next() ) {
  1358. // set the identity
  1359. if (id == 0)
  1360. id = msg->headerField( "X-KMail-Identity" ).stripWhiteSpace().toUInt();
  1361. // msgText += msg->createForwardBody();
  1362. linklist.append( msg );
  1363. }
  1364. if ( id == 0 )
  1365. id = mIdentity; // use folder identity if no message had an id set
  1366. KMMessage *fwdMsg = new KMMessage;
  1367. fwdMsg->initHeader( id );
  1368. fwdMsg->setAutomaticFields( true );
  1369. fwdMsg->setCharset( "utf-8" );
  1370. // fwdMsg->setBody( msgText );
  1371. for ( KMMessage *msg = linklist.first(); msg; msg = linklist.next() ) {
  1372. TemplateParser parser( fwdMsg, TemplateParser::Forward );
  1373. parser.setSelection( msg->body() ); // FIXME: Why is this needed?
  1374. parser.process( msg, 0, true );
  1375. fwdMsg->link( msg, KMMsgStatusForwarded );
  1376. }
  1377. KCursorSaver busy( KBusyPtr::busy() );
  1378. KMail::Composer * win = KMail::makeComposer( fwdMsg, id );
  1379. win->setCharset("");
  1380. win->show();
  1381. } else { // forward a single message at most
  1382. KMMessage *msg = msgList.getFirst();
  1383. if ( !msg || !msg->codec() )
  1384. return Failed;
  1385. KCursorSaver busy( KBusyPtr::busy() );
  1386. KMMessage *fwdMsg = msg->createForward( mTemplate );
  1387. uint id = msg->headerField( "X-KMail-Identity" ).stripWhiteSpace().toUInt();
  1388. if ( id == 0 )
  1389. id = mIdentity;
  1390. {
  1391. KMail::Composer * win = KMail::makeComposer( fwdMsg, id );
  1392. win->setCharset( fwdMsg->codec()->mimeName(), true );
  1393. win->show();
  1394. }
  1395. }
  1396. return OK;
  1397. }
  1398. KMPrintCommand::KMPrintCommand( TQWidget *parent, KMMessage *msg,
  1399. const KMail::HeaderStyle *headerStyle,
  1400. const KMail::HeaderStrategy *headerStrategy,
  1401. bool htmlOverride, bool htmlLoadExtOverride,
  1402. bool useFixedFont, const TQString & encoding )
  1403. : KMCommand( parent, msg ),
  1404. mHeaderStyle( headerStyle ), mHeaderStrategy( headerStrategy ),
  1405. mHtmlOverride( htmlOverride ),
  1406. mHtmlLoadExtOverride( htmlLoadExtOverride ),
  1407. mUseFixedFont( useFixedFont ), mEncoding( encoding )
  1408. {
  1409. if ( GlobalSettings::useDefaultFonts() )
  1410. mOverrideFont = TDEGlobalSettings::generalFont();
  1411. else {
  1412. TDEConfigGroup fonts( KMKernel::config(), "Fonts" );
  1413. TQString tmp = fonts.readEntry( "print-font", TDEGlobalSettings::generalFont().toString() );
  1414. mOverrideFont.fromString( tmp );
  1415. }
  1416. }
  1417. void KMPrintCommand::setOverrideFont( const TQFont& font )
  1418. {
  1419. mOverrideFont = font;
  1420. }
  1421. KMCommand::Result KMPrintCommand::execute()
  1422. {
  1423. KMReaderWin printWin( 0, 0, 0 );
  1424. printWin.setPrinting( true );
  1425. printWin.readConfig();
  1426. if ( mHeaderStyle != 0 && mHeaderStrategy != 0 )
  1427. printWin.setHeaderStyleAndStrategy( mHeaderStyle, mHeaderStrategy );
  1428. printWin.setHtmlOverride( mHtmlOverride );
  1429. printWin.setHtmlLoadExtOverride( mHtmlLoadExtOverride );
  1430. printWin.setUseFixedFont( mUseFixedFont );
  1431. printWin.setOverrideEncoding( mEncoding );
  1432. printWin.cssHelper()->setPrintFont( mOverrideFont );
  1433. printWin.setDecryptMessageOverwrite( true );
  1434. printWin.setMsg( retrievedMessage(), true );
  1435. printWin.printMsg();
  1436. return OK;
  1437. }
  1438. KMSeStatusCommand::KMSeStatusCommand( KMMsgStatus status,
  1439. const TQValueList<TQ_UINT32> &serNums, bool toggle )
  1440. : mStatus( status ), mSerNums( serNums ), mToggle( toggle )
  1441. {
  1442. }
  1443. KMCommand::Result KMSeStatusCommand::execute()
  1444. {
  1445. TQValueListIterator<TQ_UINT32> it;
  1446. int idx = -1;
  1447. KMFolder *folder = 0;
  1448. bool parenStatus = false;
  1449. // Toggle actions on threads toggle the whole thread
  1450. // depending on the state of the parent.
  1451. if (mToggle) {
  1452. KMMsgBase *msg;
  1453. KMMsgDict::instance()->getLocation( *mSerNums.begin(), &folder, &idx );
  1454. if (folder) {
  1455. msg = folder->getMsgBase(idx);
  1456. if (msg && (msg->status()&mStatus))
  1457. parenStatus = true;
  1458. else
  1459. parenStatus = false;
  1460. }
  1461. }
  1462. TQMap< KMFolder*, TQValueList<int> > folderMap;
  1463. for ( it = mSerNums.begin(); it != mSerNums.end(); ++it ) {
  1464. KMMsgDict::instance()->getLocation( *it, &folder, &idx );
  1465. if (folder) {
  1466. if (mToggle) {
  1467. KMMsgBase *msg = folder->getMsgBase(idx);
  1468. // check if we are already at the target toggle state
  1469. if (msg) {
  1470. bool myStatus;
  1471. if (msg->status()&mStatus)
  1472. myStatus = true;
  1473. else
  1474. myStatus = false;
  1475. if (myStatus != parenStatus)
  1476. continue;
  1477. }
  1478. }
  1479. /* Collect the ids for each folder in a separate list and
  1480. send them off in one go at the end. */
  1481. folderMap[folder].append(idx);
  1482. }
  1483. }
  1484. TQMapIterator< KMFolder*, TQValueList<int> > it2 = folderMap.begin();
  1485. while ( it2 != folderMap.end() ) {
  1486. KMFolder *f = it2.key();
  1487. f->setStatus( (*it2), mStatus, mToggle );
  1488. ++it2;
  1489. }
  1490. //kapp->dcopClient()->emitDCOPSignal( "unreadCountChanged()", TQByteArray() );
  1491. return OK;
  1492. }
  1493. KMFilterCommand::KMFilterCommand( const TQCString &field, const TQString &value )
  1494. : mField( field ), mValue( value )
  1495. {
  1496. }
  1497. KMCommand::Result KMFilterCommand::execute()
  1498. {
  1499. kmkernel->filterMgr()->createFilter( mField, mValue );
  1500. return OK;
  1501. }
  1502. KMFilterActionCommand::KMFilterActionCommand( TQWidget *parent,
  1503. const TQPtrList<KMMsgBase> &msgList,
  1504. KMFilter *filter )
  1505. : KMCommand( parent, msgList ), mFilter( filter )
  1506. {
  1507. TQPtrListIterator<KMMsgBase> it(msgList);
  1508. while ( it.current() ) {
  1509. serNumList.append( (*it)->getMsgSerNum() );
  1510. ++it;
  1511. }
  1512. }
  1513. KMCommand::Result KMFilterActionCommand::execute()
  1514. {
  1515. KCursorSaver busy( KBusyPtr::busy() );
  1516. int msgCount = 0;
  1517. int msgCountToFilter = serNumList.count();
  1518. ProgressItem* progressItem =
  1519. ProgressManager::createProgressItem ( "filter"+ProgressManager::getUniqueID(),
  1520. i18n( "Filtering messages" ) );
  1521. progressItem->setTotalItems( msgCountToFilter );
  1522. TQValueList<TQ_UINT32>::const_iterator it;
  1523. for ( it = serNumList.begin(); it != serNumList.end(); it++ ) {
  1524. TQ_UINT32 serNum = *it;
  1525. int diff = msgCountToFilter - ++msgCount;
  1526. if ( diff < 10 || !( msgCount % 20 ) || msgCount <= 10 ) {
  1527. progressItem->updateProgress();
  1528. TQString statusMsg = i18n("Filtering message %1 of %2");
  1529. statusMsg = statusMsg.arg( msgCount ).arg( msgCountToFilter );
  1530. KPIM::BroadcastStatus::instance()->setStatusMsg( statusMsg );
  1531. TDEApplication::kApplication()->eventLoop()->processEvents( TQEventLoop::ExcludeUserInput, 50 );
  1532. }
  1533. int filterResult = kmkernel->filterMgr()->process( serNum, mFilter );
  1534. if (filterResult == 2) {
  1535. // something went horribly wrong (out of space?)
  1536. perror("Critical error");
  1537. kmkernel->emergencyExit( i18n("Not enough free disk space?" ));
  1538. }
  1539. progressItem->incCompletedItems();
  1540. }
  1541. progressItem->setComplete();
  1542. progressItem = 0;
  1543. return OK;
  1544. }
  1545. KMMetaFilterActionCommand::KMMetaFilterActionCommand( KMFilter *filter,
  1546. KMHeaders *headers,
  1547. KMMainWidget *main )
  1548. : TQObject( main ),
  1549. mFilter( filter ), mHeaders( headers ), mMainWidget( main )
  1550. {
  1551. }
  1552. void KMMetaFilterActionCommand::start()
  1553. {
  1554. if (ActionScheduler::isEnabled() ) {
  1555. // use action scheduler
  1556. KMFilterMgr::FilterSet set = KMFilterMgr::All;
  1557. TQValueList<KMFilter*> filters;
  1558. filters.append( mFilter );
  1559. ActionScheduler *scheduler = new ActionScheduler( set, filters, mHeaders );
  1560. scheduler->setAlwaysMatch( true );
  1561. scheduler->setAutoDestruct( true );
  1562. int contentX, contentY;
  1563. HeaderItem *nextItem = mHeaders->prepareMove( &contentX, &contentY );
  1564. TQPtrList<KMMsgBase> msgList = *mHeaders->selectedMsgs(true);
  1565. mHeaders->finalizeMove( nextItem, contentX, contentY );
  1566. for (KMMsgBase *msg = msgList.first(); msg; msg = msgList.next())
  1567. scheduler->execFilters( msg );
  1568. } else {
  1569. KMCommand *filterCommand =
  1570. new KMFilterActionCommand( mMainWidget,
  1571. *mHeaders->selectedMsgs(), mFilter );
  1572. filterCommand->start();
  1573. int contentX, contentY;
  1574. HeaderItem *item = mHeaders->prepareMove( &contentX, &contentY );
  1575. mHeaders->finalizeMove( item, contentX, contentY );
  1576. }
  1577. }
  1578. FolderShortcutCommand::FolderShortcutCommand( KMMainWidget *mainwidget,
  1579. KMFolder *folder )
  1580. : mMainWidget( mainwidget ), mFolder( folder ), mAction( 0 )
  1581. {
  1582. }
  1583. FolderShortcutCommand::~FolderShortcutCommand()
  1584. {
  1585. if ( mAction ) mAction->unplugAll();
  1586. delete mAction;
  1587. }
  1588. void FolderShortcutCommand::start()
  1589. {
  1590. mMainWidget->slotSelectFolder( mFolder );
  1591. }
  1592. void FolderShortcutCommand::setAction( TDEAction* action )
  1593. {
  1594. mAction = action;
  1595. }
  1596. KMMailingListFilterCommand::KMMailingListFilterCommand( TQWidget *parent,
  1597. KMMessage *msg )
  1598. : KMCommand( parent, msg )
  1599. {
  1600. }
  1601. KMCommand::Result KMMailingListFilterCommand::execute()
  1602. {
  1603. TQCString name;
  1604. TQString value;
  1605. KMMessage *msg = retrievedMessage();
  1606. if (!msg)
  1607. return Failed;
  1608. if ( !MailingList::name( msg, name, value ).isEmpty() ) {
  1609. kmkernel->filterMgr()->createFilter( name, value );
  1610. return OK;
  1611. }
  1612. else
  1613. return Failed;
  1614. }
  1615. void KMMenuCommand::folderToPopupMenu(bool move,
  1616. TQObject *receiver, KMMenuToFolder *aMenuToFolder, TQPopupMenu *menu )
  1617. {
  1618. while ( menu->count() )
  1619. {
  1620. TQPopupMenu *popup = menu->findItem( menu->idAt( 0 ) )->popup();
  1621. if (popup)
  1622. delete popup;
  1623. else
  1624. menu->removeItemAt( 0 );
  1625. }
  1626. if (!kmkernel->imapFolderMgr()->dir().first() &&
  1627. !kmkernel->dimapFolderMgr()->dir().first())
  1628. { // only local folders
  1629. makeFolderMenu( &kmkernel->folderMgr()->dir(), move,
  1630. receiver, aMenuToFolder, menu );
  1631. } else {
  1632. // operate on top-level items
  1633. TQPopupMenu* subMenu = new TQPopupMenu(menu);
  1634. makeFolderMenu( &kmkernel->folderMgr()->dir(),
  1635. move, receiver, aMenuToFolder, subMenu );
  1636. menu->insertItem( i18n( "Local Folders" ), subMenu );
  1637. KMFolderDir* fdir = &kmkernel->imapFolderMgr()->dir();
  1638. for (KMFolderNode *node = fdir->first(); node; node = fdir->next()) {
  1639. if (node->isDir())
  1640. continue;
  1641. subMenu = new TQPopupMenu(menu);
  1642. makeFolderMenu( node, move, receiver, aMenuToFolder, subMenu );
  1643. menu->insertItem( node->label(), subMenu );
  1644. }
  1645. fdir = &kmkernel->dimapFolderMgr()->dir();
  1646. for (KMFolderNode *node = fdir->first(); node; node = fdir->next()) {
  1647. if (node->isDir())
  1648. continue;
  1649. subMenu = new TQPopupMenu(menu);
  1650. makeFolderMenu( node, move, receiver, aMenuToFolder, subMenu );
  1651. menu->insertItem( node->label(), subMenu );
  1652. }
  1653. }
  1654. }
  1655. void KMMenuCommand::makeFolderMenu(KMFolderNode* node, bool move,
  1656. TQObject *receiver, KMMenuToFolder *aMenuToFolder, TQPopupMenu *menu )
  1657. {
  1658. // connect the signals
  1659. if (move)
  1660. {
  1661. disconnect(menu, TQT_SIGNAL(activated(int)), receiver,
  1662. TQT_SLOT(moveSelectedToFolder(int)));
  1663. connect(menu, TQT_SIGNAL(activated(int)), receiver,
  1664. TQT_SLOT(moveSelectedToFolder(int)));
  1665. } else {
  1666. disconnect(menu, TQT_SIGNAL(activated(int)), receiver,
  1667. TQT_SLOT(copySelectedToFolder(int)));
  1668. connect(menu, TQT_SIGNAL(activated(int)), receiver,
  1669. TQT_SLOT(copySelectedToFolder(int)));
  1670. }
  1671. KMFolder *folder = 0;
  1672. KMFolderDir *folderDir = 0;
  1673. if (node->isDir()) {
  1674. folderDir = static_cast<KMFolderDir*>(node);
  1675. } else {
  1676. folder = static_cast<KMFolder*>(node);
  1677. folderDir = folder->child();
  1678. }
  1679. if (folder && !folder->noContent())
  1680. {
  1681. int menuId;
  1682. if (move)
  1683. menuId = menu->insertItem(i18n("Move to This Folder"));
  1684. else
  1685. menuId = menu->insertItem(i18n("Copy to This Folder"));
  1686. aMenuToFolder->insert( menuId, folder );
  1687. menu->setItemEnabled( menuId, !folder->isReadOnly() );
  1688. menu->insertSeparator();
  1689. }
  1690. if (!folderDir)
  1691. return;
  1692. for (KMFolderNode *it = folderDir->first(); it; it = folderDir->next() ) {
  1693. if (it->isDir())
  1694. continue;
  1695. KMFolder *child = static_cast<KMFolder*>(it);
  1696. TQString label = child->label();
  1697. label.replace("&","&&");
  1698. if (child->child() && child->child()->first()) {
  1699. // descend
  1700. TQPopupMenu *subMenu = new TQPopupMenu(menu, "subMenu");
  1701. makeFolderMenu( child, move, receiver,
  1702. aMenuToFolder, subMenu );
  1703. menu->insertItem( label, subMenu );
  1704. } else {
  1705. // insert an item
  1706. int menuId = menu->insertItem( label );
  1707. aMenuToFolder->insert( menuId, child );
  1708. menu->setItemEnabled( menuId, !child->isReadOnly() );
  1709. }
  1710. }
  1711. return;
  1712. }
  1713. KMCopyCommand::KMCopyCommand( KMFolder* destFolder,
  1714. const TQPtrList<KMMsgBase> &msgList )
  1715. :mDestFolder( destFolder ), mMsgList( msgList )
  1716. {
  1717. setDeletesItself( true );
  1718. }
  1719. KMCopyCommand::KMCopyCommand( KMFolder* destFolder, KMMessage * msg )
  1720. :mDestFolder( destFolder )
  1721. {
  1722. setDeletesItself( true );
  1723. mMsgList.append( &msg->toMsgBase() );
  1724. }
  1725. KMCommand::Result KMCopyCommand::execute()
  1726. {
  1727. KMMsgBase *msgBase;
  1728. KMMessage *msg, *newMsg;
  1729. int idx = -1;
  1730. bool isMessage;
  1731. TQPtrList<KMMessage> list;
  1732. TQPtrList<KMMessage> localList;
  1733. if (mDestFolder && mDestFolder->open("kmcommand") != 0)
  1734. {
  1735. deleteLater();
  1736. return Failed;
  1737. }
  1738. setEmitsCompletedItself( true );
  1739. KCursorSaver busy(KBusyPtr::busy());
  1740. for (msgBase = mMsgList.first(); msgBase; msgBase = mMsgList.next() )
  1741. {
  1742. KMFolder *srcFolder = msgBase->parent();
  1743. if (( isMessage = msgBase->isMessage() ))
  1744. {
  1745. msg = static_cast<KMMessage*>(msgBase);
  1746. } else {
  1747. idx = srcFolder->find(msgBase);
  1748. assert(idx != -1);
  1749. msg = srcFolder->getMsg(idx);
  1750. // corrupt IMAP cache, see FolderStorage::getMsg()
  1751. if ( msg == 0 ) {
  1752. KMessageBox::error( parentWidget(), i18n("Corrupt IMAP cache detected in folder %1. "
  1753. "Copying of messages aborted.").arg( srcFolder->prettyURL() ) );
  1754. deleteLater();
  1755. return Failed;
  1756. }
  1757. }
  1758. if (srcFolder && mDestFolder &&
  1759. (srcFolder->folderType()== KMFolderTypeImap) &&
  1760. (mDestFolder->folderType() == KMFolderTypeImap) &&
  1761. (static_cast<KMFolderImap*>(srcFolder->storage())->account() ==
  1762. static_cast<KMFolderImap*>(mDestFolder->storage())->account()))
  1763. {
  1764. // imap => imap with same account
  1765. list.append(msg);
  1766. } else {
  1767. newMsg = new KMMessage( new DwMessage( *msg->asDwMessage() ) );
  1768. newMsg->setComplete(msg->isComplete());
  1769. // make sure the attachment state is only calculated when it's complete
  1770. if (!newMsg->isComplete())
  1771. newMsg->setReadyToShow(false);
  1772. newMsg->setStatus(msg->status());
  1773. if (srcFolder && !newMsg->isComplete())
  1774. {
  1775. // imap => others
  1776. newMsg->setParent(msg->parent());
  1777. FolderJob *job = srcFolder->createJob(newMsg);
  1778. job->setCancellable( false );
  1779. mPendingJobs << job;
  1780. connect(job, TQT_SIGNAL(messageRetrieved(KMMessage*)),
  1781. mDestFolder, TQT_SLOT(reallyAddCopyOfMsg(KMMessage*)));
  1782. connect( job, TQT_SIGNAL(result(KMail::FolderJob*)),
  1783. this, TQT_SLOT(slotJobFinished(KMail::FolderJob*)) );
  1784. job->start();
  1785. } else {
  1786. // local => others
  1787. localList.append(newMsg);
  1788. }
  1789. }
  1790. if (srcFolder && !isMessage && list.isEmpty())
  1791. {
  1792. assert(idx != -1);
  1793. srcFolder->unGetMsg( idx );
  1794. }
  1795. } // end for
  1796. bool deleteNow = false;
  1797. if (!localList.isEmpty())
  1798. {
  1799. TQValueList<int> index;
  1800. mDestFolder->addMsg( localList, index );
  1801. for ( TQValueListIterator<int> it = index.begin(); it != index.end(); ++it ) {
  1802. mDestFolder->unGetMsg( *it );
  1803. }
  1804. if ( mDestFolder->folderType() == KMFolderTypeImap ) {
  1805. if ( mPendingJobs.isEmpty() ) {
  1806. // wait for the end of the copy before closing the folder
  1807. KMFolderImap *imapDestFolder = static_cast<KMFolderImap*>(mDestFolder->storage());
  1808. connect( imapDestFolder, TQT_SIGNAL( folderComplete( KMFolderImap*, bool ) ),
  1809. this, TQT_SLOT( slotFolderComplete( KMFolderImap*, bool ) ) );
  1810. }
  1811. } else {
  1812. deleteNow = list.isEmpty() && mPendingJobs.isEmpty(); // we're done if there are no other mails we need to fetch
  1813. }
  1814. }
  1815. //TODO: Get rid of the other cases just use this one for all types of folder
  1816. //TODO: requires adding copyMsg and getFolder methods to KMFolder.h
  1817. if (!list.isEmpty())
  1818. {
  1819. // copy the message(s); note: the list is empty afterwards!
  1820. KMFolderImap *imapDestFolder = static_cast<KMFolderImap*>(mDestFolder->storage());
  1821. connect( imapDestFolder, TQT_SIGNAL( folderComplete( KMFolderImap*, bool ) ),
  1822. this, TQT_SLOT( slotFolderComplete( KMFolderImap*, bool ) ) );
  1823. imapDestFolder->copyMsg(list);
  1824. imapDestFolder->getFolder();
  1825. }
  1826. // only close the folder and delete the job if we're done
  1827. // otherwise this is done in slotMsgAdded or slotFolderComplete
  1828. if ( deleteNow )
  1829. {
  1830. mDestFolder->close("kmcommand");
  1831. setResult( OK );
  1832. emit completed( this );
  1833. deleteLater();
  1834. }
  1835. return OK;
  1836. }
  1837. void KMCopyCommand::slotJobFinished(KMail::FolderJob * job)
  1838. {
  1839. mPendingJobs.remove( job );
  1840. if ( job->error() ) {
  1841. kdDebug(5006) << k_funcinfo << "folder job failed: " << job->error() << endl;
  1842. // kill all pending jobs
  1843. for ( TQValueList<KMail::FolderJob*>::Iterator it = mPendingJobs.begin(); it != mPendingJobs.end(); ++it ) {
  1844. disconnect( (*it), TQT_SIGNAL(result(KMail::FolderJob*)),
  1845. this, TQT_SLOT(slotJobFinished(KMail::FolderJob*)) );
  1846. (*it)->kill();
  1847. }
  1848. mPendingJobs.clear();
  1849. setResult( Failed );
  1850. }
  1851. if ( mPendingJobs.isEmpty() )
  1852. {
  1853. mDestFolder->close("kmcommand");
  1854. emit completed( this );
  1855. deleteLater();
  1856. }
  1857. }
  1858. void KMCopyCommand::slotFolderComplete( KMFolderImap*, bool success )
  1859. {
  1860. kdDebug(5006) << k_funcinfo << success << endl;
  1861. if ( !success )
  1862. setResult( Failed );
  1863. mDestFolder->close( "kmcommand" );
  1864. emit completed( this );
  1865. deleteLater();
  1866. }
  1867. KMMoveCommand::KMMoveCommand( KMFolder* destFolder,
  1868. const TQPtrList<KMMsgBase> &msgList)
  1869. : mDestFolder( destFolder ), mProgressItem( 0 )
  1870. {
  1871. TQPtrList<KMMsgBase> tmp = msgList;
  1872. for ( KMMsgBase *msgBase = tmp.first(); msgBase; msgBase = tmp.next() )
  1873. mSerNumList.append( msgBase->getMsgSerNum() );
  1874. }
  1875. KMMoveCommand::KMMoveCommand( KMFolder* destFolder,
  1876. KMMessage *msg )
  1877. : mDestFolder( destFolder ), mProgressItem( 0 )
  1878. {
  1879. mSerNumList.append( msg->getMsgSerNum() );
  1880. }
  1881. KMMoveCommand::KMMoveCommand( KMFolder* destFolder,
  1882. KMMsgBase *msgBase )
  1883. : mDestFolder( destFolder ), mProgressItem( 0 )
  1884. {
  1885. mSerNumList.append( msgBase->getMsgSerNum() );
  1886. }
  1887. KMMoveCommand::KMMoveCommand( TQ_UINT32 )
  1888. : mProgressItem( 0 )
  1889. {
  1890. }
  1891. KMCommand::Result KMMoveCommand::execute()
  1892. {
  1893. setEmitsCompletedItself( true );
  1894. setDeletesItself( true );
  1895. typedef TQMap< KMFolder*, TQPtrList<KMMessage>* > FolderToMessageListMap;
  1896. FolderToMessageListMap folderDeleteList;
  1897. if (mDestFolder && mDestFolder->open("kmcommand") != 0) {
  1898. completeMove( Failed );
  1899. return Failed;
  1900. }
  1901. KCursorSaver busy(KBusyPtr::busy());
  1902. // TODO set SSL state according to source and destfolder connection?
  1903. Q_ASSERT( !mProgressItem );
  1904. mProgressItem =
  1905. ProgressManager::createProgressItem (
  1906. "move"+ProgressManager::getUniqueID(),
  1907. mDestFolder ? i18n( "Moving messages" ) : i18n( "Deleting messages" ) );
  1908. connect( mProgressItem, TQT_SIGNAL( progressItemCanceled( KPIM::ProgressItem* ) ),
  1909. this, TQT_SLOT( slotMoveCanceled() ) );
  1910. KMMessage *msg;
  1911. int rc = 0;
  1912. int index;
  1913. TQPtrList<KMMessage> list;
  1914. int undoId = -1;
  1915. mCompleteWithAddedMsg = false;
  1916. if (mDestFolder) {
  1917. connect (mDestFolder, TQT_SIGNAL(msgAdded(KMFolder*, TQ_UINT32)),
  1918. this, TQT_SLOT(slotMsgAddedToDestFolder(KMFolder*, TQ_UINT32)));
  1919. mLostBoys = mSerNumList;
  1920. }
  1921. mProgressItem->setTotalItems( mSerNumList.count() );
  1922. for ( TQValueList<TQ_UINT32>::ConstIterator it = mSerNumList.constBegin(); it != mSerNumList.constEnd(); ++it ) {
  1923. if ( *it == 0 ) {
  1924. kdDebug(5006) << k_funcinfo << "serial number == 0!" << endl;
  1925. continue; // invalid message
  1926. }
  1927. KMFolder *srcFolder = 0;
  1928. int idx = -1;
  1929. KMMsgDict::instance()->getLocation( *it, &srcFolder, &idx );
  1930. if (srcFolder == mDestFolder)
  1931. continue;
  1932. assert(srcFolder);
  1933. assert(idx != -1);
  1934. if ( !srcFolder->isOpened() ) {
  1935. srcFolder->open( "kmmovecommand" );
  1936. mOpenedFolders.append( srcFolder );
  1937. }
  1938. msg = srcFolder->getMsg(idx);
  1939. if ( !msg ) {
  1940. kdDebug(5006) << k_funcinfo << "No message found for serial number " << *it << endl;
  1941. continue;
  1942. }
  1943. bool undo = msg->enableUndo();
  1944. if ( msg && msg->transferInProgress() &&
  1945. srcFolder->folderType() == KMFolderTypeImap )
  1946. {
  1947. // cancel the download
  1948. msg->setTransferInProgress( false, true );
  1949. static_cast<KMFolderImap*>(srcFolder->storage())->ignoreJobsForMessage( msg );
  1950. }
  1951. if (mDestFolder) {
  1952. if (mDestFolder->folderType() == KMFolderTypeImap) {
  1953. /* If we are moving to an imap folder, connect to it's completed
  1954. * signal so we notice when all the mails should have showed up in it
  1955. * but haven't for some reason. */
  1956. KMFolderImap *imapFolder = static_cast<KMFolderImap*> ( mDestFolder->storage() );
  1957. disconnect (imapFolder, TQT_SIGNAL(folderComplete( KMFolderImap*, bool )),
  1958. this, TQT_SLOT(slotImapFolderCompleted( KMFolderImap*, bool )));
  1959. connect (imapFolder, TQT_SIGNAL(folderComplete( KMFolderImap*, bool )),
  1960. this, TQT_SLOT(slotImapFolderCompleted( KMFolderImap*, bool )));
  1961. list.append(msg);
  1962. } else {
  1963. // We are moving to a local folder.
  1964. if ( srcFolder->folderType() == KMFolderTypeImap )
  1965. {
  1966. // do not complete here but wait until all messages are transferred
  1967. mCompleteWithAddedMsg = true;
  1968. }
  1969. rc = mDestFolder->moveMsg(msg, &index);
  1970. if (rc == 0 && index != -1) {
  1971. KMMsgBase *mb = mDestFolder->unGetMsg( mDestFolder->count() - 1 );
  1972. if (undo && mb)
  1973. {
  1974. if ( undoId == -1 )
  1975. undoId = kmkernel->undoStack()->newUndoAction( srcFolder, mDestFolder );
  1976. kmkernel->undoStack()->addMsgToAction( undoId, mb->getMsgSerNum() );
  1977. }
  1978. } else if (rc != 0) {
  1979. // Something went wrong. Stop processing here, it is likely that the
  1980. // other moves would fail as well.
  1981. completeMove( Failed );
  1982. return Failed;
  1983. }
  1984. }
  1985. } else {
  1986. // really delete messages that are already in the trash folder or if
  1987. // we are really, really deleting, not just moving to trash
  1988. if (srcFolder->folderType() == KMFolderTypeImap) {
  1989. if (!folderDeleteList[srcFolder])
  1990. folderDeleteList[srcFolder] = new TQPtrList<KMMessage>;
  1991. folderDeleteList[srcFolder]->append( msg );
  1992. } else {
  1993. srcFolder->removeMsg(idx);
  1994. delete msg;
  1995. }
  1996. }
  1997. }
  1998. if (!list.isEmpty() && mDestFolder) {
  1999. // will be completed with folderComplete signal
  2000. mDestFolder->moveMsg(list, &index);
  2001. } else {
  2002. FolderToMessageListMap::Iterator it;
  2003. for ( it = folderDeleteList.begin(); it != folderDeleteList.end(); ++it ) {
  2004. it.key()->removeMsg(*it.data());
  2005. delete it.data();
  2006. }
  2007. if ( !mCompleteWithAddedMsg ) {
  2008. // imap folders will be completed in slotMsgAddedToDestFolder
  2009. completeMove( OK );
  2010. }
  2011. }
  2012. return OK;
  2013. }
  2014. void KMMoveCommand::slotImapFolderCompleted(KMFolderImap* imapFolder, bool success)
  2015. {
  2016. disconnect (imapFolder, TQT_SIGNAL(folderComplete( KMFolderImap*, bool )),
  2017. this, TQT_SLOT(slotImapFolderCompleted( KMFolderImap*, bool )));
  2018. if ( success ) {
  2019. // the folder was checked successfully but we were still called, so check
  2020. // if we are still waiting for messages to show up. If so, uidValidity
  2021. // changed, or something else went wrong. Clean up.
  2022. /* Unfortunately older UW imap servers change uid validity for each put job.
  2023. * Yes, it is really that broken. *sigh* So we cannot report error here, I guess. */
  2024. if ( !mLostBoys.isEmpty() ) {
  2025. kdDebug(5006) << "### Not all moved messages reported back that they were " << endl
  2026. << "### added to the target folder. Did uidValidity change? " << endl;
  2027. }
  2028. completeMove( OK );
  2029. } else {
  2030. // Should we inform the user here or leave that to the caller?
  2031. completeMove( Failed );
  2032. }
  2033. }
  2034. void KMMoveCommand::slotMsgAddedToDestFolder(KMFolder *folder, TQ_UINT32 serNum)
  2035. {
  2036. if ( folder != mDestFolder || mLostBoys.find( serNum ) == mLostBoys.end() ) {
  2037. //kdDebug(5006) << "KMMoveCommand::msgAddedToDestFolder different "
  2038. // "folder or invalid serial number." << endl;
  2039. return;
  2040. }
  2041. mLostBoys.remove(serNum);
  2042. if ( mLostBoys.isEmpty() ) {
  2043. // we are done. All messages transferred to the host succesfully
  2044. disconnect (mDestFolder, TQT_SIGNAL(msgAdded(KMFolder*, TQ_UINT32)),
  2045. this, TQT_SLOT(slotMsgAddedToDestFolder(KMFolder*, TQ_UINT32)));
  2046. if (mDestFolder && mDestFolder->folderType() != KMFolderTypeImap) {
  2047. mDestFolder->sync();
  2048. }
  2049. if ( mCompleteWithAddedMsg ) {
  2050. completeMove( OK );
  2051. }
  2052. } else {
  2053. if ( mProgressItem ) {
  2054. mProgressItem->incCompletedItems();
  2055. mProgressItem->updateProgress();
  2056. }
  2057. }
  2058. }
  2059. void KMMoveCommand::completeMove( Result result )
  2060. {
  2061. if ( mDestFolder )
  2062. mDestFolder->close("kmcommand");
  2063. while ( !mOpenedFolders.empty() ) {
  2064. KMFolder *folder = mOpenedFolders.back();
  2065. mOpenedFolders.pop_back();
  2066. folder->close("kmcommand");
  2067. }
  2068. if ( mProgressItem ) {
  2069. mProgressItem->setComplete();
  2070. mProgressItem = 0;
  2071. }
  2072. setResult( result );
  2073. emit completed( this );
  2074. deleteLater();
  2075. }
  2076. void KMMoveCommand::slotMoveCanceled()
  2077. {
  2078. completeMove( Canceled );
  2079. }
  2080. // srcFolder doesn't make much sense for searchFolders
  2081. KMDeleteMsgCommand::KMDeleteMsgCommand( KMFolder* srcFolder,
  2082. const TQPtrList<KMMsgBase> &msgList )
  2083. :KMMoveCommand( findTrashFolder( srcFolder ), msgList)
  2084. {
  2085. srcFolder->open("kmcommand");
  2086. mOpenedFolders.push_back( srcFolder );
  2087. }
  2088. KMDeleteMsgCommand::KMDeleteMsgCommand( KMFolder* srcFolder, KMMessage * msg )
  2089. :KMMoveCommand( findTrashFolder( srcFolder ), msg)
  2090. {
  2091. srcFolder->open("kmcommand");
  2092. mOpenedFolders.push_back( srcFolder );
  2093. }
  2094. KMDeleteMsgCommand::KMDeleteMsgCommand( TQ_UINT32 sernum )
  2095. :KMMoveCommand( sernum )
  2096. {
  2097. if ( !sernum ) {
  2098. setDestFolder( 0 );
  2099. return;
  2100. }
  2101. KMFolder *srcFolder = 0;
  2102. int idx;
  2103. KMMsgDict::instance()->getLocation( sernum, &srcFolder, &idx );
  2104. if ( srcFolder ) {
  2105. KMMsgBase *msg = srcFolder->getMsgBase( idx );
  2106. srcFolder->open("kmcommand");
  2107. mOpenedFolders.push_back( srcFolder );
  2108. addMsg( msg );
  2109. }
  2110. setDestFolder( findTrashFolder( srcFolder ) );
  2111. }
  2112. KMFolder * KMDeleteMsgCommand::findTrashFolder( KMFolder * folder )
  2113. {
  2114. KMFolder* trash = folder->trashFolder();
  2115. if( !trash )
  2116. trash = kmkernel->trashFolder();
  2117. if( trash != folder )
  2118. return trash;
  2119. return 0;
  2120. }
  2121. KMUrlClickedCommand::KMUrlClickedCommand( const KURL &url, uint identity,
  2122. KMReaderWin *readerWin, bool htmlPref, KMMainWidget *mainWidget )
  2123. :mUrl( url ), mIdentity( identity ), mReaderWin( readerWin ),
  2124. mHtmlPref( htmlPref ), mMainWidget( mainWidget )
  2125. {
  2126. }
  2127. KMCommand::Result KMUrlClickedCommand::execute()
  2128. {
  2129. KMMessage* msg;
  2130. if (mUrl.protocol() == "mailto")
  2131. {
  2132. msg = new KMMessage;
  2133. msg->initHeader(mIdentity);
  2134. msg->setCharset("utf-8");
  2135. msg->setTo( KMMessage::decodeMailtoUrl( mUrl.path() ) );
  2136. TQString query=mUrl.query();
  2137. while (!query.isEmpty()) {
  2138. TQString queryPart;
  2139. int secondQuery = query.find('?',1);
  2140. if (secondQuery != -1)
  2141. queryPart = query.left(secondQuery);
  2142. else
  2143. queryPart = query;
  2144. query = query.mid(queryPart.length());
  2145. if (queryPart.left(9) == "?subject=")
  2146. msg->setSubject( KURL::decode_string(queryPart.mid(9)) );
  2147. else if (queryPart.left(6) == "?body=")
  2148. // It is correct to convert to latin1() as URL should not contain
  2149. // anything except ascii.
  2150. msg->setBody( KURL::decode_string(queryPart.mid(6)).latin1() );
  2151. else if (queryPart.left(4) == "?cc=")
  2152. msg->setCc( KURL::decode_string(queryPart.mid(4)) );
  2153. }
  2154. KMail::Composer * win = KMail::makeComposer( msg, mIdentity );
  2155. win->setCharset("", true);
  2156. win->show();
  2157. }
  2158. else if ( mUrl.protocol() == "im" )
  2159. {
  2160. kmkernel->imProxy()->chatWithContact( mUrl.path() );
  2161. }
  2162. else if ((mUrl.protocol() == "http") || (mUrl.protocol() == "https") ||
  2163. (mUrl.protocol() == "ftp") || (mUrl.protocol() == "file") ||
  2164. (mUrl.protocol() == "ftps") || (mUrl.protocol() == "sftp" ) ||
  2165. (mUrl.protocol() == "help") || (mUrl.protocol() == "vnc") ||
  2166. (mUrl.protocol() == "smb") || (mUrl.protocol() == "fish") ||
  2167. (mUrl.protocol() == "news"))
  2168. {
  2169. KPIM::BroadcastStatus::instance()->setStatusMsg( i18n("Opening URL..."));
  2170. KMimeType::Ptr mime = KMimeType::findByURL( mUrl );
  2171. if (mime->name() == "application/x-desktop" ||
  2172. mime->name() == "application/x-executable" ||
  2173. mime->name() == "application/x-msdos-program" ||
  2174. mime->name() == "application/x-shellscript" )
  2175. {
  2176. if (KMessageBox::warningYesNo( 0, i18n( "<qt>Do you really want to execute <b>%1</b>?</qt>" )
  2177. .arg( mUrl.prettyURL() ), TQString(), i18n("Execute"), KStdGuiItem::cancel() ) != KMessageBox::Yes)
  2178. return Canceled;
  2179. }
  2180. KRun * runner = new KRun( mUrl );
  2181. runner->setRunExecutables( false );
  2182. }
  2183. else
  2184. return Failed;
  2185. return OK;
  2186. }
  2187. KMSaveAttachmentsCommand::KMSaveAttachmentsCommand( TQWidget *parent, KMMessage *msg )
  2188. : KMCommand( parent, msg ), mImplicitAttachments( true ), mEncoded( false )
  2189. {
  2190. }
  2191. KMSaveAttachmentsCommand::KMSaveAttachmentsCommand( TQWidget *parent, const TQPtrList<KMMsgBase>& msgs )
  2192. : KMCommand( parent, msgs ), mImplicitAttachments( true ), mEncoded( false )
  2193. {
  2194. }
  2195. KMSaveAttachmentsCommand::KMSaveAttachmentsCommand( TQWidget *parent, TQPtrList<partNode>& attachments,
  2196. KMMessage *msg, bool encoded )
  2197. : KMCommand( parent ), mImplicitAttachments( false ), mEncoded( encoded )
  2198. {
  2199. for ( TQPtrListIterator<partNode> it( attachments ); it.current(); ++it ) {
  2200. mAttachmentMap.insert( it.current(), msg );
  2201. }
  2202. }
  2203. KMCommand::Result KMSaveAttachmentsCommand::execute()
  2204. {
  2205. setEmitsCompletedItself( true );
  2206. if ( mImplicitAttachments ) {
  2207. TQPtrList<KMMessage> msgList = retrievedMsgs();
  2208. KMMessage *msg;
  2209. for ( TQPtrListIterator<KMMessage> itr( msgList );
  2210. ( msg = itr.current() );
  2211. ++itr ) {
  2212. partNode *rootNode = partNode::fromMessage( msg );
  2213. for ( partNode *child = rootNode; child;
  2214. child = child->firstChild() ) {
  2215. for ( partNode *node = child; node; node = node->nextSibling() ) {
  2216. if ( node->type() != DwMime::kTypeMultipart )
  2217. mAttachmentMap.insert( node, msg );
  2218. }
  2219. }
  2220. }
  2221. }
  2222. setDeletesItself( true );
  2223. // load all parts
  2224. KMLoadPartsCommand *command = new KMLoadPartsCommand( mAttachmentMap );
  2225. connect( command, TQT_SIGNAL( partsRetrieved() ),
  2226. this, TQT_SLOT( slotSaveAll() ) );
  2227. command->start();
  2228. return OK;
  2229. }
  2230. void KMSaveAttachmentsCommand::slotSaveAll()
  2231. {
  2232. // now that all message parts have been retrieved, remove all parts which
  2233. // don't represent an attachment if they were not explicitely passed in the
  2234. // c'tor
  2235. if ( mImplicitAttachments ) {
  2236. for ( PartNodeMessageMap::iterator it = mAttachmentMap.begin();
  2237. it != mAttachmentMap.end(); ) {
  2238. // only body parts which have a filename or a name parameter (except for
  2239. // the root node for which name is set to the message's subject) are
  2240. // considered attachments
  2241. if ( it.key()->msgPart().fileName().stripWhiteSpace().isEmpty() &&
  2242. ( it.key()->msgPart().name().stripWhiteSpace().isEmpty() ||
  2243. !it.key()->parentNode() ) ) {
  2244. PartNodeMessageMap::iterator delIt = it;
  2245. ++it;
  2246. mAttachmentMap.remove( delIt );
  2247. }
  2248. else
  2249. ++it;
  2250. }
  2251. if ( mAttachmentMap.isEmpty() ) {
  2252. KMessageBox::information( 0, i18n("Found no attachments to save.") );
  2253. setResult( OK ); // The user has already been informed.
  2254. emit completed( this );
  2255. deleteLater();
  2256. return;
  2257. }
  2258. }
  2259. KURL url, dirUrl;
  2260. if ( mAttachmentMap.count() > 1 ) {
  2261. // get the dir
  2262. dirUrl = KDirSelectDialog::selectDirectory( TQString(), false,
  2263. parentWidget(),
  2264. i18n("Save Attachments To") );
  2265. if ( !dirUrl.isValid() ) {
  2266. setResult( Canceled );
  2267. emit completed( this );
  2268. deleteLater();
  2269. return;
  2270. }
  2271. // we may not get a slash-terminated url out of KDirSelectDialog
  2272. dirUrl.adjustPath( 1 );
  2273. }
  2274. else {
  2275. // only one item, get the desired filename
  2276. partNode *node = mAttachmentMap.begin().key();
  2277. // replace all ':' with '_' because ':' isn't allowed on FAT volumes
  2278. TQString s =
  2279. node->msgPart().fileName().stripWhiteSpace().replace( ':', '_' );
  2280. if ( s.isEmpty() )
  2281. s = node->msgPart().name().stripWhiteSpace().replace( ':', '_' );
  2282. if ( s.isEmpty() )
  2283. s = i18n("filename for an unnamed attachment", "attachment.1");
  2284. url = KFileDialog::getSaveURL( s, TQString(), parentWidget(),
  2285. TQString() );
  2286. if ( url.isEmpty() ) {
  2287. setResult( Canceled );
  2288. emit completed( this );
  2289. deleteLater();
  2290. return;
  2291. }
  2292. }
  2293. TQMap< TQString, int > renameNumbering;
  2294. Result globalResult = OK;
  2295. int unnamedAtmCount = 0;
  2296. for ( PartNodeMessageMap::const_iterator it = mAttachmentMap.begin();
  2297. it != mAttachmentMap.end();
  2298. ++it ) {
  2299. KURL curUrl;
  2300. if ( !dirUrl.isEmpty() ) {
  2301. curUrl = dirUrl;
  2302. TQString s =
  2303. it.key()->msgPart().fileName().stripWhiteSpace().replace( ':', '_' );
  2304. if ( s.isEmpty() )
  2305. s = it.key()->msgPart().name().stripWhiteSpace().replace( ':', '_' );
  2306. if ( s.isEmpty() ) {
  2307. ++unnamedAtmCount;
  2308. s = i18n("filename for the %1-th unnamed attachment",
  2309. "attachment.%1")
  2310. .arg( unnamedAtmCount );
  2311. }
  2312. curUrl.setFileName( s );
  2313. } else {
  2314. curUrl = url;
  2315. }
  2316. if ( !curUrl.isEmpty() ) {
  2317. // Rename the file if we have already saved one with the same name:
  2318. // try appending a number before extension (e.g. "pic.jpg" => "pic_2.jpg")
  2319. TQString origFile = curUrl.fileName();
  2320. TQString file = origFile;
  2321. while ( renameNumbering.contains(file) ) {
  2322. file = origFile;
  2323. int num = renameNumbering[file] + 1;
  2324. int dotIdx = file.findRev('.');
  2325. file = file.insert( (dotIdx>=0) ? dotIdx : file.length(), TQString("_") + TQString::number(num) );
  2326. }
  2327. curUrl.setFileName(file);
  2328. // Increment the counter for both the old and the new filename
  2329. if ( !renameNumbering.contains(origFile))
  2330. renameNumbering[origFile] = 1;
  2331. else
  2332. renameNumbering[origFile]++;
  2333. if ( file != origFile ) {
  2334. if ( !renameNumbering.contains(file))
  2335. renameNumbering[file] = 1;
  2336. else
  2337. renameNumbering[file]++;
  2338. }
  2339. if ( TDEIO::NetAccess::exists( curUrl, false, parentWidget() ) ) {
  2340. if ( KMessageBox::warningContinueCancel( parentWidget(),
  2341. i18n( "A file named %1 already exists. Do you want to overwrite it?" )
  2342. .arg( curUrl.fileName() ),
  2343. i18n( "File Already Exists" ), i18n("&Overwrite") ) == KMessageBox::Cancel) {
  2344. continue;
  2345. }
  2346. }
  2347. // save
  2348. const Result result = saveItem( it.key(), curUrl );
  2349. if ( result != OK )
  2350. globalResult = result;
  2351. }
  2352. }
  2353. setResult( globalResult );
  2354. emit completed( this );
  2355. deleteLater();
  2356. }
  2357. KMCommand::Result KMSaveAttachmentsCommand::saveItem( partNode *node,
  2358. const KURL& url )
  2359. {
  2360. bool bSaveEncrypted = false;
  2361. bool bEncryptedParts = node->encryptionState() != KMMsgNotEncrypted;
  2362. if( bEncryptedParts )
  2363. if( KMessageBox::questionYesNo( parentWidget(),
  2364. i18n( "The part %1 of the message is encrypted. Do you want to keep the encryption when saving?" ).
  2365. arg( url.fileName() ),
  2366. i18n( "KMail Question" ), i18n("Keep Encryption"), i18n("Do Not Keep") ) ==
  2367. KMessageBox::Yes )
  2368. bSaveEncrypted = true;
  2369. bool bSaveWithSig = true;
  2370. if( node->signatureState() != KMMsgNotSigned )
  2371. if( KMessageBox::questionYesNo( parentWidget(),
  2372. i18n( "The part %1 of the message is signed. Do you want to keep the signature when saving?" ).
  2373. arg( url.fileName() ),
  2374. i18n( "KMail Question" ), i18n("Keep Signature"), i18n("Do Not Keep") ) !=
  2375. KMessageBox::Yes )
  2376. bSaveWithSig = false;
  2377. TQByteArray data;
  2378. if ( mEncoded )
  2379. {
  2380. // This does not decode the Message Content-Transfer-Encoding
  2381. // but saves the _original_ content of the message part
  2382. data = KMail::Util::ByteArray( node->msgPart().dwBody() );
  2383. }
  2384. else
  2385. {
  2386. if( bSaveEncrypted || !bEncryptedParts) {
  2387. partNode *dataNode = node;
  2388. TQCString rawReplyString;
  2389. bool gotRawReplyString = false;
  2390. if( !bSaveWithSig ) {
  2391. if( DwMime::kTypeMultipart == node->type() &&
  2392. DwMime::kSubtypeSigned == node->subType() ){
  2393. // carefully look for the part that is *not* the signature part:
  2394. if( node->findType( DwMime::kTypeApplication,
  2395. DwMime::kSubtypePgpSignature,
  2396. true, false ) ){
  2397. dataNode = node->findTypeNot( DwMime::kTypeApplication,
  2398. DwMime::kSubtypePgpSignature,
  2399. true, false );
  2400. }else if( node->findType( DwMime::kTypeApplication,
  2401. DwMime::kSubtypePkcs7Mime,
  2402. true, false ) ){
  2403. dataNode = node->findTypeNot( DwMime::kTypeApplication,
  2404. DwMime::kSubtypePkcs7Mime,
  2405. true, false );
  2406. }else{
  2407. dataNode = node->findTypeNot( DwMime::kTypeMultipart,
  2408. DwMime::kSubtypeUnknown,
  2409. true, false );
  2410. }
  2411. }else{
  2412. ObjectTreeParser otp( 0, 0, false, false, false );
  2413. // process this node and all it's siblings and descendants
  2414. dataNode->setProcessed( false, true );
  2415. otp.parseObjectTree( dataNode );
  2416. rawReplyString = otp.rawReplyString();
  2417. gotRawReplyString = true;
  2418. }
  2419. }
  2420. TQByteArray cstr = gotRawReplyString
  2421. ? rawReplyString
  2422. : dataNode->msgPart().bodyDecodedBinary();
  2423. data = cstr;
  2424. size_t size = cstr.size();
  2425. if ( dataNode->msgPart().type() == DwMime::kTypeText ) {
  2426. // convert CRLF to LF before writing text attachments to disk
  2427. size = KMail::Util::crlf2lf( cstr.data(), size );
  2428. }
  2429. data.resize( size );
  2430. }
  2431. }
  2432. TQDataStream ds;
  2433. TQFile file;
  2434. KTempFile tf;
  2435. tf.setAutoDelete( true );
  2436. if ( url.isLocalFile() )
  2437. {
  2438. // save directly
  2439. file.setName( url.path() );
  2440. if ( !file.open( IO_WriteOnly ) )
  2441. {
  2442. KMessageBox::error( parentWidget(),
  2443. i18n( "%2 is detailed error description",
  2444. "Could not write the file %1:\n%2" )
  2445. .arg( file.name() )
  2446. .arg( TQString::fromLocal8Bit( strerror( errno ) ) ),
  2447. i18n( "KMail Error" ) );
  2448. return Failed;
  2449. }
  2450. // #79685 by default use the umask the user defined, but let it be configurable
  2451. if ( GlobalSettings::self()->disregardUmask() )
  2452. fchmod( file.handle(), S_IRUSR | S_IWUSR );
  2453. ds.setDevice( &file );
  2454. } else
  2455. {
  2456. // tmp file for upload
  2457. ds.setDevice( tf.file() );
  2458. }
  2459. ds.writeRawBytes( data.data(), data.size() );
  2460. if ( !url.isLocalFile() )
  2461. {
  2462. tf.close();
  2463. if ( !TDEIO::NetAccess::upload( tf.name(), url, parentWidget() ) )
  2464. {
  2465. KMessageBox::error( parentWidget(),
  2466. i18n( "Could not write the file %1." )
  2467. .arg( url.path() ),
  2468. i18n( "KMail Error" ) );
  2469. return Failed;
  2470. }
  2471. } else
  2472. file.close();
  2473. return OK;
  2474. }
  2475. KMLoadPartsCommand::KMLoadPartsCommand( TQPtrList<partNode>& parts, KMMessage *msg )
  2476. : mNeedsRetrieval( 0 )
  2477. {
  2478. for ( TQPtrListIterator<partNode> it( parts ); it.current(); ++it ) {
  2479. mPartMap.insert( it.current(), msg );
  2480. }
  2481. }
  2482. KMLoadPartsCommand::KMLoadPartsCommand( partNode *node, KMMessage *msg )
  2483. : mNeedsRetrieval( 0 )
  2484. {
  2485. mPartMap.insert( node, msg );
  2486. }
  2487. KMLoadPartsCommand::KMLoadPartsCommand( PartNodeMessageMap& partMap )
  2488. : mNeedsRetrieval( 0 ), mPartMap( partMap )
  2489. {
  2490. }
  2491. void KMLoadPartsCommand::slotStart()
  2492. {
  2493. for ( PartNodeMessageMap::const_iterator it = mPartMap.begin();
  2494. it != mPartMap.end();
  2495. ++it ) {
  2496. if ( !it.key()->msgPart().isComplete() &&
  2497. !it.key()->msgPart().partSpecifier().isEmpty() ) {
  2498. // incomplete part, so retrieve it first
  2499. ++mNeedsRetrieval;
  2500. KMFolder* curFolder = it.data()->parent();
  2501. if ( curFolder ) {
  2502. FolderJob *job =
  2503. curFolder->createJob( it.data(), FolderJob::tGetMessage,
  2504. 0, it.key()->msgPart().partSpecifier() );
  2505. job->setCancellable( false );
  2506. connect( job, TQT_SIGNAL(messageUpdated(KMMessage*, TQString)),
  2507. this, TQT_SLOT(slotPartRetrieved(KMMessage*, TQString)) );
  2508. job->start();
  2509. } else
  2510. kdWarning(5006) << "KMLoadPartsCommand - msg has no parent" << endl;
  2511. }
  2512. }
  2513. if ( mNeedsRetrieval == 0 )
  2514. execute();
  2515. }
  2516. void KMLoadPartsCommand::slotPartRetrieved( KMMessage *msg,
  2517. TQString partSpecifier )
  2518. {
  2519. DwBodyPart *part =
  2520. msg->findDwBodyPart( msg->getFirstDwBodyPart(), partSpecifier );
  2521. if ( part ) {
  2522. // update the DwBodyPart in the partNode
  2523. for ( PartNodeMessageMap::const_iterator it = mPartMap.begin();
  2524. it != mPartMap.end();
  2525. ++it ) {
  2526. if ( it.key()->dwPart()->partId() == part->partId() )
  2527. it.key()->setDwPart( part );
  2528. }
  2529. } else
  2530. kdWarning(5006) << "KMLoadPartsCommand::slotPartRetrieved - could not find bodypart!" << endl;
  2531. --mNeedsRetrieval;
  2532. if ( mNeedsRetrieval == 0 )
  2533. execute();
  2534. }
  2535. KMCommand::Result KMLoadPartsCommand::execute()
  2536. {
  2537. emit partsRetrieved();
  2538. setResult( OK );
  2539. emit completed( this );
  2540. deleteLater();
  2541. return OK;
  2542. }
  2543. KMResendMessageCommand::KMResendMessageCommand( TQWidget *parent,
  2544. KMMessage *msg )
  2545. :KMCommand( parent, msg )
  2546. {
  2547. }
  2548. KMCommand::Result KMResendMessageCommand::execute()
  2549. {
  2550. KMMessage *msg = retrievedMessage();
  2551. if ( !msg || !msg->codec() ) {
  2552. return Failed;
  2553. }
  2554. KMMessage *newMsg = new KMMessage(*msg);
  2555. TQStringList whiteList;
  2556. whiteList << "To" << "Cc" << "Bcc" << "Subject";
  2557. newMsg->sanitizeHeaders( whiteList );
  2558. newMsg->setCharset(msg->codec()->mimeName());
  2559. newMsg->setParent( 0 );
  2560. // make sure we have an identity set, default, if necessary
  2561. newMsg->setHeaderField("X-KMail-Identity", TQString::number( newMsg->identityUoid() ));
  2562. newMsg->applyIdentity( newMsg->identityUoid() );
  2563. KMail::Composer * win = KMail::makeComposer();
  2564. win->setMsg(newMsg, false, true);
  2565. win->show();
  2566. return OK;
  2567. }
  2568. KMMailingListCommand::KMMailingListCommand( TQWidget *parent, KMFolder *folder )
  2569. : KMCommand( parent ), mFolder( folder )
  2570. {
  2571. }
  2572. KMCommand::Result KMMailingListCommand::execute()
  2573. {
  2574. KURL::List lst = urls();
  2575. TQString handler = ( mFolder->mailingList().handler() == MailingList::KMail )
  2576. ? "mailto" : "https";
  2577. KMCommand *command = 0;
  2578. for ( KURL::List::Iterator itr = lst.begin(); itr != lst.end(); ++itr ) {
  2579. if ( handler == (*itr).protocol() ) {
  2580. command = new KMUrlClickedCommand( *itr, mFolder->identity(), 0, false );
  2581. }
  2582. }
  2583. if ( !command && !lst.empty() ) {
  2584. command =
  2585. new KMUrlClickedCommand( lst.first(), mFolder->identity(), 0, false );
  2586. }
  2587. if ( command ) {
  2588. connect( command, TQT_SIGNAL( completed( KMCommand * ) ),
  2589. this, TQT_SLOT( commandCompleted( KMCommand * ) ) );
  2590. setDeletesItself( true );
  2591. setEmitsCompletedItself( true );
  2592. command->start();
  2593. return OK;
  2594. }
  2595. return Failed;
  2596. }
  2597. void KMMailingListCommand::commandCompleted( KMCommand *command )
  2598. {
  2599. setResult( command->result() );
  2600. emit completed( this );
  2601. deleteLater();
  2602. }
  2603. KMMailingListPostCommand::KMMailingListPostCommand( TQWidget *parent, KMFolder *folder )
  2604. : KMMailingListCommand( parent, folder )
  2605. {
  2606. }
  2607. KURL::List KMMailingListPostCommand::urls() const
  2608. {
  2609. return mFolder->mailingList().postURLS();
  2610. }
  2611. KMMailingListSubscribeCommand::KMMailingListSubscribeCommand( TQWidget *parent, KMFolder *folder )
  2612. : KMMailingListCommand( parent, folder )
  2613. {
  2614. }
  2615. KURL::List KMMailingListSubscribeCommand::urls() const
  2616. {
  2617. return mFolder->mailingList().subscribeURLS();
  2618. }
  2619. KMMailingListUnsubscribeCommand::KMMailingListUnsubscribeCommand( TQWidget *parent, KMFolder *folder )
  2620. : KMMailingListCommand( parent, folder )
  2621. {
  2622. }
  2623. KURL::List KMMailingListUnsubscribeCommand::urls() const
  2624. {
  2625. return mFolder->mailingList().unsubscribeURLS();
  2626. }
  2627. KMMailingListArchivesCommand::KMMailingListArchivesCommand( TQWidget *parent, KMFolder *folder )
  2628. : KMMailingListCommand( parent, folder )
  2629. {
  2630. }
  2631. KURL::List KMMailingListArchivesCommand::urls() const
  2632. {
  2633. return mFolder->mailingList().archiveURLS();
  2634. }
  2635. KMMailingListHelpCommand::KMMailingListHelpCommand( TQWidget *parent, KMFolder *folder )
  2636. : KMMailingListCommand( parent, folder )
  2637. {
  2638. }
  2639. KURL::List KMMailingListHelpCommand::urls() const
  2640. {
  2641. return mFolder->mailingList().helpURLS();
  2642. }
  2643. KMIMChatCommand::KMIMChatCommand( const KURL &url, KMMessage *msg )
  2644. :mUrl( url ), mMessage( msg )
  2645. {
  2646. }
  2647. KMCommand::Result KMIMChatCommand::execute()
  2648. {
  2649. kdDebug( 5006 ) << k_funcinfo << " URL is: " << mUrl << endl;
  2650. TQString addr = KMMessage::decodeMailtoUrl( mUrl.path() );
  2651. // find UID for mail address
  2652. TDEABC::AddressBook *addressBook = TDEABC::StdAddressBook::self( true );
  2653. TDEABC::AddresseeList addressees = addressBook->findByEmail( KPIM::getEmailAddress( addr ) ) ;
  2654. // start chat
  2655. if( addressees.count() == 1 ) {
  2656. kmkernel->imProxy()->chatWithContact( addressees[0].uid() );
  2657. return OK;
  2658. }
  2659. else
  2660. {
  2661. kdDebug( 5006 ) << "Didn't find exactly one addressee, couldn't tell who to chat to for that email address. Count = " << addressees.count() << endl;
  2662. TQString apology;
  2663. if ( addressees.isEmpty() )
  2664. apology = i18n( "There is no Address Book entry for this email address. Add them to the Address Book and then add instant messaging addresses using your preferred messaging client." );
  2665. else
  2666. {
  2667. apology = i18n( "More than one Address Book entry uses this email address:\n %1\n it is not possible to determine who to chat with." );
  2668. TQStringList nameList;
  2669. TDEABC::AddresseeList::const_iterator it = addressees.begin();
  2670. TDEABC::AddresseeList::const_iterator end = addressees.end();
  2671. for ( ; it != end; ++it )
  2672. {
  2673. nameList.append( (*it).realName() );
  2674. }
  2675. TQString names = nameList.join( TQString::fromLatin1( ",\n" ) );
  2676. apology = apology.arg( names );
  2677. }
  2678. KMessageBox::sorry( parentWidget(), apology );
  2679. return Failed;
  2680. }
  2681. }
  2682. KMHandleAttachmentCommand::KMHandleAttachmentCommand( partNode* node,
  2683. KMMessage* msg, int atmId, const TQString& atmName,
  2684. AttachmentAction action, KService::Ptr offer, TQWidget* parent )
  2685. : KMCommand( parent ), mNode( node ), mMsg( msg ), mAtmId( atmId ), mAtmName( atmName ),
  2686. mAction( action ), mOffer( offer ), mJob( 0 )
  2687. {
  2688. }
  2689. void KMHandleAttachmentCommand::slotStart()
  2690. {
  2691. if ( !mNode->msgPart().isComplete() )
  2692. {
  2693. // load the part
  2694. kdDebug(5006) << "load part" << endl;
  2695. KMLoadPartsCommand *command = new KMLoadPartsCommand( mNode, mMsg );
  2696. connect( command, TQT_SIGNAL( partsRetrieved() ),
  2697. this, TQT_SLOT( slotPartComplete() ) );
  2698. command->start();
  2699. } else
  2700. {
  2701. execute();
  2702. }
  2703. }
  2704. void KMHandleAttachmentCommand::slotPartComplete()
  2705. {
  2706. execute();
  2707. }
  2708. KMCommand::Result KMHandleAttachmentCommand::execute()
  2709. {
  2710. switch( mAction )
  2711. {
  2712. case Open:
  2713. atmOpen();
  2714. break;
  2715. case OpenWith:
  2716. atmOpenWith();
  2717. break;
  2718. case View:
  2719. atmView();
  2720. break;
  2721. case Save:
  2722. atmSave();
  2723. break;
  2724. case Properties:
  2725. atmProperties();
  2726. break;
  2727. case ChiasmusEncrypt:
  2728. atmEncryptWithChiasmus();
  2729. return Undefined;
  2730. break;
  2731. default:
  2732. kdDebug(5006) << "unknown action " << mAction << endl;
  2733. break;
  2734. }
  2735. setResult( OK );
  2736. emit completed( this );
  2737. deleteLater();
  2738. return OK;
  2739. }
  2740. TQString KMHandleAttachmentCommand::createAtmFileLink() const
  2741. {
  2742. TQFileInfo atmFileInfo( mAtmName );
  2743. if ( atmFileInfo.size() == 0 )
  2744. {
  2745. kdDebug(5006) << k_funcinfo << "rewriting attachment" << endl;
  2746. // there is something wrong so write the file again
  2747. TQByteArray data = mNode->msgPart().bodyDecodedBinary();
  2748. size_t size = data.size();
  2749. if ( mNode->msgPart().type() == DwMime::kTypeText && size) {
  2750. // convert CRLF to LF before writing text attachments to disk
  2751. size = KMail::Util::crlf2lf( data.data(), size );
  2752. }
  2753. KPIM::kBytesToFile( data.data(), size, mAtmName, false, false, false );
  2754. }
  2755. KTempFile *linkFile = new KTempFile( locateLocal("tmp", atmFileInfo.fileName() +"_["),
  2756. "]."+ atmFileInfo.extension() );
  2757. linkFile->setAutoDelete(true);
  2758. TQString linkName = linkFile->name();
  2759. delete linkFile;
  2760. if ( ::link(TQFile::encodeName( mAtmName ), TQFile::encodeName( linkName )) == 0 ) {
  2761. return linkName; // success
  2762. }
  2763. return TQString();
  2764. }
  2765. KService::Ptr KMHandleAttachmentCommand::getServiceOffer()
  2766. {
  2767. KMMessagePart& msgPart = mNode->msgPart();
  2768. const TQString contentTypeStr =
  2769. ( msgPart.typeStr() + '/' + msgPart.subtypeStr() ).lower();
  2770. if ( contentTypeStr == "text/x-vcard" ) {
  2771. atmView();
  2772. return 0;
  2773. }
  2774. // determine the MIME type of the attachment
  2775. KMimeType::Ptr mimetype;
  2776. // prefer the value of the Content-Type header
  2777. mimetype = KMimeType::mimeType( contentTypeStr );
  2778. if ( mimetype->name() == "application/octet-stream" ) {
  2779. // consider the filename if Content-Type is application/octet-stream
  2780. mimetype = KMimeType::findByPath( mAtmName, 0, true /* no disk access */ );
  2781. }
  2782. if ( ( mimetype->name() == "application/octet-stream" )
  2783. && msgPart.isComplete() ) {
  2784. // consider the attachment's contents if neither the Content-Type header
  2785. // nor the filename give us a clue
  2786. mimetype = KMimeType::findByFileContent( mAtmName );
  2787. }
  2788. return KServiceTypeProfile::preferredService( mimetype->name(), "Application" );
  2789. }
  2790. void KMHandleAttachmentCommand::atmOpen()
  2791. {
  2792. if ( !mOffer )
  2793. mOffer = getServiceOffer();
  2794. if ( !mOffer ) {
  2795. kdDebug(5006) << k_funcinfo << "got no offer" << endl;
  2796. return;
  2797. }
  2798. KURL::List lst;
  2799. KURL url;
  2800. bool autoDelete = true;
  2801. TQString fname = createAtmFileLink();
  2802. if ( fname.isNull() ) {
  2803. autoDelete = false;
  2804. fname = mAtmName;
  2805. }
  2806. url.setPath( fname );
  2807. lst.append( url );
  2808. if ( (KRun::run( *mOffer, lst, autoDelete ) <= 0) && autoDelete ) {
  2809. TQFile::remove(url.path());
  2810. }
  2811. }
  2812. void KMHandleAttachmentCommand::atmOpenWith()
  2813. {
  2814. KURL::List lst;
  2815. KURL url;
  2816. bool autoDelete = true;
  2817. TQString fname = createAtmFileLink();
  2818. if ( fname.isNull() ) {
  2819. autoDelete = false;
  2820. fname = mAtmName;
  2821. }
  2822. url.setPath( fname );
  2823. lst.append( url );
  2824. if ( (! KRun::displayOpenWithDialog(lst, autoDelete)) && autoDelete ) {
  2825. TQFile::remove( url.path() );
  2826. }
  2827. }
  2828. void KMHandleAttachmentCommand::atmView()
  2829. {
  2830. // we do not handle this ourself
  2831. emit showAttachment( mAtmId, mAtmName );
  2832. }
  2833. void KMHandleAttachmentCommand::atmSave()
  2834. {
  2835. TQPtrList<partNode> parts;
  2836. parts.append( mNode );
  2837. // save, do not leave encoded
  2838. KMSaveAttachmentsCommand *command =
  2839. new KMSaveAttachmentsCommand( parentWidget(), parts, mMsg, false );
  2840. command->start();
  2841. }
  2842. void KMHandleAttachmentCommand::atmProperties()
  2843. {
  2844. KMMsgPartDialogCompat dlg( parentWidget() , 0, true );
  2845. KMMessagePart& msgPart = mNode->msgPart();
  2846. dlg.setMsgPart( &msgPart );
  2847. dlg.exec();
  2848. }
  2849. void KMHandleAttachmentCommand::atmEncryptWithChiasmus()
  2850. {
  2851. const partNode * node = mNode;
  2852. Q_ASSERT( node );
  2853. if ( !node )
  2854. return;
  2855. // FIXME: better detection of mimetype??
  2856. if ( !mAtmName.endsWith( ".xia", false ) )
  2857. return;
  2858. const Kleo::CryptoBackend::Protocol * chiasmus =
  2859. Kleo::CryptoBackendFactory::instance()->protocol( "Chiasmus" );
  2860. Q_ASSERT( chiasmus );
  2861. if ( !chiasmus )
  2862. return;
  2863. const STD_NAMESPACE_PREFIX auto_ptr<Kleo::SpecialJob> listjob( chiasmus->specialJob( "x-obtain-keys", TQMap<TQString,TQVariant>() ) );
  2864. if ( !listjob.get() ) {
  2865. const TQString msg = i18n( "Chiasmus backend does not offer the "
  2866. "\"x-obtain-keys\" function. Please report this bug." );
  2867. KMessageBox::error( parentWidget(), msg, i18n( "Chiasmus Backend Error" ) );
  2868. return;
  2869. }
  2870. if ( listjob->exec() ) {
  2871. listjob->showErrorDialog( parentWidget(), i18n( "Chiasmus Backend Error" ) );
  2872. return;
  2873. }
  2874. const TQVariant result = listjob->property( "result" );
  2875. if ( result.type() != TQVariant::StringList ) {
  2876. const TQString msg = i18n( "Unexpected return value from Chiasmus backend: "
  2877. "The \"x-obtain-keys\" function did not return a "
  2878. "string list. Please report this bug." );
  2879. KMessageBox::error( parentWidget(), msg, i18n( "Chiasmus Backend Error" ) );
  2880. return;
  2881. }
  2882. const TQStringList keys = result.toStringList();
  2883. if ( keys.empty() ) {
  2884. const TQString msg = i18n( "No keys have been found. Please check that a "
  2885. "valid key path has been set in the Chiasmus "
  2886. "configuration." );
  2887. KMessageBox::error( parentWidget(), msg, i18n( "Chiasmus Backend Error" ) );
  2888. return;
  2889. }
  2890. ChiasmusKeySelector selectorDlg( parentWidget(), i18n( "Chiasmus Decryption Key Selection" ),
  2891. keys, GlobalSettings::chiasmusDecryptionKey(),
  2892. GlobalSettings::chiasmusDecryptionOptions() );
  2893. if ( selectorDlg.exec() != TQDialog::Accepted )
  2894. return;
  2895. GlobalSettings::setChiasmusDecryptionOptions( selectorDlg.options() );
  2896. GlobalSettings::setChiasmusDecryptionKey( selectorDlg.key() );
  2897. assert( !GlobalSettings::chiasmusDecryptionKey().isEmpty() );
  2898. Kleo::SpecialJob * job = chiasmus->specialJob( "x-decrypt", TQMap<TQString,TQVariant>() );
  2899. if ( !job ) {
  2900. const TQString msg = i18n( "Chiasmus backend does not offer the "
  2901. "\"x-decrypt\" function. Please report this bug." );
  2902. KMessageBox::error( parentWidget(), msg, i18n( "Chiasmus Backend Error" ) );
  2903. return;
  2904. }
  2905. const TQByteArray input = node->msgPart().bodyDecodedBinary();
  2906. if ( !job->setProperty( "key", GlobalSettings::chiasmusDecryptionKey() ) ||
  2907. !job->setProperty( "options", GlobalSettings::chiasmusDecryptionOptions() ) ||
  2908. !job->setProperty( "input", input ) ) {
  2909. const TQString msg = i18n( "The \"x-decrypt\" function does not accept "
  2910. "the expected parameters. Please report this bug." );
  2911. KMessageBox::error( parentWidget(), msg, i18n( "Chiasmus Backend Error" ) );
  2912. return;
  2913. }
  2914. setDeletesItself( true ); // the job below is async, we have to cleanup ourselves
  2915. if ( job->start() ) {
  2916. job->showErrorDialog( parentWidget(), i18n( "Chiasmus Decryption Error" ) );
  2917. return;
  2918. }
  2919. mJob = job;
  2920. connect( job, TQT_SIGNAL(result(const GpgME::Error&,const TQVariant&)),
  2921. this, TQT_SLOT(slotAtmDecryptWithChiasmusResult(const GpgME::Error&,const TQVariant&)) );
  2922. }
  2923. static const TQString chomp( const TQString & base, const TQString & suffix, bool cs ) {
  2924. return base.endsWith( suffix, cs ) ? base.left( base.length() - suffix.length() ) : base ;
  2925. }
  2926. void KMHandleAttachmentCommand::slotAtmDecryptWithChiasmusResult( const GpgME::Error & err, const TQVariant & result )
  2927. {
  2928. LaterDeleterWithCommandCompletion d( this );
  2929. if ( !mJob )
  2930. return;
  2931. Q_ASSERT( mJob == sender() );
  2932. if ( mJob != sender() )
  2933. return;
  2934. Kleo::Job * job = mJob;
  2935. mJob = 0;
  2936. if ( err.isCanceled() )
  2937. return;
  2938. if ( err ) {
  2939. job->showErrorDialog( parentWidget(), i18n( "Chiasmus Decryption Error" ) );
  2940. return;
  2941. }
  2942. if ( result.type() != TQVariant::ByteArray ) {
  2943. const TQString msg = i18n( "Unexpected return value from Chiasmus backend: "
  2944. "The \"x-decrypt\" function did not return a "
  2945. "byte array. Please report this bug." );
  2946. KMessageBox::error( parentWidget(), msg, i18n( "Chiasmus Backend Error" ) );
  2947. return;
  2948. }
  2949. const KURL url = KFileDialog::getSaveURL( chomp( mAtmName, ".xia", false ), TQString(), parentWidget() );
  2950. if ( url.isEmpty() )
  2951. return;
  2952. bool overwrite = KMail::Util::checkOverwrite( url, parentWidget() );
  2953. if ( !overwrite )
  2954. return;
  2955. d.setDisabled( true ); // we got this far, don't delete yet
  2956. TDEIO::Job * uploadJob = TDEIO::storedPut( result.toByteArray(), url, -1, overwrite, false /*resume*/ );
  2957. uploadJob->setWindow( parentWidget() );
  2958. connect( uploadJob, TQT_SIGNAL(result(TDEIO::Job*)),
  2959. this, TQT_SLOT(slotAtmDecryptWithChiasmusUploadResult(TDEIO::Job*)) );
  2960. }
  2961. void KMHandleAttachmentCommand::slotAtmDecryptWithChiasmusUploadResult( TDEIO::Job * job )
  2962. {
  2963. if ( job->error() )
  2964. job->showErrorDialog();
  2965. LaterDeleterWithCommandCompletion d( this );
  2966. d.setResult( OK );
  2967. }
  2968. AttachmentModifyCommand::AttachmentModifyCommand(partNode * node, KMMessage * msg, TQWidget * parent) :
  2969. KMCommand( parent, msg ),
  2970. mPartIndex( node->nodeId() ),
  2971. mSernum( 0 )
  2972. {
  2973. }
  2974. AttachmentModifyCommand::AttachmentModifyCommand( int nodeId, KMMessage *msg, TQWidget *parent )
  2975. : KMCommand( parent, msg ),
  2976. mPartIndex( nodeId ),
  2977. mSernum( 0 )
  2978. {
  2979. }
  2980. AttachmentModifyCommand::~ AttachmentModifyCommand()
  2981. {
  2982. }
  2983. KMCommand::Result AttachmentModifyCommand::execute()
  2984. {
  2985. KMMessage *msg = retrievedMessage();
  2986. if ( !msg )
  2987. return Failed;
  2988. mSernum = msg->getMsgSerNum();
  2989. mFolder = msg->parent();
  2990. if ( !mFolder || !mFolder->storage() )
  2991. return Failed;
  2992. Result res = doAttachmentModify();
  2993. if ( res != OK )
  2994. return res;
  2995. setEmitsCompletedItself( true );
  2996. setDeletesItself( true );
  2997. return OK;
  2998. }
  2999. void AttachmentModifyCommand::storeChangedMessage(KMMessage * msg)
  3000. {
  3001. if ( !mFolder || !mFolder->storage() ) {
  3002. kdWarning(5006) << k_funcinfo << "We lost the folder!" << endl;
  3003. setResult( Failed );
  3004. emit completed( this );
  3005. deleteLater();
  3006. }
  3007. int res = mFolder->addMsg( msg ) != 0;
  3008. if ( mFolder->folderType() == KMFolderTypeImap ) {
  3009. KMFolderImap *f = static_cast<KMFolderImap*>( mFolder->storage() );
  3010. connect( f, TQT_SIGNAL(folderComplete(KMFolderImap*,bool)),
  3011. TQT_SLOT(messageStoreResult(KMFolderImap*,bool)) );
  3012. } else {
  3013. messageStoreResult( 0, res == 0 );
  3014. }
  3015. }
  3016. void AttachmentModifyCommand::messageStoreResult(KMFolderImap* folder, bool success )
  3017. {
  3018. Q_UNUSED( folder );
  3019. if ( success ) {
  3020. KMCommand *delCmd = new KMDeleteMsgCommand( mSernum );
  3021. connect( delCmd, TQT_SIGNAL(completed(KMCommand*)), TQT_SLOT(messageDeleteResult(KMCommand*)) );
  3022. delCmd->start();
  3023. return;
  3024. }
  3025. kdWarning(5006) << k_funcinfo << "Adding modified message failed." << endl;
  3026. setResult( Failed );
  3027. emit completed( this );
  3028. deleteLater();
  3029. }
  3030. void AttachmentModifyCommand::messageDeleteResult(KMCommand * cmd)
  3031. {
  3032. setResult( cmd->result() );
  3033. emit completed( this );
  3034. deleteLater();
  3035. }
  3036. KMDeleteAttachmentCommand::KMDeleteAttachmentCommand(partNode * node, KMMessage * msg, TQWidget * parent) :
  3037. AttachmentModifyCommand( node, msg, parent )
  3038. {
  3039. kdDebug(5006) << k_funcinfo << endl;
  3040. }
  3041. KMDeleteAttachmentCommand::KMDeleteAttachmentCommand( int nodeId, KMMessage *msg, TQWidget *parent )
  3042. : AttachmentModifyCommand( nodeId, msg, parent )
  3043. {
  3044. kdDebug(5006) << k_funcinfo << endl;
  3045. }
  3046. KMDeleteAttachmentCommand::~KMDeleteAttachmentCommand()
  3047. {
  3048. kdDebug(5006) << k_funcinfo << endl;
  3049. }
  3050. KMCommand::Result KMDeleteAttachmentCommand::doAttachmentModify()
  3051. {
  3052. KMMessage *msg = retrievedMessage();
  3053. if ( !msg || !msg->deleteBodyPart( mPartIndex ) )
  3054. return Failed;
  3055. KMMessage *newMsg = new KMMessage();
  3056. newMsg->fromDwString( msg->asDwString() );
  3057. newMsg->setStatus( msg->status() );
  3058. storeChangedMessage( newMsg );
  3059. return OK;
  3060. }
  3061. KMEditAttachmentCommand::KMEditAttachmentCommand(partNode * node, KMMessage * msg, TQWidget * parent) :
  3062. AttachmentModifyCommand( node, msg, parent )
  3063. {
  3064. kdDebug(5006) << k_funcinfo << endl;
  3065. mTempFile.setAutoDelete( true );
  3066. }
  3067. KMEditAttachmentCommand::KMEditAttachmentCommand( int nodeId, KMMessage *msg, TQWidget *parent )
  3068. : AttachmentModifyCommand( nodeId, msg, parent )
  3069. {
  3070. kdDebug(5006) << k_funcinfo << endl;
  3071. mTempFile.setAutoDelete( true );
  3072. }
  3073. KMEditAttachmentCommand::~ KMEditAttachmentCommand()
  3074. {
  3075. }
  3076. KMCommand::Result KMEditAttachmentCommand::doAttachmentModify()
  3077. {
  3078. KMMessage *msg = retrievedMessage();
  3079. if ( !msg )
  3080. return Failed;
  3081. KMMessagePart part;
  3082. DwBodyPart *dwpart = msg->findPart( mPartIndex );
  3083. if ( !dwpart )
  3084. return Failed;
  3085. KMMessage::bodyPart( dwpart, &part, true );
  3086. if ( !part.isComplete() )
  3087. return Failed;
  3088. if( !dynamic_cast<DwBody*>( dwpart->Parent() ) )
  3089. return Failed;
  3090. mTempFile.file()->writeBlock( part.bodyDecodedBinary() );
  3091. mTempFile.file()->flush();
  3092. KMail::EditorWatcher *watcher =
  3093. new KMail::EditorWatcher( KURL( mTempFile.file()->name() ),
  3094. part.typeStr() + "/" + part.subtypeStr(),
  3095. false, this, parentWidget() );
  3096. connect( watcher, TQT_SIGNAL(editDone(KMail::EditorWatcher*)), TQT_SLOT(editDone(KMail::EditorWatcher*)) );
  3097. if ( !watcher->start() )
  3098. return Failed;
  3099. setEmitsCompletedItself( true );
  3100. setDeletesItself( true );
  3101. return OK;
  3102. }
  3103. void KMEditAttachmentCommand::editDone(KMail::EditorWatcher * watcher)
  3104. {
  3105. kdDebug(5006) << k_funcinfo << endl;
  3106. // anything changed?
  3107. if ( !watcher->fileChanged() ) {
  3108. kdDebug(5006) << k_funcinfo << "File has not been changed" << endl;
  3109. setResult( Canceled );
  3110. emit completed( this );
  3111. deleteLater();
  3112. }
  3113. mTempFile.file()->reset();
  3114. TQByteArray data = mTempFile.file()->readAll();
  3115. // build the new message
  3116. KMMessage *msg = retrievedMessage();
  3117. KMMessagePart part;
  3118. DwBodyPart *dwpart = msg->findPart( mPartIndex );
  3119. KMMessage::bodyPart( dwpart, &part, true );
  3120. DwBody *parentNode = dynamic_cast<DwBody*>( dwpart->Parent() );
  3121. assert( parentNode );
  3122. parentNode->RemoveBodyPart( dwpart );
  3123. KMMessagePart att;
  3124. att.duplicate( part );
  3125. att.setBodyEncodedBinary( data );
  3126. DwBodyPart* newDwPart = msg->createDWBodyPart( &att );
  3127. parentNode->AddBodyPart( newDwPart );
  3128. msg->getTopLevelPart()->Assemble();
  3129. KMMessage *newMsg = new KMMessage();
  3130. newMsg->fromDwString( msg->asDwString() );
  3131. newMsg->setStatus( msg->status() );
  3132. storeChangedMessage( newMsg );
  3133. }
  3134. CreateTodoCommand::CreateTodoCommand(TQWidget * parent, KMMessage * msg)
  3135. : KMCommand( parent, msg )
  3136. {
  3137. }
  3138. KMCommand::Result CreateTodoCommand::execute()
  3139. {
  3140. KMMessage *msg = retrievedMessage();
  3141. if ( !msg || !msg->codec() ) {
  3142. return Failed;
  3143. }
  3144. KMail::KorgHelper::ensureRunning();
  3145. TQString txt = i18n("From: %1\nTo: %2\nSubject: %3").arg( msg->from() )
  3146. .arg( msg->to() ).arg( msg->subject() );
  3147. KTempFile tf;
  3148. tf.setAutoDelete( true );
  3149. TQString uri = "kmail:" + TQString::number( msg->getMsgSerNum() ) + "/" + msg->msgId();
  3150. tf.file()->writeBlock( msg->asDwString().c_str(), msg->asDwString().length() );
  3151. tf.close();
  3152. KCalendarIface_stub *iface = new KCalendarIface_stub( kapp->dcopClient(), "korganizer", "CalendarIface" );
  3153. iface->openTodoEditor( i18n("Mail: %1").arg( msg->subject() ), txt, uri,
  3154. tf.name(), TQStringList(), "message/rfc822", true );
  3155. delete iface;
  3156. return OK;
  3157. }
  3158. #include "kmcommands.moc"