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.

kmcomposewin.cpp 189KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422
  1. // -*- mode: C++; c-file-style: "gnu" -*-
  2. // kmcomposewin.cpp
  3. // Author: Markus Wuebben <markus.wuebben@kde.org>
  4. // This code is published under the GPL.
  5. #undef GrayScale
  6. #undef Color
  7. #include <config.h>
  8. #define REALLY_WANT_KMCOMPOSEWIN_H
  9. #include "kmcomposewin.h"
  10. #undef REALLY_WANT_KMCOMPOSEWIN_H
  11. #include "kmedit.h"
  12. #include "kmlineeditspell.h"
  13. #include "kmatmlistview.h"
  14. #include "kmmainwin.h"
  15. #include "kmreadermainwin.h"
  16. #include "messagesender.h"
  17. #include "kmmsgpartdlg.h"
  18. #include <kpgpblock.h>
  19. #include <kaddrbook.h>
  20. #include "kmaddrbook.h"
  21. #include "kmmsgdict.h"
  22. #include "kmfolderimap.h"
  23. #include "kmfoldermgr.h"
  24. #include "kmfoldercombobox.h"
  25. #include "kmtransport.h"
  26. #include "kmcommands.h"
  27. #include "kcursorsaver.h"
  28. #include "partNode.h"
  29. #include "encodingdetector.h"
  30. #include "attachmentlistview.h"
  31. #include "transportmanager.h"
  32. using KMail::AttachmentListView;
  33. #include "dictionarycombobox.h"
  34. using KMail::DictionaryComboBox;
  35. #include "addressesdialog.h"
  36. using KPIM::AddressesDialog;
  37. #include "addresseeemailselection.h"
  38. using KPIM::AddresseeEmailSelection;
  39. using KPIM::AddresseeSelectorDialog;
  40. #include <maillistdrag.h>
  41. using KPIM::MailListDrag;
  42. #include "recentaddresses.h"
  43. using TDERecentAddress::RecentAddresses;
  44. #include "kleo_util.h"
  45. #include "stl_util.h"
  46. #include "recipientseditor.h"
  47. #include "editorwatcher.h"
  48. #include "attachmentcollector.h"
  49. #include "objecttreeparser.h"
  50. #include "kmfoldermaildir.h"
  51. #include <libkpimidentities/identitymanager.h>
  52. #include <libkpimidentities/identitycombo.h>
  53. #include <libkpimidentities/identity.h>
  54. #include <libtdepim/tdefileio.h>
  55. #include <libemailfunctions/email.h>
  56. #include <kleo/cryptobackendfactory.h>
  57. #include <kleo/exportjob.h>
  58. #include <kleo/specialjob.h>
  59. #include <ui/progressdialog.h>
  60. #include <ui/keyselectiondialog.h>
  61. #include <gpgmepp/context.h>
  62. #include <gpgmepp/key.h>
  63. #include <tdeio/netaccess.h>
  64. #include "tdelistboxdialog.h"
  65. #include "messagecomposer.h"
  66. #include "chiasmuskeyselector.h"
  67. #include <kcharsets.h>
  68. #include <tdecompletionbox.h>
  69. #include <kcursor.h>
  70. #include <kcombobox.h>
  71. #include <tdestdaccel.h>
  72. #include <tdepopupmenu.h>
  73. #include <kedittoolbar.h>
  74. #include <kkeydialog.h>
  75. #include <kdebug.h>
  76. #include <tdefiledialog.h>
  77. #include <twin.h>
  78. #include <kinputdialog.h>
  79. #include <tdemessagebox.h>
  80. #include <kurldrag.h>
  81. #include <tdeio/scheduler.h>
  82. #include <tdetempfile.h>
  83. #include <tdelocale.h>
  84. #include <tdeapplication.h>
  85. #include <kstatusbar.h>
  86. #include <tdeaction.h>
  87. #include <kstdaction.h>
  88. #include <kdirwatch.h>
  89. #include <kstdguiitem.h>
  90. #include <kiconloader.h>
  91. #include <kpushbutton.h>
  92. #include <kuserprofile.h>
  93. #include <krun.h>
  94. #include <ktempdir.h>
  95. #include <kstandarddirs.h>
  96. //#include <keditlistbox.h>
  97. #include "globalsettings.h"
  98. #include "replyphrases.h"
  99. #include <tdespell.h>
  100. #include <tdespelldlg.h>
  101. #include <spellingfilter.h>
  102. #include <ksyntaxhighlighter.h>
  103. #include <kcolordialog.h>
  104. #include <kzip.h>
  105. #include <ksavefile.h>
  106. #include <tqtabdialog.h>
  107. #include <tqregexp.h>
  108. #include <tqbuffer.h>
  109. #include <tqtooltip.h>
  110. #include <tqtextcodec.h>
  111. #include <tqheader.h>
  112. #include <tqwhatsthis.h>
  113. #include <tqfontdatabase.h>
  114. #include <mimelib/mimepp.h>
  115. #include <algorithm>
  116. #include <memory>
  117. #include <sys/stat.h>
  118. #include <sys/types.h>
  119. #include <stdlib.h>
  120. #include <unistd.h>
  121. #include <errno.h>
  122. #include <fcntl.h>
  123. #include <assert.h>
  124. #include "kmcomposewin.moc"
  125. #include "snippetwidget.h"
  126. KMail::Composer * KMail::makeComposer( KMMessage * msg, uint identitiy ) {
  127. return KMComposeWin::create( msg, identitiy );
  128. }
  129. KMail::Composer * KMComposeWin::create( KMMessage * msg, uint identitiy ) {
  130. return new KMComposeWin( msg, identitiy );
  131. }
  132. //-----------------------------------------------------------------------------
  133. KMComposeWin::KMComposeWin( KMMessage *aMsg, uint id )
  134. : MailComposerIface(), KMail::Composer( "kmail-composer#" ),
  135. mSpellCheckInProgress( false ),
  136. mDone( false ),
  137. mAtmModified( false ),
  138. mAtmSelectNew( 0 ),
  139. mMsg( 0 ),
  140. mAttachMenu( 0 ),
  141. mSigningAndEncryptionExplicitlyDisabled( false ),
  142. mFolder( 0 ),
  143. mUseHTMLEditor( false ),
  144. mId( id ),
  145. mAttachPK( 0 ), mAttachMPK( 0 ),
  146. mAttachRemoveAction( 0 ), mAttachSaveAction( 0 ), mAttachPropertiesAction( 0 ),
  147. mAppendSignatureAction( 0 ), mPrependSignatureAction( 0 ), mInsertSignatureAction( 0 ),
  148. mSignAction( 0 ), mEncryptAction( 0 ), mRequestMDNAction( 0 ),
  149. mUrgentAction( 0 ), mAllFieldsAction( 0 ), mFromAction( 0 ),
  150. mReplyToAction( 0 ), mToAction( 0 ), mCcAction( 0 ), mBccAction( 0 ),
  151. mSubjectAction( 0 ),
  152. mIdentityAction( 0 ), mTransportAction( 0 ), mFccAction( 0 ),
  153. mWordWrapAction( 0 ), mFixedFontAction( 0 ), mAutoSpellCheckingAction( 0 ),
  154. mDictionaryAction( 0 ), mSnippetAction( 0 ),
  155. mEncodingAction( 0 ),
  156. mCryptoModuleAction( 0 ),
  157. mEncryptChiasmusAction( 0 ),
  158. mEncryptWithChiasmus( false ),
  159. mComposer( 0 ),
  160. mLabelWidth( 0 ),
  161. mAutoSaveTimer( 0 ), mLastAutoSaveErrno( 0 ),
  162. mSignatureStateIndicator( 0 ), mEncryptionStateIndicator( 0 ),
  163. mPreserveUserCursorPosition( false ),
  164. mPreventFccOverwrite( false ),
  165. mCheckForRecipients( true ),
  166. mCheckForForgottenAttachments( true ),
  167. mIgnoreStickyFields( false )
  168. {
  169. mClassicalRecipients = GlobalSettings::self()->recipientsEditorType() ==
  170. GlobalSettings::EnumRecipientsEditorType::Classic;
  171. mSubjectTextWasSpellChecked = false;
  172. if (kmkernel->xmlGuiInstance())
  173. setInstance( kmkernel->xmlGuiInstance() );
  174. mMainWidget = new TQWidget(this);
  175. // splitter between the headers area and the actual editor
  176. mHeadersToEditorSplitter = new TQSplitter( Qt::Vertical, mMainWidget, "mHeadersToEditorSplitter" );
  177. mHeadersToEditorSplitter->setChildrenCollapsible( false );
  178. mHeadersArea = new TQWidget( mHeadersToEditorSplitter );
  179. mHeadersArea->setSizePolicy( mHeadersToEditorSplitter->sizePolicy().horData(), TQSizePolicy::Maximum );
  180. TQVBoxLayout *v = new TQVBoxLayout( mMainWidget );
  181. v->addWidget( mHeadersToEditorSplitter );
  182. mIdentity = new KPIM::IdentityCombo(kmkernel->identityManager(), mHeadersArea);
  183. TQToolTip::add( mIdentity,
  184. i18n( "Select an identity for this message" ) );
  185. mDictionaryCombo = new DictionaryComboBox( mHeadersArea );
  186. TQToolTip::add( mDictionaryCombo,
  187. i18n( "Select the dictionary to use when spell-checking this message" ) );
  188. mFcc = new KMFolderComboBox(mHeadersArea);
  189. mFcc->showOutboxFolder( false );
  190. TQToolTip::add( mFcc,
  191. i18n( "Select the sent-mail folder where a copy of this message will be saved" ) );
  192. mTransport = new TQComboBox(true, mHeadersArea);
  193. TQToolTip::add( mTransport,
  194. i18n( "Select the outgoing account to use for sending this message" ) );
  195. mEdtFrom = new KMLineEdit(false,mHeadersArea, "fromLine");
  196. TQToolTip::add( mEdtFrom,
  197. i18n( "Set the \"From:\" email address for this message" ) );
  198. mEdtReplyTo = new KMLineEdit(true,mHeadersArea, "replyToLine");
  199. TQToolTip::add( mEdtReplyTo,
  200. i18n( "Set the \"Reply-To:\" email address for this message" ) );
  201. connect(mEdtReplyTo,TQT_SIGNAL(completionModeChanged(TDEGlobalSettings::Completion)),
  202. TQT_SLOT(slotCompletionModeChanged(TDEGlobalSettings::Completion)));
  203. if ( mClassicalRecipients ) {
  204. mRecipientsEditor = 0;
  205. mEdtTo = new KMLineEdit(true,mHeadersArea, "toLine");
  206. mEdtCc = new KMLineEdit(true,mHeadersArea, "ccLine");
  207. mEdtBcc = new KMLineEdit(true,mHeadersArea, "bccLine");
  208. mLblTo = new TQLabel(mHeadersArea);
  209. mLblCc = new TQLabel(mHeadersArea);
  210. mLblBcc = new TQLabel(mHeadersArea);
  211. mBtnTo = new TQPushButton("...",mHeadersArea);
  212. mBtnCc = new TQPushButton("...",mHeadersArea);
  213. mBtnBcc = new TQPushButton("...",mHeadersArea);
  214. //mBtnFrom = new TQPushButton("...",mHeadersArea);
  215. TQString tip = i18n("Select email address(es)");
  216. TQToolTip::add( mBtnTo, tip );
  217. TQToolTip::add( mBtnCc, tip );
  218. TQToolTip::add( mBtnBcc, tip );
  219. mBtnTo->setFocusPolicy(TQ_NoFocus);
  220. mBtnCc->setFocusPolicy(TQ_NoFocus);
  221. mBtnBcc->setFocusPolicy(TQ_NoFocus);
  222. //mBtnFrom->setFocusPolicy(TQ_NoFocus);
  223. connect(mBtnTo,TQT_SIGNAL(clicked()),TQT_SLOT(slotAddrBookTo()));
  224. connect(mBtnCc,TQT_SIGNAL(clicked()),TQT_SLOT(slotAddrBookTo()));
  225. connect(mBtnBcc,TQT_SIGNAL(clicked()),TQT_SLOT(slotAddrBookTo()));
  226. //connect(mBtnFrom,TQT_SIGNAL(clicked()),TQT_SLOT(slotAddrBookFrom()));
  227. connect(mEdtTo,TQT_SIGNAL(completionModeChanged(TDEGlobalSettings::Completion)),
  228. TQT_SLOT(slotCompletionModeChanged(TDEGlobalSettings::Completion)));
  229. connect(mEdtCc,TQT_SIGNAL(completionModeChanged(TDEGlobalSettings::Completion)),
  230. TQT_SLOT(slotCompletionModeChanged(TDEGlobalSettings::Completion)));
  231. connect(mEdtBcc,TQT_SIGNAL(completionModeChanged(TDEGlobalSettings::Completion)),
  232. TQT_SLOT(slotCompletionModeChanged(TDEGlobalSettings::Completion)));
  233. mEdtTo->setFocus();
  234. } else {
  235. mEdtTo = 0;
  236. mEdtCc = 0;
  237. mEdtBcc = 0;
  238. mLblTo = 0;
  239. mLblCc = 0;
  240. mLblBcc = 0;
  241. mBtnTo = 0;
  242. mBtnCc = 0;
  243. mBtnBcc = 0;
  244. //mBtnFrom = 0;
  245. mRecipientsEditor = new RecipientsEditor( mHeadersArea );
  246. connect( mRecipientsEditor,
  247. TQT_SIGNAL( completionModeChanged( TDEGlobalSettings::Completion ) ),
  248. TQT_SLOT( slotCompletionModeChanged( TDEGlobalSettings::Completion ) ) );
  249. connect( mRecipientsEditor, TQT_SIGNAL(sizeHintChanged()), TQT_SLOT(recipientEditorSizeHintChanged()) );
  250. mRecipientsEditor->setFocus();
  251. }
  252. mEdtSubject = new KMLineEditSpell(false,mHeadersArea, "subjectLine");
  253. TQToolTip::add( mEdtSubject,
  254. i18n( "Set a subject for this message" ) );
  255. mLblIdentity = new TQLabel( i18n("&Identity:"), mHeadersArea );
  256. mDictionaryLabel = new TQLabel( i18n("&Dictionary:"), mHeadersArea );
  257. mLblFcc = new TQLabel( i18n("&Sent-Mail folder:"), mHeadersArea );
  258. mLblTransport = new TQLabel( i18n("&Mail transport:"), mHeadersArea );
  259. mLblFrom = new TQLabel( i18n("sender address field", "&From:"), mHeadersArea );
  260. mLblReplyTo = new TQLabel( i18n("&Reply to:"), mHeadersArea );
  261. mLblSubject = new TQLabel( i18n("S&ubject:"), mHeadersArea );
  262. TQString sticky = i18n("Sticky");
  263. mBtnIdentity = new TQCheckBox(sticky,mHeadersArea);
  264. TQToolTip::add( mBtnIdentity,
  265. i18n( "Use the selected value as your identity for future messages" ) );
  266. mBtnFcc = new TQCheckBox(sticky,mHeadersArea);
  267. TQToolTip::add( mBtnFcc,
  268. i18n( "Use the selected value as your sent-mail folder for future messages" ) );
  269. mBtnTransport = new TQCheckBox(sticky,mHeadersArea);
  270. TQToolTip::add( mBtnTransport,
  271. i18n( "Use the selected value as your outgoing account for future messages" ) );
  272. mBtnDictionary = new TQCheckBox( sticky, mHeadersArea );
  273. TQToolTip::add( mBtnDictionary,
  274. i18n( "Use the selected value as your dictionary for future messages" ) );
  275. //setWFlags( WType_TopLevel | WStyle_Dialog );
  276. mHtmlMarkup = GlobalSettings::self()->useHtmlMarkup();
  277. mShowHeaders = GlobalSettings::self()->headers();
  278. mDone = false;
  279. mGrid = 0;
  280. mAtmListView = 0;
  281. mAtmList.setAutoDelete(true);
  282. mAtmTempList.setAutoDelete(true);
  283. mAtmModified = false;
  284. mAutoDeleteMsg = false;
  285. mFolder = 0;
  286. mAutoCharset = true;
  287. mFixedFontAction = 0;
  288. mTempDir = 0;
  289. // the attachment view is separated from the editor by a splitter
  290. mSplitter = new TQSplitter( Qt::Vertical, mHeadersToEditorSplitter, "mSplitter" );
  291. mSplitter->setChildrenCollapsible( false );
  292. mSnippetSplitter = new TQSplitter( Qt::Horizontal, mSplitter, "mSnippetSplitter");
  293. mSnippetSplitter->setChildrenCollapsible( false );
  294. TQWidget *editorAndCryptoStateIndicators = new TQWidget( mSnippetSplitter );
  295. TQVBoxLayout *vbox = new TQVBoxLayout( editorAndCryptoStateIndicators );
  296. TQHBoxLayout *hbox = new TQHBoxLayout( vbox );
  297. {
  298. mSignatureStateIndicator = new TQLabel( editorAndCryptoStateIndicators );
  299. mSignatureStateIndicator->setAlignment( TQt::AlignHCenter );
  300. hbox->addWidget( mSignatureStateIndicator );
  301. TDEConfigGroup reader( KMKernel::config(), "Reader" );
  302. TQPalette p( mSignatureStateIndicator->palette() );
  303. TQColor defaultSignedColor( 0x40, 0xFF, 0x40 ); // light green // pgp ok, trusted key
  304. TQColor defaultEncryptedColor( 0x00, 0x80, 0xFF ); // light blue // pgp encrypted
  305. p.setColor( TQColorGroup::Background, reader.readColorEntry( "PGPMessageOkKeyOk", &defaultSignedColor ) );
  306. mSignatureStateIndicator->setPalette( p );
  307. mEncryptionStateIndicator = new TQLabel( editorAndCryptoStateIndicators );
  308. mEncryptionStateIndicator->setAlignment( TQt::AlignHCenter );
  309. hbox->addWidget( mEncryptionStateIndicator );
  310. p.setColor( TQColorGroup::Background, reader.readColorEntry( "PGPMessageEncr" , &defaultEncryptedColor ) );
  311. mEncryptionStateIndicator->setPalette( p );
  312. }
  313. mEditor = new KMEdit( editorAndCryptoStateIndicators, this, mDictionaryCombo->spellConfig() );
  314. vbox->addWidget( mEditor );
  315. mSnippetWidget = new SnippetWidget( mEditor, actionCollection(), mSnippetSplitter );
  316. mSnippetWidget->setShown( GlobalSettings::self()->showSnippetManager() );
  317. // mSplitter->moveToFirst( editorAndCryptoStateIndicators );
  318. mSplitter->setOpaqueResize( true );
  319. mEditor->initializeAutoSpellChecking();
  320. mEditor->setTextFormat(TQt::PlainText);
  321. mEditor->setAcceptDrops( true );
  322. TQWhatsThis::add( mBtnIdentity,
  323. GlobalSettings::self()->stickyIdentityItem()->whatsThis() );
  324. TQWhatsThis::add( mBtnFcc,
  325. GlobalSettings::self()->stickyFccItem()->whatsThis() );
  326. TQWhatsThis::add( mBtnTransport,
  327. GlobalSettings::self()->stickyTransportItem()->whatsThis() );
  328. TQWhatsThis::add( mBtnTransport,
  329. GlobalSettings::self()->stickyDictionaryItem()->whatsThis() );
  330. mSpellCheckInProgress=false;
  331. setCaption( i18n("Composer") );
  332. setMinimumSize(200,200);
  333. mBtnIdentity->setFocusPolicy(TQ_NoFocus);
  334. mBtnFcc->setFocusPolicy(TQ_NoFocus);
  335. mBtnTransport->setFocusPolicy(TQ_NoFocus);
  336. mBtnDictionary->setFocusPolicy( TQ_NoFocus );
  337. mAtmListView = new AttachmentListView( this, mSplitter,
  338. "attachment list view" );
  339. mAtmListView->setSelectionMode( TQListView::Extended );
  340. mAtmListView->addColumn( i18n("Name"), 200 );
  341. mAtmListView->addColumn( i18n("Size"), 80 );
  342. mAtmListView->addColumn( i18n("Encoding"), 120 );
  343. int atmColType = mAtmListView->addColumn( i18n("Type"), 120 );
  344. // Stretch "Type".
  345. mAtmListView->header()->setStretchEnabled( true, atmColType );
  346. mAtmEncryptColWidth = 80;
  347. mAtmSignColWidth = 80;
  348. mAtmCompressColWidth = 100;
  349. mAtmColCompress = mAtmListView->addColumn( i18n("Compress"),
  350. mAtmCompressColWidth );
  351. mAtmColEncrypt = mAtmListView->addColumn( i18n("Encrypt"),
  352. mAtmEncryptColWidth );
  353. mAtmColSign = mAtmListView->addColumn( i18n("Sign"),
  354. mAtmSignColWidth );
  355. mAtmListView->setColumnWidth( mAtmColEncrypt, 0 );
  356. mAtmListView->setColumnWidth( mAtmColSign, 0 );
  357. mAtmListView->setAllColumnsShowFocus( true );
  358. connect( mAtmListView,
  359. TQT_SIGNAL( doubleClicked( TQListViewItem* ) ),
  360. TQT_SLOT( slotAttachEdit() ) );
  361. connect( mAtmListView,
  362. TQT_SIGNAL( rightButtonPressed( TQListViewItem*, const TQPoint&, int ) ),
  363. TQT_SLOT( slotAttachPopupMenu( TQListViewItem*, const TQPoint&, int ) ) );
  364. connect( mAtmListView,
  365. TQT_SIGNAL( selectionChanged() ),
  366. TQT_SLOT( slotUpdateAttachActions() ) );
  367. connect( mAtmListView,
  368. TQT_SIGNAL( attachmentDeleted() ),
  369. TQT_SLOT( slotAttachRemove() ) );
  370. connect( mAtmListView,
  371. TQT_SIGNAL( dragStarted() ),
  372. TQT_SLOT( slotAttachmentDragStarted() ) );
  373. mAttachMenu = 0;
  374. readConfig();
  375. setupStatusBar();
  376. setupActions();
  377. setupEditor();
  378. slotUpdateSignatureAndEncrypionStateIndicators();
  379. applyMainWindowSettings(KMKernel::config(), "Composer");
  380. connect( mEdtSubject, TQT_SIGNAL( subjectTextSpellChecked() ),
  381. TQT_SLOT( slotSubjectTextSpellChecked() ) );
  382. connect(mEdtSubject,TQT_SIGNAL(textChanged(const TQString&)),
  383. TQT_SLOT(slotUpdWinTitle(const TQString&)));
  384. connect(mIdentity,TQT_SIGNAL(identityChanged(uint)),
  385. TQT_SLOT(slotIdentityChanged(uint)));
  386. connect( kmkernel->identityManager(), TQT_SIGNAL(changed(uint)),
  387. TQT_SLOT(slotIdentityChanged(uint)));
  388. connect(mEdtFrom,TQT_SIGNAL(completionModeChanged(TDEGlobalSettings::Completion)),
  389. TQT_SLOT(slotCompletionModeChanged(TDEGlobalSettings::Completion)));
  390. connect(kmkernel->folderMgr(),TQT_SIGNAL(folderRemoved(KMFolder*)),
  391. TQT_SLOT(slotFolderRemoved(KMFolder*)));
  392. connect(kmkernel->imapFolderMgr(),TQT_SIGNAL(folderRemoved(KMFolder*)),
  393. TQT_SLOT(slotFolderRemoved(KMFolder*)));
  394. connect(kmkernel->dimapFolderMgr(),TQT_SIGNAL(folderRemoved(KMFolder*)),
  395. TQT_SLOT(slotFolderRemoved(KMFolder*)));
  396. connect( kmkernel, TQT_SIGNAL( configChanged() ),
  397. TQT_TQOBJECT(this), TQT_SLOT( slotConfigChanged() ) );
  398. connect (mEditor, TQT_SIGNAL (spellcheck_done(int)),
  399. this, TQT_SLOT (slotSpellcheckDone (int)));
  400. connect (mEditor, TQT_SIGNAL( attachPNGImageData(const TQByteArray &) ),
  401. this, TQT_SLOT ( slotAttachPNGImageData(const TQByteArray &) ) );
  402. connect (mEditor, TQT_SIGNAL( focusChanged(bool) ),
  403. this, TQT_SLOT (editorFocusChanged(bool)) );
  404. mMainWidget->resize(480,510);
  405. setCentralWidget(mMainWidget);
  406. rethinkFields();
  407. if ( !mClassicalRecipients ) {
  408. // This is ugly, but if it isn't called the line edits in the recipients
  409. // editor aren't wide enough until the first resize event comes.
  410. rethinkFields();
  411. }
  412. if ( GlobalSettings::self()->useExternalEditor() ) {
  413. mEditor->setUseExternalEditor(true);
  414. mEditor->setExternalEditorPath( GlobalSettings::self()->externalEditor() );
  415. }
  416. initAutoSave();
  417. slotUpdateSignatureActions();
  418. mMsg = 0;
  419. if (aMsg)
  420. setMsg(aMsg);
  421. fontChanged( mEditor->currentFont() ); // set toolbar buttons to correct values
  422. mDone = true;
  423. }
  424. //-----------------------------------------------------------------------------
  425. KMComposeWin::~KMComposeWin()
  426. {
  427. writeConfig();
  428. if (mFolder && mMsg)
  429. {
  430. mAutoDeleteMsg = false;
  431. mFolder->addMsg(mMsg);
  432. // Ensure that the message is correctly and fully parsed
  433. mFolder->unGetMsg( mFolder->count() - 1 );
  434. }
  435. if (mAutoDeleteMsg) {
  436. delete mMsg;
  437. mMsg = 0;
  438. }
  439. TQMap<TDEIO::Job*, atmLoadData>::Iterator it = mMapAtmLoadData.begin();
  440. while ( it != mMapAtmLoadData.end() )
  441. {
  442. TDEIO::Job *job = it.key();
  443. mMapAtmLoadData.remove( it );
  444. job->kill();
  445. it = mMapAtmLoadData.begin();
  446. }
  447. deleteAll( mComposedMessages );
  448. for ( std::set<KTempDir*>::iterator it = mTempDirs.begin() ; it != mTempDirs.end() ; ++it ) {
  449. delete *it;
  450. }
  451. }
  452. void KMComposeWin::setAutoDeleteWindow( bool f )
  453. {
  454. if ( f )
  455. setWFlags( getWFlags() | WDestructiveClose );
  456. else
  457. setWFlags( getWFlags() & ~WDestructiveClose );
  458. }
  459. //-----------------------------------------------------------------------------
  460. void KMComposeWin::send(int how)
  461. {
  462. switch (how) {
  463. case 1:
  464. slotSendNow();
  465. break;
  466. default:
  467. case 0:
  468. // TODO: find out, what the default send method is and send it this way
  469. case 2:
  470. slotSendLater();
  471. break;
  472. }
  473. }
  474. //-----------------------------------------------------------------------------
  475. void KMComposeWin::addAttachmentsAndSend(const KURL::List &urls, const TQString &/*comment*/, int how)
  476. {
  477. if (urls.isEmpty())
  478. {
  479. send(how);
  480. return;
  481. }
  482. mAttachFilesSend = how;
  483. mAttachFilesPending = urls;
  484. connect(this, TQT_SIGNAL(attachmentAdded(const KURL&, bool)), TQT_SLOT(slotAttachedFile(const KURL&)));
  485. for( KURL::List::ConstIterator itr = urls.begin(); itr != urls.end(); ++itr ) {
  486. if (!addAttach( *itr ))
  487. mAttachFilesPending.remove(mAttachFilesPending.find(*itr)); // only remove one copy of the url
  488. }
  489. if (mAttachFilesPending.isEmpty() && mAttachFilesSend == how)
  490. {
  491. send(mAttachFilesSend);
  492. mAttachFilesSend = -1;
  493. }
  494. }
  495. void KMComposeWin::slotAttachedFile(const KURL &url)
  496. {
  497. if (mAttachFilesPending.isEmpty())
  498. return;
  499. mAttachFilesPending.remove(mAttachFilesPending.find(url)); // only remove one copy of url
  500. if (mAttachFilesPending.isEmpty())
  501. {
  502. send(mAttachFilesSend);
  503. mAttachFilesSend = -1;
  504. }
  505. }
  506. //-----------------------------------------------------------------------------
  507. void KMComposeWin::addAttachment(KURL url,TQString /*comment*/)
  508. {
  509. addAttach(url);
  510. }
  511. //-----------------------------------------------------------------------------
  512. void KMComposeWin::addAttachment(const TQString &name,
  513. const TQCString &/*cte*/,
  514. const TQByteArray &data,
  515. const TQCString &type,
  516. const TQCString &subType,
  517. const TQCString &paramAttr,
  518. const TQString &paramValue,
  519. const TQCString &contDisp)
  520. {
  521. if (!data.isEmpty()) {
  522. KMMessagePart *msgPart = new KMMessagePart;
  523. msgPart->setName(name);
  524. if( type == "message" && subType == "rfc822" ) {
  525. msgPart->setMessageBody( data );
  526. } else {
  527. TQValueList<int> dummy;
  528. msgPart->setBodyAndGuessCte(data, dummy,
  529. kmkernel->msgSender()->sendQuotedPrintable());
  530. }
  531. msgPart->setTypeStr(type);
  532. msgPart->setSubtypeStr(subType);
  533. msgPart->setParameter(paramAttr,paramValue);
  534. msgPart->setContentDisposition(contDisp);
  535. addAttach(msgPart);
  536. }
  537. }
  538. //-----------------------------------------------------------------------------
  539. void KMComposeWin::slotAttachPNGImageData(const TQByteArray &image)
  540. {
  541. bool ok;
  542. TQString attName = KInputDialog::getText( "KMail", i18n("Name of the attachment:"), TQString(), &ok, this );
  543. if ( !ok )
  544. return;
  545. if ( !attName.lower().endsWith(".png") ) attName += ".png";
  546. addAttachment( attName, "base64", image, "image", "png", TQCString(), TQString(), TQCString() );
  547. }
  548. //-----------------------------------------------------------------------------
  549. void KMComposeWin::setBody(TQString body)
  550. {
  551. mEditor->setText(body);
  552. }
  553. //-----------------------------------------------------------------------------
  554. bool KMComposeWin::event(TQEvent *e)
  555. {
  556. if (e->type() == TQEvent::ApplicationPaletteChange)
  557. {
  558. readColorConfig();
  559. }
  560. return KMail::Composer::event(e);
  561. }
  562. //-----------------------------------------------------------------------------
  563. void KMComposeWin::readColorConfig(void)
  564. {
  565. if ( GlobalSettings::self()->useDefaultColors() ) {
  566. mForeColor = TQColor(kapp->palette().active().text());
  567. mBackColor = TQColor(kapp->palette().active().base());
  568. } else {
  569. mForeColor = GlobalSettings::self()->foregroundColor();
  570. mBackColor = GlobalSettings::self()->backgroundColor();
  571. }
  572. // Color setup
  573. mPalette = kapp->palette();
  574. TQColorGroup cgrp = mPalette.active();
  575. cgrp.setColor( TQColorGroup::Base, mBackColor);
  576. cgrp.setColor( TQColorGroup::Text, mForeColor);
  577. mPalette.setDisabled(cgrp);
  578. mPalette.setActive(cgrp);
  579. mPalette.setInactive(cgrp);
  580. mEdtFrom->setPalette(mPalette);
  581. mEdtReplyTo->setPalette(mPalette);
  582. if ( mClassicalRecipients ) {
  583. mEdtTo->setPalette(mPalette);
  584. mEdtCc->setPalette(mPalette);
  585. mEdtBcc->setPalette(mPalette);
  586. }
  587. mEdtSubject->setPalette(mPalette);
  588. mTransport->setPalette(mPalette);
  589. mEditor->setPalette(mPalette);
  590. mFcc->setPalette(mPalette);
  591. }
  592. //-----------------------------------------------------------------------------
  593. void KMComposeWin::readConfig( bool reload /* = false */ )
  594. {
  595. mDefCharset = KMMessage::defaultCharset();
  596. mBtnIdentity->setChecked( GlobalSettings::self()->stickyIdentity() );
  597. if (mBtnIdentity->isChecked()) {
  598. mId = (GlobalSettings::self()->previousIdentity()!=0) ?
  599. GlobalSettings::self()->previousIdentity() : mId;
  600. }
  601. mBtnFcc->setChecked( GlobalSettings::self()->stickyFcc() );
  602. mBtnTransport->setChecked( GlobalSettings::self()->stickyTransport() );
  603. mBtnDictionary->setChecked( GlobalSettings::self()->stickyDictionary() );
  604. TQStringList transportHistory = GlobalSettings::self()->transportHistory();
  605. TQString currentTransport = GlobalSettings::self()->currentTransport();
  606. mEdtFrom->setCompletionMode( (TDEGlobalSettings::Completion)GlobalSettings::self()->completionMode() );
  607. mEdtReplyTo->setCompletionMode( (TDEGlobalSettings::Completion)GlobalSettings::self()->completionMode() );
  608. if ( mClassicalRecipients ) {
  609. mEdtTo->setCompletionMode( (TDEGlobalSettings::Completion)GlobalSettings::self()->completionMode() );
  610. mEdtCc->setCompletionMode( (TDEGlobalSettings::Completion)GlobalSettings::self()->completionMode() );
  611. mEdtBcc->setCompletionMode( (TDEGlobalSettings::Completion)GlobalSettings::self()->completionMode() );
  612. }
  613. else
  614. mRecipientsEditor->setCompletionMode( (TDEGlobalSettings::Completion)GlobalSettings::self()->completionMode() );
  615. readColorConfig();
  616. if ( GlobalSettings::self()->useDefaultFonts() ) {
  617. mBodyFont = TDEGlobalSettings::generalFont();
  618. mFixedFont = TDEGlobalSettings::fixedFont();
  619. } else {
  620. mBodyFont = GlobalSettings::self()->composerFont();
  621. mFixedFont = GlobalSettings::self()->fixedFont();
  622. }
  623. slotUpdateFont();
  624. mEdtFrom->setFont(mBodyFont);
  625. mEdtReplyTo->setFont(mBodyFont);
  626. if ( mClassicalRecipients ) {
  627. mEdtTo->setFont(mBodyFont);
  628. mEdtCc->setFont(mBodyFont);
  629. mEdtBcc->setFont(mBodyFont);
  630. }
  631. mEdtSubject->setFont(mBodyFont);
  632. if ( !reload ) {
  633. TQSize siz = GlobalSettings::self()->composerSize();
  634. if (siz.width() < 200) siz.setWidth(200);
  635. if (siz.height() < 200) siz.setHeight(200);
  636. resize(siz);
  637. if ( !GlobalSettings::self()->snippetSplitterPosition().isEmpty() ) {
  638. mSnippetSplitter->setSizes( GlobalSettings::self()->snippetSplitterPosition() );
  639. } else {
  640. TQValueList<int> defaults;
  641. defaults << (int)(width() * 0.8) << (int)(width() * 0.2);
  642. mSnippetSplitter->setSizes( defaults );
  643. }
  644. }
  645. mIdentity->setCurrentIdentity( mId );
  646. kdDebug(5006) << "KMComposeWin::readConfig. " << mIdentity->currentIdentityName() << endl;
  647. const KPIM::Identity & ident =
  648. kmkernel->identityManager()->identityForUoid( mIdentity->currentIdentity() );
  649. mTransport->clear();
  650. mTransport->insertStringList( KMTransportInfo::availableTransports() );
  651. while ( transportHistory.count() > (uint)GlobalSettings::self()->maxTransportEntries() )
  652. transportHistory.remove( transportHistory.last() );
  653. mTransport->insertStringList( transportHistory );
  654. mTransport->setCurrentText( GlobalSettings::self()->defaultTransport() );
  655. if ( mBtnTransport->isChecked() ) {
  656. setTransport( currentTransport );
  657. }
  658. if ( mBtnDictionary->isChecked() ) {
  659. mDictionaryCombo->setCurrentByDictionaryName( GlobalSettings::self()->previousDictionary() );
  660. } else {
  661. mDictionaryCombo->setCurrentByDictionary( ident.dictionary() );
  662. }
  663. TQString fccName = "";
  664. if ( mBtnFcc->isChecked() ) {
  665. fccName = GlobalSettings::self()->previousFcc();
  666. } else if ( !ident.fcc().isEmpty() ) {
  667. fccName = ident.fcc();
  668. }
  669. setFcc( fccName );
  670. }
  671. //-----------------------------------------------------------------------------
  672. void KMComposeWin::writeConfig(void)
  673. {
  674. GlobalSettings::self()->setHeaders( mShowHeaders );
  675. GlobalSettings::self()->setStickyFcc( mBtnFcc->isChecked() );
  676. if ( !mIgnoreStickyFields ) {
  677. GlobalSettings::self()->setCurrentTransport( mTransport->currentText() );
  678. GlobalSettings::self()->setStickyTransport( mBtnTransport->isChecked() );
  679. GlobalSettings::self()->setStickyDictionary( mBtnDictionary->isChecked() );
  680. GlobalSettings::self()->setStickyIdentity( mBtnIdentity->isChecked() );
  681. GlobalSettings::self()->setPreviousIdentity( mIdentity->currentIdentity() );
  682. }
  683. GlobalSettings::self()->setPreviousFcc( mFcc->getFolder()->idString() );
  684. GlobalSettings::self()->setPreviousDictionary( mDictionaryCombo->currentDictionaryName() );
  685. GlobalSettings::self()->setAutoSpellChecking(
  686. mAutoSpellCheckingAction->isChecked() );
  687. TQStringList transportHistory = GlobalSettings::self()->transportHistory();
  688. transportHistory.remove(mTransport->currentText());
  689. if (KMTransportInfo::availableTransports().findIndex(mTransport
  690. ->currentText()) == -1) {
  691. transportHistory.prepend(mTransport->currentText());
  692. }
  693. GlobalSettings::self()->setTransportHistory( transportHistory );
  694. GlobalSettings::self()->setUseFixedFont( mFixedFontAction->isChecked() );
  695. GlobalSettings::self()->setUseHtmlMarkup( mHtmlMarkup );
  696. GlobalSettings::self()->setComposerSize( size() );
  697. GlobalSettings::self()->setShowSnippetManager( mSnippetAction->isChecked() );
  698. TDEConfigGroupSaver saver( KMKernel::config(), "Geometry" );
  699. saveMainWindowSettings( KMKernel::config(), "Composer" );
  700. GlobalSettings::setSnippetSplitterPosition( mSnippetSplitter->sizes() );
  701. // make sure config changes are written to disk, cf. bug 127538
  702. GlobalSettings::self()->writeConfig();
  703. }
  704. //-----------------------------------------------------------------------------
  705. void KMComposeWin::autoSaveMessage()
  706. {
  707. kdDebug(5006) << k_funcinfo << endl;
  708. if ( !mMsg || mComposer || mAutoSaveFilename.isEmpty() )
  709. return;
  710. kdDebug(5006) << k_funcinfo << "autosaving message" << endl;
  711. if ( mAutoSaveTimer )
  712. mAutoSaveTimer->stop();
  713. connect( this, TQT_SIGNAL( applyChangesDone( bool ) ),
  714. TQT_TQOBJECT(this), TQT_SLOT( slotContinueAutoSave() ) );
  715. // This method is called when KMail crashed, so don't try signing/encryption
  716. // and don't disable controls because it is also called from a timer and
  717. // then the disabling is distracting.
  718. applyChanges( true, true );
  719. // Don't continue before the applyChanges is done!
  720. }
  721. void KMComposeWin::slotContinueAutoSave()
  722. {
  723. disconnect( this, TQT_SIGNAL( applyChangesDone( bool ) ),
  724. TQT_TQOBJECT(this), TQT_SLOT( slotContinueAutoSave() ) );
  725. // Ok, it's done now - continue dead letter saving
  726. if ( mComposedMessages.isEmpty() ) {
  727. kdDebug(5006) << "Composing the message failed." << endl;
  728. return;
  729. }
  730. KMMessage *msg = mComposedMessages.first();
  731. if ( !msg ) // a bit of extra defensiveness
  732. return;
  733. kdDebug(5006) << k_funcinfo << "opening autoSaveFile " << mAutoSaveFilename
  734. << endl;
  735. const TQString filename =
  736. KMKernel::localDataPath() + "autosave/cur/" + mAutoSaveFilename;
  737. KSaveFile autoSaveFile( filename, 0600 );
  738. int status = autoSaveFile.status();
  739. kdDebug(5006) << k_funcinfo << "autoSaveFile.status() = " << status << endl;
  740. if ( status == 0 ) { // no error
  741. kdDebug(5006) << "autosaving message in " << filename << endl;
  742. int fd = autoSaveFile.handle();
  743. const DwString& msgStr = msg->asDwString();
  744. if ( ::write( fd, msgStr.data(), msgStr.length() ) == -1 )
  745. status = errno;
  746. }
  747. if ( status == 0 ) {
  748. kdDebug(5006) << k_funcinfo << "closing autoSaveFile" << endl;
  749. autoSaveFile.close();
  750. mLastAutoSaveErrno = 0;
  751. }
  752. else {
  753. kdDebug(5006) << k_funcinfo << "autosaving failed" << endl;
  754. autoSaveFile.abort();
  755. if ( status != mLastAutoSaveErrno ) {
  756. // don't show the same error message twice
  757. KMessageBox::queuedMessageBox( 0, KMessageBox::Sorry,
  758. i18n("Autosaving the message as %1 "
  759. "failed.\n"
  760. "Reason: %2" )
  761. .arg( filename, strerror( status ) ),
  762. i18n("Autosaving Failed") );
  763. mLastAutoSaveErrno = status;
  764. }
  765. }
  766. if ( autoSaveInterval() > 0 )
  767. updateAutoSave();
  768. }
  769. //-----------------------------------------------------------------------------
  770. void KMComposeWin::slotView(void)
  771. {
  772. if (!mDone)
  773. return; // otherwise called from rethinkFields during the construction
  774. // which is not the intended behavior
  775. int id;
  776. //This sucks awfully, but no, I cannot get an activated(int id) from
  777. // actionContainer()
  778. if (!TQT_TQOBJECT_CONST(sender())->isA("TDEToggleAction"))
  779. return;
  780. TDEToggleAction *act = (TDEToggleAction *) sender();
  781. if (act == mAllFieldsAction)
  782. id = 0;
  783. else if (act == mIdentityAction)
  784. id = HDR_IDENTITY;
  785. else if (act == mTransportAction)
  786. id = HDR_TRANSPORT;
  787. else if (act == mFromAction)
  788. id = HDR_FROM;
  789. else if (act == mReplyToAction)
  790. id = HDR_REPLY_TO;
  791. else if (act == mToAction)
  792. id = HDR_TO;
  793. else if (act == mCcAction)
  794. id = HDR_CC;
  795. else if (act == mBccAction)
  796. id = HDR_BCC;
  797. else if (act == mSubjectAction)
  798. id = HDR_SUBJECT;
  799. else if (act == mFccAction)
  800. id = HDR_FCC;
  801. else if ( act == mDictionaryAction )
  802. id = HDR_DICTIONARY;
  803. else
  804. {
  805. id = 0;
  806. kdDebug(5006) << "Something is wrong (Oh, yeah?)" << endl;
  807. return;
  808. }
  809. // sanders There's a bug here this logic doesn't work if no
  810. // fields are shown and then show all fields is selected.
  811. // Instead of all fields being shown none are.
  812. if (!act->isChecked())
  813. {
  814. // hide header
  815. if (id > 0) mShowHeaders = mShowHeaders & ~id;
  816. else mShowHeaders = abs(mShowHeaders);
  817. }
  818. else
  819. {
  820. // show header
  821. if (id > 0) mShowHeaders |= id;
  822. else mShowHeaders = -abs(mShowHeaders);
  823. }
  824. rethinkFields(true);
  825. }
  826. int KMComposeWin::calcColumnWidth(int which, long allShowing, int width)
  827. {
  828. if ( (allShowing & which) == 0 )
  829. return width;
  830. TQLabel *w;
  831. if ( which == HDR_IDENTITY )
  832. w = mLblIdentity;
  833. else if ( which == HDR_DICTIONARY )
  834. w = mDictionaryLabel;
  835. else if ( which == HDR_FCC )
  836. w = mLblFcc;
  837. else if ( which == HDR_TRANSPORT )
  838. w = mLblTransport;
  839. else if ( which == HDR_FROM )
  840. w = mLblFrom;
  841. else if ( which == HDR_REPLY_TO )
  842. w = mLblReplyTo;
  843. else if ( which == HDR_SUBJECT )
  844. w = mLblSubject;
  845. else
  846. return width;
  847. w->setBuddy( mEditor ); // set dummy so we don't calculate width of '&' for this label.
  848. w->adjustSize();
  849. w->show();
  850. return TQMAX( width, w->sizeHint().width() );
  851. }
  852. void KMComposeWin::rethinkFields(bool fromSlot)
  853. {
  854. //This sucks even more but again no ids. sorry (sven)
  855. int mask, row, numRows;
  856. long showHeaders;
  857. if (mShowHeaders < 0)
  858. showHeaders = HDR_ALL;
  859. else
  860. showHeaders = mShowHeaders;
  861. for (mask=1,mNumHeaders=0; mask<=showHeaders; mask<<=1)
  862. if ((showHeaders&mask) != 0) mNumHeaders++;
  863. numRows = mNumHeaders + 1;
  864. delete mGrid;
  865. mGrid = new TQGridLayout( mHeadersArea, numRows, 3, KDialogBase::marginHint()/2, KDialogBase::spacingHint());
  866. mGrid->setColStretch(0, 1);
  867. mGrid->setColStretch(1, 100);
  868. mGrid->setColStretch(2, 1);
  869. mGrid->setRowStretch( mNumHeaders + 1, 100 );
  870. row = 0;
  871. kdDebug(5006) << "KMComposeWin::rethinkFields" << endl;
  872. if (mRecipientsEditor)
  873. mLabelWidth = mRecipientsEditor->setFirstColumnWidth( 0 );
  874. mLabelWidth = calcColumnWidth( HDR_IDENTITY, showHeaders, mLabelWidth );
  875. mLabelWidth = calcColumnWidth( HDR_DICTIONARY, showHeaders, mLabelWidth );
  876. mLabelWidth = calcColumnWidth( HDR_FCC, showHeaders, mLabelWidth );
  877. mLabelWidth = calcColumnWidth( HDR_TRANSPORT, showHeaders, mLabelWidth );
  878. mLabelWidth = calcColumnWidth( HDR_FROM, showHeaders, mLabelWidth );
  879. mLabelWidth = calcColumnWidth( HDR_REPLY_TO, showHeaders, mLabelWidth );
  880. mLabelWidth = calcColumnWidth( HDR_SUBJECT, showHeaders, mLabelWidth );
  881. if (!fromSlot) mAllFieldsAction->setChecked(showHeaders==HDR_ALL);
  882. if (!fromSlot) mIdentityAction->setChecked(abs(mShowHeaders)&HDR_IDENTITY);
  883. rethinkHeaderLine(showHeaders,HDR_IDENTITY, row,
  884. mLblIdentity, mIdentity, mBtnIdentity);
  885. if (!fromSlot) mDictionaryAction->setChecked(abs(mShowHeaders)&HDR_DICTIONARY);
  886. rethinkHeaderLine(showHeaders,HDR_DICTIONARY, row,
  887. mDictionaryLabel, mDictionaryCombo, mBtnDictionary );
  888. if (!fromSlot) mFccAction->setChecked(abs(mShowHeaders)&HDR_FCC);
  889. rethinkHeaderLine(showHeaders,HDR_FCC, row,
  890. mLblFcc, mFcc, mBtnFcc);
  891. if (!fromSlot) mTransportAction->setChecked(abs(mShowHeaders)&HDR_TRANSPORT);
  892. rethinkHeaderLine(showHeaders,HDR_TRANSPORT, row,
  893. mLblTransport, mTransport, mBtnTransport);
  894. if (!fromSlot) mFromAction->setChecked(abs(mShowHeaders)&HDR_FROM);
  895. rethinkHeaderLine(showHeaders,HDR_FROM, row,
  896. mLblFrom, mEdtFrom /*, mBtnFrom */ );
  897. TQWidget *prevFocus = mEdtFrom;
  898. if (!fromSlot) mReplyToAction->setChecked(abs(mShowHeaders)&HDR_REPLY_TO);
  899. rethinkHeaderLine(showHeaders,HDR_REPLY_TO,row,
  900. mLblReplyTo, mEdtReplyTo, 0);
  901. if ( showHeaders & HDR_REPLY_TO ) {
  902. prevFocus = connectFocusMoving( prevFocus, mEdtReplyTo );
  903. }
  904. if ( mClassicalRecipients ) {
  905. if (!fromSlot) mToAction->setChecked(abs(mShowHeaders)&HDR_TO);
  906. rethinkHeaderLine(showHeaders, HDR_TO, row,
  907. mLblTo, mEdtTo, mBtnTo,
  908. i18n("Primary Recipients"),
  909. i18n("<qt>The email addresses you put "
  910. "in this field receive a copy of the email.</qt>"));
  911. if ( showHeaders & HDR_TO ) {
  912. prevFocus = connectFocusMoving( prevFocus, mEdtTo );
  913. }
  914. if (!fromSlot) mCcAction->setChecked(abs(mShowHeaders)&HDR_CC);
  915. rethinkHeaderLine(showHeaders, HDR_CC, row,
  916. mLblCc, mEdtCc, mBtnCc,
  917. i18n("Additional Recipients"),
  918. i18n("<qt>The email addresses you put "
  919. "in this field receive a copy of the email. "
  920. "Technically it is the same thing as putting all the "
  921. "addresses in the <b>To:</b> field but differs in "
  922. "that it usually symbolises the receiver of the "
  923. "Carbon Copy (CC) is a listener, not the main "
  924. "recipient.</qt>"));
  925. if ( showHeaders & HDR_CC ) {
  926. prevFocus = connectFocusMoving( prevFocus, mEdtCc );
  927. }
  928. if (!fromSlot) mBccAction->setChecked(abs(mShowHeaders)&HDR_BCC);
  929. rethinkHeaderLine(showHeaders,HDR_BCC, row,
  930. mLblBcc, mEdtBcc, mBtnBcc,
  931. i18n("Hidden Recipients"),
  932. i18n("<qt>Essentially the same thing "
  933. "as the <b>Copy To:</b> field but differs in that "
  934. "all other recipients do not see who receives a "
  935. "blind copy.</qt>"));
  936. if ( showHeaders & HDR_BCC ) {
  937. prevFocus = connectFocusMoving( prevFocus, mEdtBcc );
  938. }
  939. } else {
  940. mGrid->addMultiCellWidget( mRecipientsEditor, row, row, 0, 2 );
  941. ++row;
  942. if ( showHeaders & HDR_REPLY_TO ) {
  943. connect( mEdtReplyTo, TQT_SIGNAL( focusDown() ), mRecipientsEditor,
  944. TQT_SLOT( setFocusTop() ) );
  945. } else {
  946. connect( mEdtFrom, TQT_SIGNAL( focusDown() ), mRecipientsEditor,
  947. TQT_SLOT( setFocusTop() ) );
  948. }
  949. if ( showHeaders & HDR_REPLY_TO ) {
  950. connect( mRecipientsEditor, TQT_SIGNAL( focusUp() ), mEdtReplyTo, TQT_SLOT( setFocus() ) );
  951. } else {
  952. connect( mRecipientsEditor, TQT_SIGNAL( focusUp() ), mEdtFrom, TQT_SLOT( setFocus() ) );
  953. }
  954. connect( mRecipientsEditor, TQT_SIGNAL( focusDown() ), mEdtSubject,
  955. TQT_SLOT( setFocus() ) );
  956. connect( mEdtSubject, TQT_SIGNAL( focusUp() ), mRecipientsEditor,
  957. TQT_SLOT( setFocusBottom() ) );
  958. prevFocus = mRecipientsEditor;
  959. }
  960. if (!fromSlot) mSubjectAction->setChecked(abs(mShowHeaders)&HDR_SUBJECT);
  961. rethinkHeaderLine(showHeaders,HDR_SUBJECT, row,
  962. mLblSubject, mEdtSubject);
  963. connectFocusMoving( mEdtSubject, mEditor );
  964. assert(row<=mNumHeaders);
  965. if( !mAtmList.isEmpty() )
  966. mAtmListView->show();
  967. else
  968. mAtmListView->hide();
  969. resize(this->size());
  970. repaint();
  971. mHeadersArea->setMaximumHeight( mHeadersArea->sizeHint().height() );
  972. mGrid->activate();
  973. mHeadersArea->show();
  974. slotUpdateAttachActions();
  975. mIdentityAction->setEnabled(!mAllFieldsAction->isChecked());
  976. mDictionaryAction->setEnabled( !mAllFieldsAction->isChecked() );
  977. mTransportAction->setEnabled(!mAllFieldsAction->isChecked());
  978. mFromAction->setEnabled(!mAllFieldsAction->isChecked());
  979. if ( mReplyToAction ) mReplyToAction->setEnabled(!mAllFieldsAction->isChecked());
  980. if ( mToAction ) mToAction->setEnabled(!mAllFieldsAction->isChecked());
  981. if ( mCcAction ) mCcAction->setEnabled(!mAllFieldsAction->isChecked());
  982. if ( mBccAction ) mBccAction->setEnabled(!mAllFieldsAction->isChecked());
  983. mFccAction->setEnabled(!mAllFieldsAction->isChecked());
  984. mSubjectAction->setEnabled(!mAllFieldsAction->isChecked());
  985. if (mRecipientsEditor)
  986. mRecipientsEditor->setFirstColumnWidth( mLabelWidth );
  987. }
  988. TQWidget *KMComposeWin::connectFocusMoving( TQWidget *prev, TQWidget *next )
  989. {
  990. connect( prev, TQT_SIGNAL( focusDown() ), next, TQT_SLOT( setFocus() ) );
  991. connect( next, TQT_SIGNAL( focusUp() ), prev, TQT_SLOT( setFocus() ) );
  992. return next;
  993. }
  994. //-----------------------------------------------------------------------------
  995. void KMComposeWin::rethinkHeaderLine(int aValue, int aMask, int& aRow,
  996. TQLabel* aLbl,
  997. TQLineEdit* aEdt, TQPushButton* aBtn,
  998. const TQString &toolTip, const TQString &whatsThis )
  999. {
  1000. if (aValue & aMask)
  1001. {
  1002. if ( !toolTip.isEmpty() )
  1003. TQToolTip::add( aLbl, toolTip );
  1004. if ( !whatsThis.isEmpty() )
  1005. TQWhatsThis::add( aLbl, whatsThis );
  1006. aLbl->setFixedWidth( mLabelWidth );
  1007. aLbl->setBuddy(aEdt);
  1008. mGrid->addWidget(aLbl, aRow, 0);
  1009. aEdt->setBackgroundColor( mBackColor );
  1010. aEdt->show();
  1011. if (aBtn) {
  1012. mGrid->addWidget(aEdt, aRow, 1);
  1013. mGrid->addWidget(aBtn, aRow, 2);
  1014. aBtn->show();
  1015. } else {
  1016. mGrid->addMultiCellWidget(aEdt, aRow, aRow, 1, 2 );
  1017. }
  1018. aRow++;
  1019. }
  1020. else
  1021. {
  1022. aLbl->hide();
  1023. aEdt->hide();
  1024. if (aBtn) aBtn->hide();
  1025. }
  1026. }
  1027. //-----------------------------------------------------------------------------
  1028. void KMComposeWin::rethinkHeaderLine(int aValue, int aMask, int& aRow,
  1029. TQLabel* aLbl,
  1030. TQComboBox* aCbx, TQCheckBox* aChk)
  1031. {
  1032. if (aValue & aMask)
  1033. {
  1034. aLbl->adjustSize();
  1035. aLbl->resize((int)aLbl->sizeHint().width(),aLbl->sizeHint().height() + 6);
  1036. aLbl->setMinimumSize(aLbl->size());
  1037. aLbl->show();
  1038. aLbl->setBuddy(aCbx);
  1039. mGrid->addWidget(aLbl, aRow, 0);
  1040. aCbx->show();
  1041. aCbx->setMinimumSize(100, aLbl->height()+2);
  1042. mGrid->addWidget(aCbx, aRow, 1);
  1043. if ( aChk ) {
  1044. mGrid->addWidget(aChk, aRow, 2);
  1045. aChk->setFixedSize(aChk->sizeHint().width(), aLbl->height());
  1046. aChk->show();
  1047. }
  1048. aRow++;
  1049. }
  1050. else
  1051. {
  1052. aLbl->hide();
  1053. aCbx->hide();
  1054. if ( aChk )
  1055. aChk->hide();
  1056. }
  1057. }
  1058. //-----------------------------------------------------------------------------
  1059. void KMComposeWin::getTransportMenu()
  1060. {
  1061. TQStringList availTransports;
  1062. mActNowMenu->clear();
  1063. mActLaterMenu->clear();
  1064. availTransports = KMail::TransportManager::transportNames();
  1065. TQStringList::Iterator it;
  1066. int id = 0;
  1067. for(it = availTransports.begin(); it != availTransports.end() ; ++it, id++)
  1068. {
  1069. mActNowMenu->insertItem((*it).replace("&", "&&"), id);
  1070. mActLaterMenu->insertItem((*it).replace("&", "&&"), id);
  1071. }
  1072. }
  1073. //-----------------------------------------------------------------------------
  1074. void KMComposeWin::setupActions(void)
  1075. {
  1076. TDEActionMenu *actActionNowMenu, *actActionLaterMenu;
  1077. if (kmkernel->msgSender()->sendImmediate()) //default == send now?
  1078. {
  1079. //default = send now, alternative = queue
  1080. ( void ) new TDEAction( i18n("&Send Mail"), "mail_send", CTRL+Key_Return,
  1081. TQT_TQOBJECT(this), TQT_SLOT(slotSendNow()), actionCollection(),"send_default");
  1082. // FIXME: change to mail_send_via icon when this exits.
  1083. actActionNowMenu = new TDEActionMenu (i18n("&Send Mail Via"), "mail_send",
  1084. actionCollection(), "send_default_via" );
  1085. (void) new TDEAction (i18n("Send &Later"), "queue", 0, TQT_TQOBJECT(this),
  1086. TQT_SLOT(slotSendLater()), actionCollection(),"send_alternative");
  1087. actActionLaterMenu = new TDEActionMenu (i18n("Send &Later Via"), "queue",
  1088. actionCollection(), "send_alternative_via" );
  1089. }
  1090. else //no, default = send later
  1091. {
  1092. //default = queue, alternative = send now
  1093. (void) new TDEAction (i18n("Send &Later"), "queue",
  1094. CTRL+Key_Return,
  1095. TQT_TQOBJECT(this), TQT_SLOT(slotSendLater()), actionCollection(),"send_default");
  1096. actActionLaterMenu = new TDEActionMenu (i18n("Send &Later Via"), "queue",
  1097. actionCollection(), "send_default_via" );
  1098. ( void ) new TDEAction( i18n("&Send Mail"), "mail_send", 0,
  1099. TQT_TQOBJECT(this), TQT_SLOT(slotSendNow()), actionCollection(),"send_alternative");
  1100. // FIXME: change to mail_send_via icon when this exits.
  1101. actActionNowMenu = new TDEActionMenu (i18n("&Send Mail Via"), "mail_send",
  1102. actionCollection(), "send_alternative_via" );
  1103. }
  1104. // needed for sending "default transport"
  1105. actActionNowMenu->setDelayed(true);
  1106. actActionLaterMenu->setDelayed(true);
  1107. connect( actActionNowMenu, TQT_SIGNAL( activated() ), this,
  1108. TQT_SLOT( slotSendNow() ) );
  1109. connect( actActionLaterMenu, TQT_SIGNAL( activated() ), this,
  1110. TQT_SLOT( slotSendLater() ) );
  1111. mActNowMenu = actActionNowMenu->popupMenu();
  1112. mActLaterMenu = actActionLaterMenu->popupMenu();
  1113. connect( mActNowMenu, TQT_SIGNAL( activated( int ) ), this,
  1114. TQT_SLOT( slotSendNowVia( int ) ) );
  1115. connect( mActNowMenu, TQT_SIGNAL( aboutToShow() ), this,
  1116. TQT_SLOT( getTransportMenu() ) );
  1117. connect( mActLaterMenu, TQT_SIGNAL( activated( int ) ), this,
  1118. TQT_SLOT( slotSendLaterVia( int ) ) );
  1119. connect( mActLaterMenu, TQT_SIGNAL( aboutToShow() ), this,
  1120. TQT_SLOT( getTransportMenu() ) );
  1121. (void) new TDEAction (i18n("Save as &Draft"), "filesave", 0,
  1122. TQT_TQOBJECT(this), TQT_SLOT(slotSaveDraft()),
  1123. actionCollection(), "save_in_drafts");
  1124. (void) new TDEAction (i18n("Save as &Template"), "filesave", 0,
  1125. TQT_TQOBJECT(this), TQT_SLOT(slotSaveTemplate()),
  1126. actionCollection(), "save_in_templates");
  1127. (void) new TDEAction (i18n("&Insert File..."), "fileopen", 0,
  1128. TQT_TQOBJECT(this), TQT_SLOT(slotInsertFile()),
  1129. actionCollection(), "insert_file");
  1130. mRecentAction = new TDERecentFilesAction (i18n("&Insert File Recent"),
  1131. "fileopen", 0,
  1132. TQT_TQOBJECT(this), TQT_SLOT(slotInsertRecentFile(const KURL&)),
  1133. actionCollection(), "insert_file_recent");
  1134. mRecentAction->loadEntries( KMKernel::config() );
  1135. (void) new TDEAction (i18n("&Address Book"), "contents",0,
  1136. TQT_TQOBJECT(this), TQT_SLOT(slotAddrBook()),
  1137. actionCollection(), "addressbook");
  1138. (void) new TDEAction (i18n("&New Composer"), "mail_new",
  1139. TDEStdAccel::shortcut(TDEStdAccel::New),
  1140. TQT_TQOBJECT(this), TQT_SLOT(slotNewComposer()),
  1141. actionCollection(), "new_composer");
  1142. (void) new TDEAction (i18n("New Main &Window"), "window_new", 0,
  1143. TQT_TQOBJECT(this), TQT_SLOT(slotNewMailReader()),
  1144. actionCollection(), "open_mailreader");
  1145. if ( !mClassicalRecipients ) {
  1146. new TDEAction( i18n("Select &Recipients..."), CTRL + Key_L, TQT_TQOBJECT(mRecipientsEditor),
  1147. TQT_SLOT( selectRecipients() ), actionCollection(), "select_recipients" );
  1148. new TDEAction( i18n("Save &Distribution List..."), 0, TQT_TQOBJECT(mRecipientsEditor),
  1149. TQT_SLOT( saveDistributionList() ), actionCollection(),
  1150. "save_distribution_list" );
  1151. }
  1152. //KStdAction::save(TQT_TQOBJECT(this), TQT_SLOT(), actionCollection(), "save_message");
  1153. KStdAction::print (TQT_TQOBJECT(this), TQT_SLOT(slotPrint()), actionCollection());
  1154. KStdAction::close (TQT_TQOBJECT(this), TQT_SLOT(slotClose()), actionCollection());
  1155. KStdAction::undo (TQT_TQOBJECT(this), TQT_SLOT(slotUndo()), actionCollection());
  1156. KStdAction::redo (TQT_TQOBJECT(this), TQT_SLOT(slotRedo()), actionCollection());
  1157. KStdAction::cut (TQT_TQOBJECT(this), TQT_SLOT(slotCut()), actionCollection());
  1158. KStdAction::copy (TQT_TQOBJECT(this), TQT_SLOT(slotCopy()), actionCollection());
  1159. KStdAction::pasteText (TQT_TQOBJECT(this), TQT_SLOT(slotPasteClipboard()), actionCollection());
  1160. KStdAction::selectAll (TQT_TQOBJECT(this), TQT_SLOT(slotMarkAll()), actionCollection());
  1161. KStdAction::find (TQT_TQOBJECT(this), TQT_SLOT(slotFind()), actionCollection());
  1162. KStdAction::findNext(TQT_TQOBJECT(this), TQT_SLOT(slotSearchAgain()), actionCollection());
  1163. KStdAction::replace (TQT_TQOBJECT(this), TQT_SLOT(slotReplace()), actionCollection());
  1164. KStdAction::spelling (TQT_TQOBJECT(this), TQT_SLOT(slotSpellcheck()), actionCollection(), "spellcheck");
  1165. mPasteQuotation = new TDEAction (i18n("Pa&ste as Quotation"),0,TQT_TQOBJECT(this),TQT_SLOT( slotPasteClipboardAsQuotation()),
  1166. actionCollection(), "paste_quoted");
  1167. (void) new TDEAction (i18n("Paste as Attac&hment"),0,TQT_TQOBJECT(this),TQT_SLOT( slotPasteClipboardAsAttachment()),
  1168. actionCollection(), "paste_att");
  1169. TDEAction * addq = new TDEAction(i18n("Add &Quote Characters"), 0, TQT_TQOBJECT(this),
  1170. TQT_SLOT(slotAddQuotes()), actionCollection(), "tools_quote");
  1171. connect( mEditor, TQT_SIGNAL(selectionAvailable(bool)),
  1172. addq, TQT_SLOT(setEnabled(bool)) );
  1173. TDEAction * remq = new TDEAction(i18n("Re&move Quote Characters"), 0, TQT_TQOBJECT(this),
  1174. TQT_SLOT(slotRemoveQuotes()), actionCollection(), "tools_unquote");
  1175. connect( mEditor, TQT_SIGNAL(selectionAvailable(bool)),
  1176. remq, TQT_SLOT(setEnabled(bool)) );
  1177. (void) new TDEAction (i18n("Cl&ean Spaces"), 0, TQT_TQOBJECT(this), TQT_SLOT(slotCleanSpace()),
  1178. actionCollection(), "clean_spaces");
  1179. mFixedFontAction = new TDEToggleAction( i18n("Use Fi&xed Font"), 0, TQT_TQOBJECT(this),
  1180. TQT_SLOT(slotUpdateFont()), actionCollection(), "toggle_fixedfont" );
  1181. mFixedFontAction->setChecked( GlobalSettings::self()->useFixedFont() );
  1182. //these are checkable!!!
  1183. mUrgentAction = new TDEToggleAction (i18n("&Urgent"), 0,
  1184. actionCollection(),
  1185. "urgent");
  1186. mRequestMDNAction = new TDEToggleAction ( i18n("&Request Disposition Notification"), 0,
  1187. actionCollection(),
  1188. "options_request_mdn");
  1189. mRequestMDNAction->setChecked(GlobalSettings::self()->requestMDN());
  1190. //----- Message-Encoding Submenu
  1191. mEncodingAction = new TDESelectAction( i18n( "Se&t Encoding" ), "charset",
  1192. 0, TQT_TQOBJECT(this), TQT_SLOT(slotSetCharset() ),
  1193. actionCollection(), "charsets" );
  1194. mWordWrapAction = new TDEToggleAction (i18n("&Wordwrap"), 0,
  1195. actionCollection(), "wordwrap");
  1196. mWordWrapAction->setChecked(GlobalSettings::self()->wordWrap());
  1197. connect(mWordWrapAction, TQT_SIGNAL(toggled(bool)), TQT_SLOT(slotWordWrapToggled(bool)));
  1198. mSnippetAction = new TDEToggleAction ( i18n("&Snippets"), 0,
  1199. actionCollection(), "snippets");
  1200. connect(mSnippetAction, TQT_SIGNAL(toggled(bool)), mSnippetWidget, TQT_SLOT(setShown(bool)) );
  1201. mSnippetAction->setChecked( GlobalSettings::self()->showSnippetManager() );
  1202. mAutoSpellCheckingAction =
  1203. new TDEToggleAction( i18n( "&Automatic Spellchecking" ), "spellcheck", 0,
  1204. actionCollection(), "options_auto_spellchecking" );
  1205. const bool spellChecking = GlobalSettings::self()->autoSpellChecking();
  1206. mAutoSpellCheckingAction->setEnabled( !GlobalSettings::self()->useExternalEditor() );
  1207. mAutoSpellCheckingAction->setChecked( !GlobalSettings::self()->useExternalEditor() && spellChecking );
  1208. slotAutoSpellCheckingToggled( !GlobalSettings::self()->useExternalEditor() && spellChecking );
  1209. connect( mAutoSpellCheckingAction, TQT_SIGNAL( toggled( bool ) ),
  1210. TQT_TQOBJECT(this), TQT_SLOT( slotAutoSpellCheckingToggled( bool ) ) );
  1211. TQStringList encodings = KMMsgBase::supportedEncodings(true);
  1212. encodings.prepend( i18n("Auto-Detect"));
  1213. mEncodingAction->setItems( encodings );
  1214. mEncodingAction->setCurrentItem( -1 );
  1215. //these are checkable!!!
  1216. markupAction = new TDEToggleAction (i18n("Formatting (HTML)"), 0, TQT_TQOBJECT(this),
  1217. TQT_SLOT(slotToggleMarkup()),
  1218. actionCollection(), "html");
  1219. mAllFieldsAction = new TDEToggleAction (i18n("&All Fields"), 0, TQT_TQOBJECT(this),
  1220. TQT_SLOT(slotView()),
  1221. actionCollection(), "show_all_fields");
  1222. mIdentityAction = new TDEToggleAction (i18n("&Identity"), 0, TQT_TQOBJECT(this),
  1223. TQT_SLOT(slotView()),
  1224. actionCollection(), "show_identity");
  1225. mDictionaryAction = new TDEToggleAction (i18n("&Dictionary"), 0, TQT_TQOBJECT(this),
  1226. TQT_SLOT(slotView()),
  1227. actionCollection(), "show_dictionary");
  1228. mFccAction = new TDEToggleAction (i18n("&Sent-Mail Folder"), 0, TQT_TQOBJECT(this),
  1229. TQT_SLOT(slotView()),
  1230. actionCollection(), "show_fcc");
  1231. mTransportAction = new TDEToggleAction (i18n("&Mail Transport"), 0, TQT_TQOBJECT(this),
  1232. TQT_SLOT(slotView()),
  1233. actionCollection(), "show_transport");
  1234. mFromAction = new TDEToggleAction (i18n("&From"), 0, TQT_TQOBJECT(this),
  1235. TQT_SLOT(slotView()),
  1236. actionCollection(), "show_from");
  1237. mReplyToAction = new TDEToggleAction (i18n("&Reply To"), 0, TQT_TQOBJECT(this),
  1238. TQT_SLOT(slotView()),
  1239. actionCollection(), "show_reply_to");
  1240. if ( mClassicalRecipients ) {
  1241. mToAction = new TDEToggleAction (i18n("&To"), 0, TQT_TQOBJECT(this),
  1242. TQT_SLOT(slotView()),
  1243. actionCollection(), "show_to");
  1244. mCcAction = new TDEToggleAction (i18n("&CC"), 0, TQT_TQOBJECT(this),
  1245. TQT_SLOT(slotView()),
  1246. actionCollection(), "show_cc");
  1247. mBccAction = new TDEToggleAction (i18n("&BCC"), 0, TQT_TQOBJECT(this),
  1248. TQT_SLOT(slotView()),
  1249. actionCollection(), "show_bcc");
  1250. }
  1251. mSubjectAction = new TDEToggleAction (i18n("S&ubject"), 0, TQT_TQOBJECT(this),
  1252. TQT_SLOT(slotView()),
  1253. actionCollection(), "show_subject");
  1254. //end of checkable
  1255. mAppendSignatureAction = new TDEAction (i18n("Append S&ignature"), 0, TQT_TQOBJECT(this),
  1256. TQT_SLOT(slotAppendSignature()),
  1257. actionCollection(), "append_signature");
  1258. mPrependSignatureAction = new TDEAction (i18n("Prepend S&ignature"), 0, TQT_TQOBJECT(this),
  1259. TQT_SLOT(slotPrependSignature()),
  1260. actionCollection(), "prepend_signature");
  1261. mInsertSignatureAction = new TDEAction (i18n("Insert Signature At C&ursor Position"), "edit", 0, TQT_TQOBJECT(this),
  1262. TQT_SLOT(slotInsertSignatureAtCursor()),
  1263. actionCollection(), "insert_signature_at_cursor_position");
  1264. mAttachPK = new TDEAction (i18n("Attach &Public Key..."), 0, TQT_TQOBJECT(this),
  1265. TQT_SLOT(slotInsertPublicKey()),
  1266. actionCollection(), "attach_public_key");
  1267. mAttachMPK = new TDEAction (i18n("Attach &My Public Key"), 0, TQT_TQOBJECT(this),
  1268. TQT_SLOT(slotInsertMyPublicKey()),
  1269. actionCollection(), "attach_my_public_key");
  1270. (void) new TDEAction (i18n("&Attach File..."), "attach",
  1271. 0, TQT_TQOBJECT(this), TQT_SLOT(slotAttachFile()),
  1272. actionCollection(), "attach");
  1273. mAttachRemoveAction = new TDEAction (i18n("&Remove Attachment"), 0, TQT_TQOBJECT(this),
  1274. TQT_SLOT(slotAttachRemove()),
  1275. actionCollection(), "remove");
  1276. mAttachSaveAction = new TDEAction (i18n("&Save Attachment As..."), "filesave",0,
  1277. TQT_TQOBJECT(this), TQT_SLOT(slotAttachSave()),
  1278. actionCollection(), "attach_save");
  1279. mAttachPropertiesAction = new TDEAction (i18n("Attachment Pr&operties"), 0, TQT_TQOBJECT(this),
  1280. TQT_SLOT(slotAttachProperties()),
  1281. actionCollection(), "attach_properties");
  1282. setStandardToolBarMenuEnabled(true);
  1283. KStdAction::keyBindings(TQT_TQOBJECT(this), TQT_SLOT(slotEditKeys()), actionCollection());
  1284. KStdAction::configureToolbars(TQT_TQOBJECT(this), TQT_SLOT(slotEditToolbars()), actionCollection());
  1285. KStdAction::preferences(kmkernel, TQT_SLOT(slotShowConfigurationDialog()), actionCollection());
  1286. (void) new TDEAction (i18n("&Spellchecker..."), 0, TQT_TQOBJECT(this), TQT_SLOT(slotSpellcheckConfig()),
  1287. actionCollection(), "setup_spellchecker");
  1288. if ( Kleo::CryptoBackendFactory::instance()->protocol( "Chiasmus" ) ) {
  1289. TDEToggleAction * a = new TDEToggleAction( i18n( "Encrypt Message with Chiasmus..." ),
  1290. "chidecrypted", 0, actionCollection(),
  1291. "encrypt_message_chiasmus" );
  1292. a->setCheckedState( KGuiItem( i18n( "Encrypt Message with Chiasmus..." ), "chiencrypted" ) );
  1293. mEncryptChiasmusAction = a;
  1294. connect( mEncryptChiasmusAction, TQT_SIGNAL(toggled(bool)),
  1295. TQT_TQOBJECT(this), TQT_SLOT(slotEncryptChiasmusToggled(bool)) );
  1296. } else {
  1297. mEncryptChiasmusAction = 0;
  1298. }
  1299. mEncryptAction = new TDEToggleAction (i18n("&Encrypt Message"),
  1300. "decrypted", 0,
  1301. actionCollection(), "encrypt_message");
  1302. mSignAction = new TDEToggleAction (i18n("&Sign Message"),
  1303. "signature", 0,
  1304. actionCollection(), "sign_message");
  1305. // get PGP user id for the chosen identity
  1306. const KPIM::Identity & ident =
  1307. kmkernel->identityManager()->identityForUoidOrDefault( mIdentity->currentIdentity() );
  1308. // PENDING(marc): check the uses of this member and split it into
  1309. // smime/openpgp and or enc/sign, if necessary:
  1310. mLastIdentityHasSigningKey = !ident.pgpSigningKey().isEmpty() || !ident.smimeSigningKey().isEmpty();
  1311. mLastIdentityHasEncryptionKey = !ident.pgpEncryptionKey().isEmpty() || !ident.smimeEncryptionKey().isEmpty();
  1312. mLastEncryptActionState = false;
  1313. mLastSignActionState = GlobalSettings::self()->pgpAutoSign();
  1314. // "Attach public key" is only possible if OpenPGP support is available:
  1315. mAttachPK->setEnabled( Kleo::CryptoBackendFactory::instance()->openpgp() );
  1316. // "Attach my public key" is only possible if OpenPGP support is
  1317. // available and the user specified his key for the current identity:
  1318. mAttachMPK->setEnabled( Kleo::CryptoBackendFactory::instance()->openpgp() &&
  1319. !ident.pgpEncryptionKey().isEmpty() );
  1320. if ( !Kleo::CryptoBackendFactory::instance()->openpgp() && !Kleo::CryptoBackendFactory::instance()->smime() ) {
  1321. // no crypto whatsoever
  1322. mEncryptAction->setEnabled( false );
  1323. setEncryption( false );
  1324. mSignAction->setEnabled( false );
  1325. setSigning( false );
  1326. } else {
  1327. const bool canOpenPGPSign = Kleo::CryptoBackendFactory::instance()->openpgp()
  1328. && !ident.pgpSigningKey().isEmpty();
  1329. const bool canSMIMESign = Kleo::CryptoBackendFactory::instance()->smime()
  1330. && !ident.smimeSigningKey().isEmpty();
  1331. setEncryption( false );
  1332. setSigning( ( canOpenPGPSign || canSMIMESign ) && GlobalSettings::self()->pgpAutoSign() );
  1333. }
  1334. connect(mEncryptAction, TQT_SIGNAL(toggled(bool)),
  1335. TQT_SLOT(slotEncryptToggled( bool )));
  1336. connect(mSignAction, TQT_SIGNAL(toggled(bool)),
  1337. TQT_SLOT(slotSignToggled( bool )));
  1338. TQStringList l;
  1339. for ( int i = 0 ; i < numCryptoMessageFormats ; ++i )
  1340. l.push_back( Kleo::cryptoMessageFormatToLabel( cryptoMessageFormats[i] ) );
  1341. mCryptoModuleAction = new TDESelectAction( i18n( "&Cryptographic Message Format" ), 0,
  1342. TQT_TQOBJECT(this), TQT_SLOT(slotSelectCryptoModule()),
  1343. actionCollection(), "options_select_crypto" );
  1344. mCryptoModuleAction->setItems( l );
  1345. mCryptoModuleAction->setCurrentItem( format2cb( ident.preferredCryptoMessageFormat() ) );
  1346. mCryptoModuleAction->setToolTip( i18n( "Select a cryptographic format for this message" ) );
  1347. slotSelectCryptoModule( true /* initialize */ );
  1348. TQStringList styleItems;
  1349. styleItems << i18n( "Standard" );
  1350. styleItems << i18n( "Bulleted List (Disc)" );
  1351. styleItems << i18n( "Bulleted List (Circle)" );
  1352. styleItems << i18n( "Bulleted List (Square)" );
  1353. styleItems << i18n( "Ordered List (Decimal)" );
  1354. styleItems << i18n( "Ordered List (Alpha lower)" );
  1355. styleItems << i18n( "Ordered List (Alpha upper)" );
  1356. listAction = new TDESelectAction( i18n( "Select Style" ), 0, actionCollection(),
  1357. "text_list" );
  1358. listAction->setItems( styleItems );
  1359. listAction->setToolTip( i18n( "Select a list style" ) );
  1360. connect( listAction, TQT_SIGNAL( activated( const TQString& ) ),
  1361. TQT_SLOT( slotListAction( const TQString& ) ) );
  1362. fontAction = new TDEFontAction( "Select Font", 0, actionCollection(),
  1363. "text_font" );
  1364. fontAction->setToolTip( i18n( "Select a font" ) );
  1365. connect( fontAction, TQT_SIGNAL( activated( const TQString& ) ),
  1366. TQT_SLOT( slotFontAction( const TQString& ) ) );
  1367. fontSizeAction = new TDEFontSizeAction( "Select Size", 0, actionCollection(),
  1368. "text_size" );
  1369. fontSizeAction->setToolTip( i18n( "Select a font size" ) );
  1370. connect( fontSizeAction, TQT_SIGNAL( fontSizeChanged( int ) ),
  1371. TQT_SLOT( slotSizeAction( int ) ) );
  1372. alignLeftAction = new TDEToggleAction (i18n("Align Left"), "text_left", 0,
  1373. TQT_TQOBJECT(this), TQT_SLOT(slotAlignLeft()), actionCollection(),
  1374. "align_left");
  1375. alignLeftAction->setChecked( true );
  1376. alignRightAction = new TDEToggleAction (i18n("Align Right"), "text_right", 0,
  1377. TQT_TQOBJECT(this), TQT_SLOT(slotAlignRight()), actionCollection(),
  1378. "align_right");
  1379. alignCenterAction = new TDEToggleAction (i18n("Align Center"), "text_center", 0,
  1380. TQT_TQOBJECT(this), TQT_SLOT(slotAlignCenter()), actionCollection(),
  1381. "align_center");
  1382. textBoldAction = new TDEToggleAction( i18n("&Bold"), "text_bold", CTRL+Key_B,
  1383. TQT_TQOBJECT(this), TQT_SLOT(slotTextBold()),
  1384. actionCollection(), "text_bold");
  1385. textItalicAction = new TDEToggleAction( i18n("&Italic"), "text_italic", CTRL+Key_I,
  1386. TQT_TQOBJECT(this), TQT_SLOT(slotTextItalic()),
  1387. actionCollection(), "text_italic");
  1388. textUnderAction = new TDEToggleAction( i18n("&Underline"), "text_under", CTRL+Key_U,
  1389. TQT_TQOBJECT(this), TQT_SLOT(slotTextUnder()),
  1390. actionCollection(), "text_under");
  1391. actionFormatReset = new TDEAction( i18n( "Reset Font Settings" ), "eraser", 0,
  1392. TQT_TQOBJECT(this), TQT_SLOT( slotFormatReset() ),
  1393. actionCollection(), "format_reset");
  1394. actionFormatColor = new TDEAction( i18n( "Text Color..." ), "colorize", 0,
  1395. TQT_TQOBJECT(this), TQT_SLOT( slotTextColor() ),
  1396. actionCollection(), "format_color");
  1397. // editorFocusChanged(false);
  1398. createGUI("kmcomposerui.rc");
  1399. connect( toolBar("htmlToolBar"), TQT_SIGNAL( visibilityChanged(bool) ),
  1400. TQT_TQOBJECT(this), TQT_SLOT( htmlToolBarVisibilityChanged(bool) ) );
  1401. // In Kontact, this entry would read "Configure Kontact", but bring
  1402. // up KMail's config dialog. That's sensible, though, so fix the label.
  1403. TDEAction* configureAction = actionCollection()->action("options_configure" );
  1404. if ( configureAction )
  1405. configureAction->setText( i18n("Configure KMail..." ) );
  1406. }
  1407. //-----------------------------------------------------------------------------
  1408. void KMComposeWin::setupStatusBar(void)
  1409. {
  1410. statusBar()->insertItem("", 0, 1);
  1411. statusBar()->setItemAlignment(0, AlignLeft | AlignVCenter);
  1412. statusBar()->insertItem(i18n( " Spellcheck: %1 ").arg( " " ), 3, 0, true );
  1413. statusBar()->insertItem(i18n( " Column: %1 ").arg(" "), 2, 0, true);
  1414. statusBar()->insertItem(i18n( " Line: %1 ").arg(" "), 1, 0, true);
  1415. }
  1416. //-----------------------------------------------------------------------------
  1417. void KMComposeWin::updateCursorPosition()
  1418. {
  1419. int col,line;
  1420. TQString temp;
  1421. line = mEditor->currentLine();
  1422. col = mEditor->currentColumn();
  1423. temp = i18n(" Line: %1 ").arg(line+1);
  1424. statusBar()->changeItem(temp,1);
  1425. temp = i18n(" Column: %1 ").arg(col+1);
  1426. statusBar()->changeItem(temp,2);
  1427. }
  1428. //-----------------------------------------------------------------------------
  1429. void KMComposeWin::setupEditor(void)
  1430. {
  1431. //TQPopupMenu* menu;
  1432. mEditor->setModified(false);
  1433. TQFontMetrics fm(mBodyFont);
  1434. mEditor->setTabStopWidth(fm.width(TQChar(' ')) * 8);
  1435. //mEditor->setFocusPolicy(TQWidget::ClickFocus);
  1436. slotWordWrapToggled( GlobalSettings::self()->wordWrap() );
  1437. // Font setup
  1438. slotUpdateFont();
  1439. /* installRBPopup() is broken in tdelibs, we should wait for
  1440. the new klibtextedit (dnaber, 2002-01-01)
  1441. menu = new TQPopupMenu(this);
  1442. //#ifdef BROKEN
  1443. menu->insertItem(i18n("Undo"),mEditor,
  1444. TQT_SLOT(undo()), TDEStdAccel::shortcut(TDEStdAccel::Undo));
  1445. menu->insertItem(i18n("Redo"),mEditor,
  1446. TQT_SLOT(redo()), TDEStdAccel::shortcut(TDEStdAccel::Redo));
  1447. menu->insertSeparator();
  1448. //#endif //BROKEN
  1449. menu->insertItem(i18n("Cut"), this, TQT_SLOT(slotCut()));
  1450. menu->insertItem(i18n("Copy"), this, TQT_SLOT(slotCopy()));
  1451. menu->insertItem(i18n("Paste"), this, TQT_SLOT(slotPasteClipboard()));
  1452. menu->insertItem(i18n("Mark All"),this, TQT_SLOT(slotMarkAll()));
  1453. menu->insertSeparator();
  1454. menu->insertItem(i18n("Find..."), this, TQT_SLOT(slotFind()));
  1455. menu->insertItem(i18n("Replace..."), this, TQT_SLOT(slotReplace()));
  1456. menu->insertSeparator();
  1457. menu->insertItem(i18n("Fixed Font Widths"), this, TQT_SLOT(slotUpdateFont()));
  1458. mEditor->installRBPopup(menu);
  1459. */
  1460. updateCursorPosition();
  1461. connect(mEditor,TQT_SIGNAL(CursorPositionChanged()),TQT_SLOT(updateCursorPosition()));
  1462. connect( mEditor, TQT_SIGNAL( currentFontChanged( const TQFont & ) ),
  1463. TQT_TQOBJECT(this), TQT_SLOT( fontChanged( const TQFont & ) ) );
  1464. connect( mEditor, TQT_SIGNAL( currentAlignmentChanged( int ) ),
  1465. TQT_TQOBJECT(this), TQT_SLOT( alignmentChanged( int ) ) );
  1466. }
  1467. //-----------------------------------------------------------------------------
  1468. static TQString cleanedUpHeaderString( const TQString & s )
  1469. {
  1470. // remove invalid characters from the header strings
  1471. TQString res( s );
  1472. res.replace( '\r', "" );
  1473. res.replace( '\n', " " );
  1474. return res.stripWhiteSpace();
  1475. }
  1476. //-----------------------------------------------------------------------------
  1477. TQString KMComposeWin::subject() const
  1478. {
  1479. return cleanedUpHeaderString( mEdtSubject->text() );
  1480. }
  1481. //-----------------------------------------------------------------------------
  1482. TQString KMComposeWin::to() const
  1483. {
  1484. if ( mEdtTo ) {
  1485. return cleanedUpHeaderString( mEdtTo->text() );
  1486. } else if ( mRecipientsEditor ) {
  1487. return mRecipientsEditor->recipientString( Recipient::To );
  1488. } else {
  1489. return TQString();
  1490. }
  1491. }
  1492. //-----------------------------------------------------------------------------
  1493. TQString KMComposeWin::cc() const
  1494. {
  1495. if ( mEdtCc && !mEdtCc->isHidden() ) {
  1496. return cleanedUpHeaderString( mEdtCc->text() );
  1497. } else if ( mRecipientsEditor ) {
  1498. return mRecipientsEditor->recipientString( Recipient::Cc );
  1499. } else {
  1500. return TQString();
  1501. }
  1502. }
  1503. //-----------------------------------------------------------------------------
  1504. TQString KMComposeWin::bcc() const
  1505. {
  1506. if ( mEdtBcc && !mEdtBcc->isHidden() ) {
  1507. return cleanedUpHeaderString( mEdtBcc->text() );
  1508. } else if ( mRecipientsEditor ) {
  1509. return mRecipientsEditor->recipientString( Recipient::Bcc );
  1510. } else {
  1511. return TQString();
  1512. }
  1513. }
  1514. //-----------------------------------------------------------------------------
  1515. TQString KMComposeWin::from() const
  1516. {
  1517. return cleanedUpHeaderString( mEdtFrom->text() );
  1518. }
  1519. //-----------------------------------------------------------------------------
  1520. TQString KMComposeWin::replyTo() const
  1521. {
  1522. if ( mEdtReplyTo ) {
  1523. return cleanedUpHeaderString( mEdtReplyTo->text() );
  1524. } else {
  1525. return TQString();
  1526. }
  1527. }
  1528. //-----------------------------------------------------------------------------
  1529. void KMComposeWin::verifyWordWrapLengthIsAdequate(const TQString &body)
  1530. {
  1531. int maxLineLength = 0;
  1532. int curPos;
  1533. int oldPos = 0;
  1534. if (mEditor->TQTextEdit::wordWrap() == TQTextEdit::FixedColumnWidth) {
  1535. for (curPos = 0; curPos < (int)body.length(); ++curPos)
  1536. if (body[curPos] == '\n') {
  1537. if ((curPos - oldPos) > maxLineLength)
  1538. maxLineLength = curPos - oldPos;
  1539. oldPos = curPos;
  1540. }
  1541. if ((curPos - oldPos) > maxLineLength)
  1542. maxLineLength = curPos - oldPos;
  1543. if (mEditor->wrapColumnOrWidth() < maxLineLength) // column
  1544. mEditor->setWrapColumnOrWidth(maxLineLength);
  1545. }
  1546. }
  1547. //-----------------------------------------------------------------------------
  1548. void KMComposeWin::decryptOrStripOffCleartextSignature( TQCString& body )
  1549. {
  1550. TQPtrList<Kpgp::Block> pgpBlocks;
  1551. TQStrList nonPgpBlocks;
  1552. if( Kpgp::Module::prepareMessageForDecryption( body,
  1553. pgpBlocks, nonPgpBlocks ) )
  1554. {
  1555. // Only decrypt/strip off the signature if there is only one OpenPGP
  1556. // block in the message
  1557. if( pgpBlocks.count() == 1 )
  1558. {
  1559. Kpgp::Block* block = pgpBlocks.first();
  1560. if( ( block->type() == Kpgp::PgpMessageBlock ) ||
  1561. ( block->type() == Kpgp::ClearsignedBlock ) )
  1562. {
  1563. if( block->type() == Kpgp::PgpMessageBlock )
  1564. // try to decrypt this OpenPGP block
  1565. block->decrypt();
  1566. else
  1567. // strip off the signature
  1568. block->verify();
  1569. body = nonPgpBlocks.first()
  1570. + block->text()
  1571. + nonPgpBlocks.last();
  1572. }
  1573. }
  1574. }
  1575. }
  1576. //-----------------------------------------------------------------------------
  1577. void KMComposeWin::setTransport( const TQString & transport )
  1578. {
  1579. kdDebug(5006) << "KMComposeWin::setTransport( \"" << transport << "\" )" << endl;
  1580. // Don't change the transport combobox if transport is empty
  1581. if ( transport.isEmpty() )
  1582. return;
  1583. bool transportFound = false;
  1584. for ( int i = 0; i < mTransport->count(); ++i ) {
  1585. if ( mTransport->text(i) == transport ) {
  1586. transportFound = true;
  1587. mTransport->setCurrentItem(i);
  1588. kdDebug(5006) << "transport found, it's no. " << i << " in the list" << endl;
  1589. break;
  1590. }
  1591. }
  1592. if ( !transportFound ) { // unknown transport
  1593. kdDebug(5006) << "unknown transport \"" << transport << "\"" << endl;
  1594. if ( transport.startsWith("smtp://") || transport.startsWith("smtps://") ||
  1595. transport.startsWith("file://") ) {
  1596. // set custom transport
  1597. mTransport->setEditText( transport );
  1598. }
  1599. else {
  1600. // neither known nor custom transport -> use default transport
  1601. mTransport->setCurrentText( GlobalSettings::self()->defaultTransport() );
  1602. }
  1603. }
  1604. }
  1605. //-----------------------------------------------------------------------------
  1606. void KMComposeWin::setMsg(KMMessage* newMsg, bool mayAutoSign,
  1607. bool allowDecryption, bool isModified)
  1608. {
  1609. //assert(newMsg!=0);
  1610. if(!newMsg)
  1611. {
  1612. kdDebug(5006) << "KMComposeWin::setMsg() : newMsg == 0!" << endl;
  1613. return;
  1614. }
  1615. mMsg = newMsg;
  1616. KPIM::IdentityManager * im = kmkernel->identityManager();
  1617. mEdtFrom->setText(mMsg->from());
  1618. mEdtReplyTo->setText(mMsg->replyTo());
  1619. if ( mClassicalRecipients ) {
  1620. mEdtTo->setText(mMsg->to());
  1621. mEdtCc->setText(mMsg->cc());
  1622. mEdtBcc->setText(mMsg->bcc());
  1623. } else {
  1624. mRecipientsEditor->setRecipientString( mMsg->to(), Recipient::To );
  1625. mRecipientsEditor->setRecipientString( mMsg->cc(), Recipient::Cc );
  1626. mRecipientsEditor->setRecipientString( mMsg->bcc(), Recipient::Bcc );
  1627. mRecipientsEditor->setFocusBottom();
  1628. }
  1629. mEdtSubject->setText(mMsg->subject());
  1630. const bool stickyIdentity = mBtnIdentity->isChecked() && !mIgnoreStickyFields;
  1631. const bool messageHasIdentity = !newMsg->headerField("X-KMail-Identity").isEmpty();
  1632. if (!stickyIdentity && messageHasIdentity)
  1633. mId = newMsg->headerField("X-KMail-Identity").stripWhiteSpace().toUInt();
  1634. // don't overwrite the header values with identity specific values
  1635. // unless the identity is sticky
  1636. if ( !stickyIdentity ) {
  1637. disconnect(mIdentity,TQT_SIGNAL(identityChanged(uint)),
  1638. TQT_TQOBJECT(this), TQT_SLOT(slotIdentityChanged(uint)));
  1639. }
  1640. // load the mId into the gui, sticky or not, without emitting
  1641. mIdentity->setCurrentIdentity( mId );
  1642. const uint idToApply = mId;
  1643. if ( !stickyIdentity ) {
  1644. connect(mIdentity,TQT_SIGNAL(identityChanged(uint)),
  1645. TQT_TQOBJECT(this), TQT_SLOT(slotIdentityChanged(uint)));
  1646. } else {
  1647. // load the message's state into the mId, without applying it to the gui
  1648. // that's so we can detect that the id changed (because a sticky was set)
  1649. // on apply()
  1650. if ( messageHasIdentity )
  1651. mId = newMsg->headerField("X-KMail-Identity").stripWhiteSpace().toUInt();
  1652. else
  1653. mId = im->defaultIdentity().uoid();
  1654. }
  1655. // manually load the identity's value into the fields; either the one from the
  1656. // messge, where appropriate, or the one from the sticky identity. What's in
  1657. // mId might have changed meanwhile, thus the save value
  1658. slotIdentityChanged( idToApply );
  1659. const KPIM::Identity & ident = im->identityForUoid( mIdentity->currentIdentity() );
  1660. // check for the presence of a DNT header, indicating that MDN's were
  1661. // requested
  1662. TQString mdnAddr = newMsg->headerField("Disposition-Notification-To");
  1663. mRequestMDNAction->setChecked( ( !mdnAddr.isEmpty() &&
  1664. im->thatIsMe( mdnAddr ) ) ||
  1665. GlobalSettings::self()->requestMDN() );
  1666. // check for presence of a priority header, indicating urgent mail:
  1667. mUrgentAction->setChecked( newMsg->isUrgent() );
  1668. if (!ident.isXFaceEnabled() || ident.xface().isEmpty())
  1669. mMsg->removeHeaderField("X-Face");
  1670. else
  1671. {
  1672. TQString xface = ident.xface();
  1673. if (!xface.isEmpty())
  1674. {
  1675. int numNL = ( xface.length() - 1 ) / 70;
  1676. for ( int i = numNL; i > 0; --i )
  1677. xface.insert( i*70, "\n\t" );
  1678. mMsg->setHeaderField("X-Face", xface);
  1679. }
  1680. }
  1681. // enable/disable encryption if the message was/wasn't encrypted
  1682. switch ( mMsg->encryptionState() ) {
  1683. case KMMsgFullyEncrypted: // fall through
  1684. case KMMsgPartiallyEncrypted:
  1685. mLastEncryptActionState = true;
  1686. break;
  1687. case KMMsgNotEncrypted:
  1688. mLastEncryptActionState = false;
  1689. break;
  1690. default: // nothing
  1691. break;
  1692. }
  1693. // enable/disable signing if the message was/wasn't signed
  1694. switch ( mMsg->signatureState() ) {
  1695. case KMMsgFullySigned: // fall through
  1696. case KMMsgPartiallySigned:
  1697. mLastSignActionState = true;
  1698. break;
  1699. case KMMsgNotSigned:
  1700. mLastSignActionState = false;
  1701. break;
  1702. default: // nothing
  1703. break;
  1704. }
  1705. // if these headers are present, the state of the message should be overruled
  1706. if ( mMsg->headers().FindField( "X-KMail-SignatureActionEnabled" ) )
  1707. mLastSignActionState = (mMsg->headerField( "X-KMail-SignatureActionEnabled" ) == "true");
  1708. if ( mMsg->headers().FindField( "X-KMail-EncryptActionEnabled" ) )
  1709. mLastEncryptActionState = (mMsg->headerField( "X-KMail-EncryptActionEnabled" ) == "true");
  1710. if ( mMsg->headers().FindField( "X-KMail-CryptoMessageFormat" ) )
  1711. mCryptoModuleAction->setCurrentItem( format2cb( static_cast<Kleo::CryptoMessageFormat>(
  1712. mMsg->headerField( "X-KMail-CryptoMessageFormat" ).toInt() ) ) );
  1713. mLastIdentityHasSigningKey = !ident.pgpSigningKey().isEmpty() || !ident.smimeSigningKey().isEmpty();
  1714. mLastIdentityHasEncryptionKey = !ident.pgpEncryptionKey().isEmpty() || !ident.smimeEncryptionKey().isEmpty();
  1715. if ( Kleo::CryptoBackendFactory::instance()->openpgp() || Kleo::CryptoBackendFactory::instance()->smime() ) {
  1716. const bool canOpenPGPSign = Kleo::CryptoBackendFactory::instance()->openpgp()
  1717. && !ident.pgpSigningKey().isEmpty();
  1718. const bool canSMIMESign = Kleo::CryptoBackendFactory::instance()->smime()
  1719. && !ident.smimeSigningKey().isEmpty();
  1720. setEncryption( mLastEncryptActionState );
  1721. setSigning( ( canOpenPGPSign || canSMIMESign ) && mLastSignActionState );
  1722. }
  1723. slotUpdateSignatureAndEncrypionStateIndicators();
  1724. // "Attach my public key" is only possible if the user uses OpenPGP
  1725. // support and he specified his key:
  1726. mAttachMPK->setEnabled( Kleo::CryptoBackendFactory::instance()->openpgp() &&
  1727. !ident.pgpEncryptionKey().isEmpty() );
  1728. TQString transport = newMsg->headerField("X-KMail-Transport");
  1729. const bool stickyTransport = mBtnTransport->isChecked() && !mIgnoreStickyFields;
  1730. if (!stickyTransport && !transport.isEmpty()) {
  1731. setTransport( transport );
  1732. }
  1733. // If we are using the default transport, and the originating account name of the original message matches the name of a valid transport, use setTransport() to set it
  1734. // See Bug 1239
  1735. if (transport.isEmpty() && !mMsg->originatingAccountName().isEmpty()) {
  1736. TQString transportCandidate = mMsg->originatingAccountName();
  1737. bool transportFound = false;
  1738. for ( int i = 0; i < mTransport->count(); ++i ) {
  1739. if ( mTransport->text(i) == transportCandidate ) {
  1740. transportFound = true;
  1741. setTransport(transportCandidate);
  1742. break;
  1743. }
  1744. }
  1745. }
  1746. if (!mBtnFcc->isChecked())
  1747. {
  1748. if (!mMsg->fcc().isEmpty())
  1749. setFcc(mMsg->fcc());
  1750. else
  1751. setFcc(ident.fcc());
  1752. }
  1753. const bool stickyDictionary = mBtnDictionary->isChecked() && !mIgnoreStickyFields;
  1754. if ( !stickyDictionary ) {
  1755. mDictionaryCombo->setCurrentByDictionary( ident.dictionary() );
  1756. }
  1757. partNode * root = partNode::fromMessage( mMsg );
  1758. KMail::ObjectTreeParser otp; // all defaults are ok
  1759. otp.parseObjectTree( root );
  1760. KMail::AttachmentCollector ac;
  1761. ac.collectAttachmentsFrom( root );
  1762. for ( std::vector<partNode*>::const_iterator it = ac.attachments().begin() ; it != ac.attachments().end() ; ++it )
  1763. addAttach( new KMMessagePart( (*it)->msgPart() ) );
  1764. mEditor->setText( otp.textualContent() );
  1765. mCharset = otp.textualContentCharset();
  1766. if ( partNode * n = root->findType( DwMime::kTypeText, DwMime::kSubtypeHtml ) )
  1767. if ( partNode * p = n->parentNode() )
  1768. if ( p->hasType( DwMime::kTypeMultipart ) &&
  1769. p->hasSubType( DwMime::kSubtypeAlternative ) )
  1770. if ( mMsg->headerField( "X-KMail-Markup" ) == "true" ) {
  1771. toggleMarkup( true );
  1772. // get cte decoded body part
  1773. mCharset = n->msgPart().charset();
  1774. TQCString bodyDecoded = n->msgPart().bodyDecoded();
  1775. // respect html part charset
  1776. const TQTextCodec *codec = KMMsgBase::codecForName( mCharset );
  1777. if ( codec ) {
  1778. mEditor->setText( codec->toUnicode( bodyDecoded ) );
  1779. } else {
  1780. mEditor->setText( TQString::fromLocal8Bit( bodyDecoded ) );
  1781. }
  1782. }
  1783. if ( mCharset.isEmpty() )
  1784. mCharset = mMsg->charset();
  1785. if ( mCharset.isEmpty() )
  1786. mCharset = mDefCharset;
  1787. setCharset( mCharset );
  1788. /* Handle the special case of non-mime mails */
  1789. if ( mMsg->numBodyParts() == 0 && otp.textualContent().isEmpty() ) {
  1790. mCharset=mMsg->charset();
  1791. if ( mCharset.isEmpty() || mCharset == "default" )
  1792. mCharset = mDefCharset;
  1793. TQCString bodyDecoded = mMsg->bodyDecoded();
  1794. if( allowDecryption )
  1795. decryptOrStripOffCleartextSignature( bodyDecoded );
  1796. const TQTextCodec *codec = KMMsgBase::codecForName(mCharset);
  1797. if (codec) {
  1798. mEditor->setText(codec->toUnicode(bodyDecoded));
  1799. } else
  1800. mEditor->setText(TQString::fromLocal8Bit(bodyDecoded));
  1801. }
  1802. #ifdef BROKEN_FOR_OPAQUE_SIGNED_OR_ENCRYPTED_MAILS
  1803. const int num = mMsg->numBodyParts();
  1804. kdDebug(5006) << "KMComposeWin::setMsg() mMsg->numBodyParts="
  1805. << mMsg->numBodyParts() << endl;
  1806. if ( num > 0 ) {
  1807. KMMessagePart bodyPart;
  1808. int firstAttachment = 0;
  1809. mMsg->bodyPart(1, &bodyPart);
  1810. if ( bodyPart.typeStr().lower() == "text" &&
  1811. bodyPart.subtypeStr().lower() == "html" ) {
  1812. // check whether we are inside a mp/al body part
  1813. partNode *root = partNode::fromMessage( mMsg );
  1814. partNode *node = root->findType( DwMime::kTypeText,
  1815. DwMime::kSubtypeHtml );
  1816. if ( node && node->parentNode() &&
  1817. node->parentNode()->hasType( DwMime::kTypeMultipart ) &&
  1818. node->parentNode()->hasSubType( DwMime::kSubtypeAlternative ) ) {
  1819. // we have a mp/al body part with a text and an html body
  1820. kdDebug(5006) << "KMComposeWin::setMsg() : text/html found" << endl;
  1821. firstAttachment = 2;
  1822. if ( mMsg->headerField( "X-KMail-Markup" ) == "true" )
  1823. toggleMarkup( true );
  1824. }
  1825. delete root; root = 0;
  1826. }
  1827. if ( firstAttachment == 0 ) {
  1828. mMsg->bodyPart(0, &bodyPart);
  1829. if ( bodyPart.typeStr().lower() == "text" ) {
  1830. // we have a mp/mx body with a text body
  1831. kdDebug(5006) << "KMComposeWin::setMsg() : text/* found" << endl;
  1832. firstAttachment = 1;
  1833. }
  1834. }
  1835. if ( firstAttachment != 0 ) // there's text to show
  1836. {
  1837. mCharset = bodyPart.charset();
  1838. if ( mCharset.isEmpty() || mCharset == "default" )
  1839. mCharset = mDefCharset;
  1840. TQCString bodyDecoded = bodyPart.bodyDecoded();
  1841. if( allowDecryption )
  1842. decryptOrStripOffCleartextSignature( bodyDecoded );
  1843. // As nobody seems to know the purpose of the following line and
  1844. // as it breaks word wrapping of long lines if drafts with attachments
  1845. // are opened for editting in the composer (cf. Bug#41102) I comment it
  1846. // out. Ingo, 2002-04-21
  1847. //verifyWordWrapLengthIsAdequate(bodyDecoded);
  1848. const TQTextCodec *codec = KMMsgBase::codecForName(mCharset);
  1849. if (codec)
  1850. mEditor->setText(codec->toUnicode(bodyDecoded));
  1851. else
  1852. mEditor->setText(TQString::fromLocal8Bit(bodyDecoded));
  1853. //mEditor->insertLine("\n", -1); <-- why ?
  1854. } else mEditor->setText("");
  1855. for( int i = firstAttachment; i < num; ++i )
  1856. {
  1857. KMMessagePart *msgPart = new KMMessagePart;
  1858. mMsg->bodyPart(i, msgPart);
  1859. TQCString mimeType = msgPart->typeStr().lower() + '/'
  1860. + msgPart->subtypeStr().lower();
  1861. // don't add the detached signature as attachment when editting a
  1862. // PGP/MIME signed message
  1863. if( mimeType != "application/pgp-signature" ) {
  1864. addAttach(msgPart);
  1865. }
  1866. }
  1867. } else{
  1868. mCharset=mMsg->charset();
  1869. if ( mCharset.isEmpty() || mCharset == "default" )
  1870. mCharset = mDefCharset;
  1871. TQCString bodyDecoded = mMsg->bodyDecoded();
  1872. if( allowDecryption )
  1873. decryptOrStripOffCleartextSignature( bodyDecoded );
  1874. const TQTextCodec *codec = KMMsgBase::codecForName(mCharset);
  1875. if (codec) {
  1876. mEditor->setText(codec->toUnicode(bodyDecoded));
  1877. } else
  1878. mEditor->setText(TQString::fromLocal8Bit(bodyDecoded));
  1879. }
  1880. setCharset(mCharset);
  1881. #endif // BROKEN_FOR_OPAQUE_SIGNED_OR_ENCRYPTED_MAILS
  1882. if( (GlobalSettings::self()->autoTextSignature()=="auto") && mayAutoSign ) {
  1883. //
  1884. // Espen 2000-05-16
  1885. // Delay the signature appending. It may start a fileseletor.
  1886. // Not user friendy if this modal fileseletor opens before the
  1887. // composer.
  1888. //
  1889. //TQTimer::singleShot( 200, this, TQT_SLOT(slotAppendSignature()) );
  1890. if ( GlobalSettings::self()->prependSignature() ) {
  1891. TQTimer::singleShot( 0, this, TQT_SLOT(slotPrependSignature()) );
  1892. } else {
  1893. TQTimer::singleShot( 0, this, TQT_SLOT(slotAppendSignature()) );
  1894. }
  1895. }
  1896. if ( mMsg->getCursorPos() > 0 ) {
  1897. // The message has a cursor position explicitly set, so avoid
  1898. // changing it when appending the signature.
  1899. mPreserveUserCursorPosition = true;
  1900. }
  1901. setModified( isModified );
  1902. // do this even for new messages
  1903. mEditor->setCursorPositionFromStart( (unsigned int) mMsg->getCursorPos() );
  1904. // honor "keep reply in this folder" setting even when the identity is changed later on
  1905. mPreventFccOverwrite = ( !newMsg->fcc().isEmpty() && ident.fcc() != newMsg->fcc() );
  1906. }
  1907. //-----------------------------------------------------------------------------
  1908. void KMComposeWin::setFcc( const TQString &idString )
  1909. {
  1910. // check if the sent-mail folder still exists
  1911. if ( ! idString.isEmpty() && kmkernel->findFolderById( idString ) ) {
  1912. mFcc->setFolder( idString );
  1913. } else {
  1914. mFcc->setFolder( kmkernel->sentFolder() );
  1915. }
  1916. }
  1917. //-----------------------------------------------------------------------------
  1918. bool KMComposeWin::isModified() const
  1919. {
  1920. return ( mEditor->isModified() ||
  1921. mEdtFrom->edited() ||
  1922. ( mEdtReplyTo && mEdtReplyTo->edited() ) ||
  1923. ( mEdtTo && mEdtTo->edited() ) ||
  1924. ( mEdtCc && mEdtCc->edited() ) ||
  1925. ( mEdtBcc && mEdtBcc->edited() ) ||
  1926. ( mRecipientsEditor && mRecipientsEditor->isModified() ) ||
  1927. mEdtSubject->edited() ||
  1928. mAtmModified ||
  1929. ( mTransport->lineEdit() && mTransport->lineEdit()->edited() ) );
  1930. }
  1931. //-----------------------------------------------------------------------------
  1932. void KMComposeWin::setModified( bool modified )
  1933. {
  1934. mEditor->setModified( modified );
  1935. if ( !modified ) {
  1936. mEdtFrom->setEdited( false );
  1937. if ( mEdtReplyTo ) mEdtReplyTo->setEdited( false );
  1938. if ( mEdtTo ) mEdtTo->setEdited( false );
  1939. if ( mEdtCc ) mEdtCc->setEdited( false );
  1940. if ( mEdtBcc ) mEdtBcc->setEdited( false );
  1941. if ( mRecipientsEditor ) mRecipientsEditor->clearModified();
  1942. mEdtSubject->setEdited( false );
  1943. mAtmModified = false ;
  1944. if ( mTransport->lineEdit() )
  1945. mTransport->lineEdit()->setEdited( false );
  1946. }
  1947. }
  1948. //-----------------------------------------------------------------------------
  1949. bool KMComposeWin::queryClose ()
  1950. {
  1951. if ( !mEditor->checkExternalEditorFinished() )
  1952. return false;
  1953. if ( kmkernel->shuttingDown() || kapp->sessionSaving() )
  1954. return true;
  1955. if ( mComposer && mComposer->isPerformingSignOperation() ) // since the non-gpg-agent gpg plugin gets a passphrase using TQDialog::exec()
  1956. return false; // the user can try to close the window, which destroys mComposer mid-call.
  1957. if ( isModified() ) {
  1958. bool istemplate = ( mFolder!=0 && mFolder->isTemplates() );
  1959. const TQString savebut = ( istemplate ?
  1960. i18n("Re&save as Template") :
  1961. i18n("&Save as Draft") );
  1962. const TQString savetext = ( istemplate ?
  1963. i18n("Resave this message in the Templates folder. "
  1964. "It can then be used at a later time.") :
  1965. i18n("Save this message in the Drafts folder. "
  1966. "It can then be edited and sent at a later time.") );
  1967. const int rc = KMessageBox::warningYesNoCancel( this,
  1968. i18n("Do you want to save the message for later or discard it?"),
  1969. i18n("Close Composer"),
  1970. KGuiItem(savebut, "filesave", TQString(), savetext),
  1971. KStdGuiItem::discard() );
  1972. if ( rc == KMessageBox::Cancel )
  1973. return false;
  1974. else if ( rc == KMessageBox::Yes ) {
  1975. // doSend will close the window. Just return false from this method
  1976. if ( istemplate ) {
  1977. slotSaveTemplate();
  1978. } else {
  1979. slotSaveDraft();
  1980. }
  1981. return false;
  1982. }
  1983. }
  1984. cleanupAutoSave();
  1985. return true;
  1986. }
  1987. //-----------------------------------------------------------------------------
  1988. bool KMComposeWin::userForgotAttachment()
  1989. {
  1990. bool checkForForgottenAttachments =
  1991. mCheckForForgottenAttachments && GlobalSettings::self()->showForgottenAttachmentWarning();
  1992. if ( !checkForForgottenAttachments || ( mAtmList.count() > 0 ) )
  1993. return false;
  1994. TQStringList attachWordsList = GlobalSettings::self()->attachmentKeywords();
  1995. if ( attachWordsList.isEmpty() ) {
  1996. // default value (FIXME: this is duplicated in configuredialog.cpp)
  1997. attachWordsList << TQString::fromLatin1("attachment")
  1998. << TQString::fromLatin1("attached");
  1999. if ( TQString::fromLatin1("attachment") != i18n("attachment") )
  2000. attachWordsList << i18n("attachment");
  2001. if ( TQString::fromLatin1("attached") != i18n("attached") )
  2002. attachWordsList << i18n("attached");
  2003. }
  2004. TQRegExp rx ( TQString::fromLatin1("\\b") +
  2005. attachWordsList.join("\\b|\\b") +
  2006. TQString::fromLatin1("\\b") );
  2007. rx.setCaseSensitive( false );
  2008. bool gotMatch = false;
  2009. // check whether the subject contains one of the attachment key words
  2010. // unless the message is a reply or a forwarded message
  2011. TQString subj = subject();
  2012. gotMatch = ( KMMessage::stripOffPrefixes( subj ) == subj )
  2013. && ( rx.search( subj ) >= 0 );
  2014. if ( !gotMatch ) {
  2015. // check whether the non-quoted text contains one of the attachment key
  2016. // words
  2017. TQRegExp quotationRx ("^([ \\t]*([|>:}#]|[A-Za-z]+>))+");
  2018. for ( int i = 0; i < mEditor->numLines(); ++i ) {
  2019. TQString line = mEditor->textLine( i );
  2020. gotMatch = ( quotationRx.search( line ) < 0 )
  2021. && ( rx.search( line ) >= 0 );
  2022. if ( gotMatch )
  2023. break;
  2024. }
  2025. }
  2026. if ( !gotMatch )
  2027. return false;
  2028. int rc = KMessageBox::warningYesNoCancel( this,
  2029. i18n("The message you have composed seems to refer to an "
  2030. "attached file but you have not attached anything.\n"
  2031. "Do you want to attach a file to your message?"),
  2032. i18n("File Attachment Reminder"),
  2033. i18n("&Attach File..."),
  2034. i18n("&Send as Is") );
  2035. if ( rc == KMessageBox::Cancel )
  2036. return true;
  2037. if ( rc == KMessageBox::Yes ) {
  2038. slotAttachFile();
  2039. //preceed with editing
  2040. return true;
  2041. }
  2042. return false;
  2043. }
  2044. //-----------------------------------------------------------------------------
  2045. void KMComposeWin::applyChanges( bool dontSignNorEncrypt, bool dontDisable )
  2046. {
  2047. kdDebug(5006) << "entering KMComposeWin::applyChanges" << endl;
  2048. if(!mMsg || mComposer) {
  2049. kdDebug(5006) << "KMComposeWin::applyChanges() : mMsg == 0!\n" << endl;
  2050. emit applyChangesDone( false );
  2051. return;
  2052. }
  2053. // Make new job and execute it
  2054. mComposer = new MessageComposer( this );
  2055. connect( mComposer, TQT_SIGNAL( done( bool ) ),
  2056. TQT_TQOBJECT(this), TQT_SLOT( slotComposerDone( bool ) ) );
  2057. // TODO: Add a cancel button for the following operations?
  2058. // Disable any input to the window, so that we have a snapshot of the
  2059. // composed stuff
  2060. if ( !dontDisable ) setEnabled( false );
  2061. // apply the current state to the composer and let it do it's thing
  2062. mComposer->setDisableBreaking( mDisableBreaking ); // FIXME
  2063. mComposer->applyChanges( dontSignNorEncrypt );
  2064. }
  2065. void KMComposeWin::slotComposerDone( bool rc )
  2066. {
  2067. deleteAll( mComposedMessages );
  2068. mComposedMessages = mComposer->composedMessageList();
  2069. emit applyChangesDone( rc );
  2070. delete mComposer;
  2071. mComposer = 0;
  2072. // re-enable the composewin, the messsage composition is now done
  2073. setEnabled( true );
  2074. }
  2075. const KPIM::Identity & KMComposeWin::identity() const {
  2076. return kmkernel->identityManager()->identityForUoidOrDefault( mIdentity->currentIdentity() );
  2077. }
  2078. uint KMComposeWin::identityUid() const {
  2079. return mIdentity->currentIdentity();
  2080. }
  2081. Kleo::CryptoMessageFormat KMComposeWin::cryptoMessageFormat() const {
  2082. if ( !mCryptoModuleAction )
  2083. return Kleo::AutoFormat;
  2084. return cb2format( mCryptoModuleAction->currentItem() );
  2085. }
  2086. bool KMComposeWin::encryptToSelf() const {
  2087. // return !Kpgp::Module::getKpgp() || Kpgp::Module::getKpgp()->encryptToSelf();
  2088. TDEConfigGroup group( KMKernel::config(), "Composer" );
  2089. return group.readBoolEntry( "crypto-encrypt-to-self", true );
  2090. }
  2091. bool KMComposeWin::queryExit ()
  2092. {
  2093. return true;
  2094. }
  2095. //-----------------------------------------------------------------------------
  2096. bool KMComposeWin::addAttach(const KURL aUrl)
  2097. {
  2098. if ( !aUrl.isValid() ) {
  2099. KMessageBox::sorry( this, i18n( "<qt><p>KMail could not recognize the location of the attachment (%1);</p>"
  2100. "<p>you have to specify the full path if you wish to attach a file.</p></qt>" )
  2101. .arg( aUrl.prettyURL() ) );
  2102. return false;
  2103. }
  2104. const int maxAttachmentSize = GlobalSettings::maximumAttachmentSize();
  2105. const uint maximumAttachmentSizeInByte = maxAttachmentSize*1024*1024;
  2106. if ( aUrl.isLocalFile() && TQFileInfo( aUrl.pathOrURL() ).size() > maximumAttachmentSizeInByte ) {
  2107. KMessageBox::sorry( this, i18n( "<qt><p>Your administrator has disallowed attaching files bigger than %1 MB.</p>" ).arg( maxAttachmentSize ) );
  2108. return false;
  2109. }
  2110. TDEIO::TransferJob *job = TDEIO::get(aUrl);
  2111. TDEIO::Scheduler::scheduleJob( job );
  2112. atmLoadData ld;
  2113. ld.url = aUrl;
  2114. ld.data = TQByteArray();
  2115. ld.insert = false;
  2116. if( !aUrl.fileEncoding().isEmpty() )
  2117. ld.encoding = aUrl.fileEncoding().latin1();
  2118. mMapAtmLoadData.insert(job, ld);
  2119. mAttachJobs[job] = aUrl;
  2120. connect(job, TQT_SIGNAL(result(TDEIO::Job *)),
  2121. TQT_TQOBJECT(this), TQT_SLOT(slotAttachFileResult(TDEIO::Job *)));
  2122. connect(job, TQT_SIGNAL(data(TDEIO::Job *, const TQByteArray &)),
  2123. TQT_TQOBJECT(this), TQT_SLOT(slotAttachFileData(TDEIO::Job *, const TQByteArray &)));
  2124. return true;
  2125. }
  2126. //-----------------------------------------------------------------------------
  2127. void KMComposeWin::addAttach(const KMMessagePart* msgPart)
  2128. {
  2129. mAtmList.append(msgPart);
  2130. // show the attachment listbox if it does not up to now
  2131. if (mAtmList.count()==1)
  2132. {
  2133. mAtmListView->resize(mAtmListView->width(), 50);
  2134. mAtmListView->show();
  2135. resize(size());
  2136. }
  2137. // add a line in the attachment listbox
  2138. KMAtmListViewItem *lvi = new KMAtmListViewItem( mAtmListView );
  2139. msgPartToItem(msgPart, lvi);
  2140. mAtmItemList.append(lvi);
  2141. // the Attach file job has finished, so the possibly present tmp dir can be deleted now.
  2142. if ( mTempDir != 0 ) {
  2143. delete mTempDir;
  2144. mTempDir = 0;
  2145. }
  2146. connect( lvi, TQT_SIGNAL( compress( int ) ),
  2147. TQT_TQOBJECT(this), TQT_SLOT( compressAttach( int ) ) );
  2148. connect( lvi, TQT_SIGNAL( uncompress( int ) ),
  2149. TQT_TQOBJECT(this), TQT_SLOT( uncompressAttach( int ) ) );
  2150. slotUpdateAttachActions();
  2151. }
  2152. //-----------------------------------------------------------------------------
  2153. void KMComposeWin::slotUpdateAttachActions()
  2154. {
  2155. int selectedCount = 0;
  2156. for ( TQPtrListIterator<TQListViewItem> it(mAtmItemList); *it; ++it ) {
  2157. if ( (*it)->isSelected() ) {
  2158. ++selectedCount;
  2159. }
  2160. }
  2161. mAttachRemoveAction->setEnabled( selectedCount >= 1 );
  2162. mAttachSaveAction->setEnabled( selectedCount == 1 );
  2163. mAttachPropertiesAction->setEnabled( selectedCount == 1 );
  2164. }
  2165. //-----------------------------------------------------------------------------
  2166. TQString KMComposeWin::prettyMimeType( const TQString& type )
  2167. {
  2168. TQString t = type.lower();
  2169. KServiceType::Ptr st = KServiceType::serviceType( t );
  2170. return st ? st->comment() : t;
  2171. }
  2172. void KMComposeWin::msgPartToItem(const KMMessagePart* msgPart,
  2173. KMAtmListViewItem *lvi, bool loadDefaults)
  2174. {
  2175. assert(msgPart != 0);
  2176. if (!msgPart->fileName().isEmpty())
  2177. lvi->setText(0, msgPart->fileName());
  2178. else
  2179. lvi->setText(0, msgPart->name());
  2180. lvi->setText(1, TDEIO::convertSize( msgPart->decodedSize()));
  2181. lvi->setText(2, msgPart->contentTransferEncodingStr());
  2182. lvi->setText(3, prettyMimeType(msgPart->typeStr() + "/" + msgPart->subtypeStr()));
  2183. lvi->setAttachmentSize(msgPart->decodedSize());
  2184. if ( loadDefaults ) {
  2185. if( canSignEncryptAttachments() ) {
  2186. lvi->enableCryptoCBs( true );
  2187. lvi->setEncrypt( mEncryptAction->isChecked() );
  2188. lvi->setSign( mSignAction->isChecked() );
  2189. } else {
  2190. lvi->enableCryptoCBs( false );
  2191. }
  2192. }
  2193. }
  2194. //-----------------------------------------------------------------------------
  2195. void KMComposeWin::removeAttach(const TQString &aUrl)
  2196. {
  2197. int idx;
  2198. KMMessagePart* msgPart;
  2199. for(idx=0,msgPart=mAtmList.first(); msgPart;
  2200. msgPart=mAtmList.next(),idx++) {
  2201. if (msgPart->name() == aUrl) {
  2202. removeAttach(idx);
  2203. return;
  2204. }
  2205. }
  2206. }
  2207. //-----------------------------------------------------------------------------
  2208. void KMComposeWin::removeAttach(int idx)
  2209. {
  2210. mAtmModified = true;
  2211. KMAtmListViewItem *item = static_cast<KMAtmListViewItem*>( mAtmItemList.at( idx ) );
  2212. if ( item->itemBelow() )
  2213. mAtmSelectNew = item->itemBelow();
  2214. else if ( item->itemAbove() )
  2215. mAtmSelectNew = item->itemAbove();
  2216. mAtmList.remove(idx);
  2217. delete mAtmItemList.take(idx);
  2218. if( mAtmList.isEmpty() )
  2219. {
  2220. mAtmListView->hide();
  2221. mAtmListView->setMinimumSize(0, 0);
  2222. resize(size());
  2223. }
  2224. }
  2225. //-----------------------------------------------------------------------------
  2226. bool KMComposeWin::encryptFlagOfAttachment(int idx)
  2227. {
  2228. return (int)(mAtmItemList.count()) > idx
  2229. ? static_cast<KMAtmListViewItem*>( mAtmItemList.at( idx ) )->isEncrypt()
  2230. : false;
  2231. }
  2232. //-----------------------------------------------------------------------------
  2233. bool KMComposeWin::signFlagOfAttachment(int idx)
  2234. {
  2235. return (int)(mAtmItemList.count()) > idx
  2236. ? ((KMAtmListViewItem*)(mAtmItemList.at( idx )))->isSign()
  2237. : false;
  2238. }
  2239. //-----------------------------------------------------------------------------
  2240. void KMComposeWin::addrBookSelInto()
  2241. {
  2242. if ( mClassicalRecipients ) {
  2243. if ( GlobalSettings::self()->addresseeSelectorType() ==
  2244. GlobalSettings::EnumAddresseeSelectorType::New ) {
  2245. addrBookSelIntoNew();
  2246. } else {
  2247. addrBookSelIntoOld();
  2248. }
  2249. } else {
  2250. kdWarning() << "To be implemented: call recipients picker." << endl;
  2251. }
  2252. }
  2253. void KMComposeWin::addrBookSelIntoOld()
  2254. {
  2255. AddressesDialog dlg( this );
  2256. TQString txt;
  2257. TQStringList lst;
  2258. txt = to();
  2259. if ( !txt.isEmpty() ) {
  2260. lst = KPIM::splitEmailAddrList( txt );
  2261. dlg.setSelectedTo( lst );
  2262. }
  2263. txt = mEdtCc->text();
  2264. if ( !txt.isEmpty() ) {
  2265. lst = KPIM::splitEmailAddrList( txt );
  2266. dlg.setSelectedCC( lst );
  2267. }
  2268. txt = mEdtBcc->text();
  2269. if ( !txt.isEmpty() ) {
  2270. lst = KPIM::splitEmailAddrList( txt );
  2271. dlg.setSelectedBCC( lst );
  2272. }
  2273. dlg.setRecentAddresses( RecentAddresses::self( KMKernel::config() )->tdeabcAddresses() );
  2274. if (dlg.exec()==TQDialog::Rejected) return;
  2275. mEdtTo->setText( dlg.to().join(", ") );
  2276. mEdtTo->setEdited( true );
  2277. mEdtCc->setText( dlg.cc().join(", ") );
  2278. mEdtCc->setEdited( true );
  2279. mEdtBcc->setText( dlg.bcc().join(", ") );
  2280. mEdtBcc->setEdited( true );
  2281. //Make sure BCC field is shown if needed
  2282. if ( !mEdtBcc->text().isEmpty() ) {
  2283. mShowHeaders |= HDR_BCC;
  2284. rethinkFields( false );
  2285. }
  2286. }
  2287. void KMComposeWin::addrBookSelIntoNew()
  2288. {
  2289. AddresseeEmailSelection selection;
  2290. AddresseeSelectorDialog dlg( &selection );
  2291. TQString txt;
  2292. TQStringList lst;
  2293. txt = to();
  2294. if ( !txt.isEmpty() ) {
  2295. lst = KPIM::splitEmailAddrList( txt );
  2296. selection.setSelectedTo( lst );
  2297. }
  2298. txt = mEdtCc->text();
  2299. if ( !txt.isEmpty() ) {
  2300. lst = KPIM::splitEmailAddrList( txt );
  2301. selection.setSelectedCC( lst );
  2302. }
  2303. txt = mEdtBcc->text();
  2304. if ( !txt.isEmpty() ) {
  2305. lst = KPIM::splitEmailAddrList( txt );
  2306. selection.setSelectedBCC( lst );
  2307. }
  2308. if (dlg.exec()==TQDialog::Rejected) return;
  2309. TQStringList list = selection.to() + selection.toDistributionLists();
  2310. mEdtTo->setText( list.join(", ") );
  2311. mEdtTo->setEdited( true );
  2312. list = selection.cc() + selection.ccDistributionLists();
  2313. mEdtCc->setText( list.join(", ") );
  2314. mEdtCc->setEdited( true );
  2315. list = selection.bcc() + selection.bccDistributionLists();
  2316. mEdtBcc->setText( list.join(", ") );
  2317. mEdtBcc->setEdited( true );
  2318. //Make sure BCC field is shown if needed
  2319. if ( !mEdtBcc->text().isEmpty() ) {
  2320. mShowHeaders |= HDR_BCC;
  2321. rethinkFields( false );
  2322. }
  2323. }
  2324. //-----------------------------------------------------------------------------
  2325. void KMComposeWin::setCharset(const TQCString& aCharset, bool forceDefault)
  2326. {
  2327. if ((forceDefault && GlobalSettings::self()->forceReplyCharset()) || aCharset.isEmpty())
  2328. mCharset = mDefCharset;
  2329. else
  2330. mCharset = aCharset.lower();
  2331. if ( mCharset.isEmpty() || mCharset == "default" )
  2332. mCharset = mDefCharset;
  2333. if (mAutoCharset)
  2334. {
  2335. mEncodingAction->setCurrentItem( 0 );
  2336. return;
  2337. }
  2338. TQStringList encodings = mEncodingAction->items();
  2339. int i = 0;
  2340. bool charsetFound = false;
  2341. for ( TQStringList::Iterator it = encodings.begin(); it != encodings.end();
  2342. ++it, i++ )
  2343. {
  2344. if (i > 0 && ((mCharset == "us-ascii" && i == 1) ||
  2345. (i != 1 && TDEGlobal::charsets()->codecForName(
  2346. TDEGlobal::charsets()->encodingForName(*it))
  2347. == TDEGlobal::charsets()->codecForName(mCharset))))
  2348. {
  2349. mEncodingAction->setCurrentItem( i );
  2350. slotSetCharset();
  2351. charsetFound = true;
  2352. break;
  2353. }
  2354. }
  2355. if (!aCharset.isEmpty() && !charsetFound) setCharset("", true);
  2356. }
  2357. //-----------------------------------------------------------------------------
  2358. void KMComposeWin::slotAddrBook()
  2359. {
  2360. KAddrBookExternal::openAddressBook(this);
  2361. }
  2362. //-----------------------------------------------------------------------------
  2363. void KMComposeWin::slotAddrBookFrom()
  2364. {
  2365. addrBookSelInto();
  2366. }
  2367. //-----------------------------------------------------------------------------
  2368. void KMComposeWin::slotAddrBookReplyTo()
  2369. {
  2370. addrBookSelInto();
  2371. }
  2372. //-----------------------------------------------------------------------------
  2373. void KMComposeWin::slotAddrBookTo()
  2374. {
  2375. addrBookSelInto();
  2376. }
  2377. //-----------------------------------------------------------------------------
  2378. void KMComposeWin::slotAttachFile()
  2379. {
  2380. // Create File Dialog and return selected file(s)
  2381. // We will not care about any permissions, existence or whatsoever in
  2382. // this function.
  2383. // Handle the case where the last savedir is gone. kolab/issue4057
  2384. TQString recent;
  2385. KURL recentURL = KFileDialog::getStartURL( TQString(), recent );
  2386. if ( !recentURL.url().isEmpty() &&
  2387. !TDEIO::NetAccess::exists( recentURL, true, this ) ) {
  2388. recentURL = KURL( TQDir::homeDirPath() );
  2389. }
  2390. KFileDialog fdlg( recentURL.url(), TQString(), this, 0, true );
  2391. fdlg.setOperationMode( KFileDialog::Other );
  2392. fdlg.setCaption( i18n( "Attach File" ) );
  2393. fdlg.okButton()->setGuiItem( KGuiItem( i18n( "&Attach" ),"fileopen" ) );
  2394. fdlg.setMode( KFile::Files );
  2395. fdlg.exec();
  2396. KURL::List files = fdlg.selectedURLs();
  2397. for (KURL::List::Iterator it = files.begin(); it != files.end(); ++it)
  2398. addAttach(*it);
  2399. }
  2400. //-----------------------------------------------------------------------------
  2401. void KMComposeWin::slotAttachFileData(TDEIO::Job *job, const TQByteArray &data)
  2402. {
  2403. TQMap<TDEIO::Job*, atmLoadData>::Iterator it = mMapAtmLoadData.find(job);
  2404. assert(it != mMapAtmLoadData.end());
  2405. TQBuffer buff((*it).data);
  2406. buff.open(IO_WriteOnly | IO_Append);
  2407. buff.writeBlock(data.data(), data.size());
  2408. buff.close();
  2409. }
  2410. //-----------------------------------------------------------------------------
  2411. void KMComposeWin::slotAttachFileResult(TDEIO::Job *job)
  2412. {
  2413. TQMap<TDEIO::Job*, atmLoadData>::Iterator it = mMapAtmLoadData.find(job);
  2414. assert(it != mMapAtmLoadData.end());
  2415. KURL attachURL;
  2416. TQMap<TDEIO::Job*, KURL>::iterator jit = mAttachJobs.find(job);
  2417. bool attachURLfound = (jit != mAttachJobs.end());
  2418. if (attachURLfound)
  2419. {
  2420. attachURL = jit.data();
  2421. mAttachJobs.remove(jit);
  2422. }
  2423. if (job->error())
  2424. {
  2425. mMapAtmLoadData.remove(it);
  2426. job->showErrorDialog();
  2427. if (attachURLfound)
  2428. emit attachmentAdded(attachURL, false);
  2429. return;
  2430. }
  2431. if ((*it).insert)
  2432. {
  2433. (*it).data.resize((*it).data.size() + 1);
  2434. (*it).data[(*it).data.size() - 1] = '\0';
  2435. if ( const TQTextCodec * codec = TDEGlobal::charsets()->codecForName((*it).encoding) )
  2436. mEditor->insert( codec->toUnicode( (*it).data ) );
  2437. else
  2438. mEditor->insert( TQString::fromLocal8Bit( (*it).data ) );
  2439. mMapAtmLoadData.remove(it);
  2440. if (attachURLfound)
  2441. emit attachmentAdded(attachURL, true);
  2442. return;
  2443. }
  2444. TQCString partCharset;
  2445. if ( !( *it ).url.fileEncoding().isEmpty() ) {
  2446. partCharset = TQCString( ( *it ).url.fileEncoding().latin1() );
  2447. } else {
  2448. EncodingDetector ed;
  2449. TDELocale *loc = TDEGlobal::locale();
  2450. ed.setAutoDetectLanguage( EncodingDetector::scriptForLanguageCode ( loc->language() ) );
  2451. ed.analyze( (*it).data );
  2452. partCharset = ed.encoding();
  2453. if ( partCharset.isEmpty() ) //shouldn't happen
  2454. partCharset = mCharset;
  2455. }
  2456. KMMessagePart* msgPart;
  2457. KCursorSaver busy(KBusyPtr::busy());
  2458. TQString name( (*it).url.fileName() );
  2459. // ask the job for the mime type of the file
  2460. TQString mimeType = static_cast<TDEIO::MimetypeJob*>(job)->mimetype();
  2461. if ( name.isEmpty() ) {
  2462. // URL ends with '/' (e.g. http://www.kde.org/)
  2463. // guess a reasonable filename
  2464. if( mimeType == "text/html" )
  2465. name = "index.html";
  2466. else {
  2467. // try to determine a reasonable extension
  2468. TQStringList patterns( KMimeType::mimeType( mimeType )->patterns() );
  2469. TQString ext;
  2470. if( !patterns.isEmpty() ) {
  2471. ext = patterns[0];
  2472. int i = ext.findRev( '.' );
  2473. if( i == -1 )
  2474. ext.prepend( '.' );
  2475. else if( i > 0 )
  2476. ext = ext.mid( i );
  2477. }
  2478. name = TQString("unknown") += ext;
  2479. }
  2480. }
  2481. name.truncate( 256 ); // is this needed?
  2482. TQCString encoding = KMMsgBase::autoDetectCharset(partCharset,
  2483. KMMessage::preferredCharsets(), name);
  2484. if ( encoding.isEmpty() )
  2485. encoding = "utf-8";
  2486. TQCString encName;
  2487. if ( GlobalSettings::self()->outlookCompatibleAttachments() )
  2488. encName = KMMsgBase::encodeRFC2047String( name, encoding );
  2489. else
  2490. encName = KMMsgBase::encodeRFC2231String( name, encoding );
  2491. bool RFC2231encoded = false;
  2492. if ( !GlobalSettings::self()->outlookCompatibleAttachments() )
  2493. RFC2231encoded = name != TQString( encName );
  2494. // create message part
  2495. msgPart = new KMMessagePart;
  2496. msgPart->setName(name);
  2497. TQValueList<int> allowedCTEs;
  2498. if ( mimeType == "message/rfc822" ) {
  2499. msgPart->setMessageBody( (*it).data );
  2500. allowedCTEs << DwMime::kCte7bit;
  2501. allowedCTEs << DwMime::kCte8bit;
  2502. } else {
  2503. msgPart->setBodyAndGuessCte((*it).data, allowedCTEs,
  2504. !kmkernel->msgSender()->sendQuotedPrintable());
  2505. kdDebug(5006) << "autodetected cte: " << msgPart->cteStr() << endl;
  2506. }
  2507. int slash = mimeType.find( '/' );
  2508. if( slash == -1 )
  2509. slash = mimeType.length();
  2510. msgPart->setTypeStr( mimeType.left( slash ).latin1() );
  2511. msgPart->setSubtypeStr( mimeType.mid( slash + 1 ).latin1() );
  2512. msgPart->setContentDisposition(TQCString("attachment;\n\tfilename")
  2513. + ( RFC2231encoded ? "*=" + encName : "=\"" + encName + '"' ) );
  2514. mMapAtmLoadData.remove(it);
  2515. if ( msgPart->typeStr().lower() == "text" ) {
  2516. msgPart->setCharset(partCharset);
  2517. }
  2518. // show message part dialog, if not configured away (default):
  2519. TDEConfigGroup composer(KMKernel::config(), "Composer");
  2520. if ( GlobalSettings::self()->showMessagePartDialogOnAttach() ) {
  2521. const KCursorSaver saver( TQCursor::ArrowCursor );
  2522. KMMsgPartDialogCompat dlg(mMainWidget);
  2523. int encodings = 0;
  2524. for ( TQValueListConstIterator<int> it = allowedCTEs.begin() ;
  2525. it != allowedCTEs.end() ; ++it )
  2526. switch ( *it ) {
  2527. case DwMime::kCteBase64: encodings |= KMMsgPartDialog::Base64; break;
  2528. case DwMime::kCteQp: encodings |= KMMsgPartDialog::QuotedPrintable; break;
  2529. case DwMime::kCte7bit: encodings |= KMMsgPartDialog::SevenBit; break;
  2530. case DwMime::kCte8bit: encodings |= KMMsgPartDialog::EightBit; break;
  2531. default: ;
  2532. }
  2533. dlg.setShownEncodings( encodings );
  2534. dlg.setMsgPart(msgPart);
  2535. if (!dlg.exec()) {
  2536. delete msgPart;
  2537. msgPart = 0;
  2538. if (attachURLfound)
  2539. emit attachmentAdded(attachURL, false);
  2540. return;
  2541. }
  2542. }
  2543. mAtmModified = true;
  2544. // add the new attachment to the list
  2545. addAttach(msgPart);
  2546. if (attachURLfound)
  2547. emit attachmentAdded(attachURL, true);
  2548. }
  2549. //-----------------------------------------------------------------------------
  2550. void KMComposeWin::slotInsertFile()
  2551. {
  2552. KFileDialog fdlg(TQString(), TQString(), this, 0, true);
  2553. fdlg.setOperationMode( KFileDialog::Opening );
  2554. fdlg.okButton()->setText(i18n("&Insert"));
  2555. fdlg.setCaption(i18n("Insert File"));
  2556. fdlg.toolBar()->insertCombo(KMMsgBase::supportedEncodings(false), 4711,
  2557. false, 0, 0, 0);
  2558. KComboBox *combo = fdlg.toolBar()->getCombo(4711);
  2559. for (int i = 0; i < combo->count(); i++)
  2560. if (TDEGlobal::charsets()->codecForName(TDEGlobal::charsets()->
  2561. encodingForName(combo->text(i)))
  2562. == TQTextCodec::codecForLocale()) combo->setCurrentItem(i);
  2563. if (!fdlg.exec()) return;
  2564. KURL u = fdlg.selectedURL();
  2565. mRecentAction->addURL(u);
  2566. // Prevent race condition updating list when multiple composers are open
  2567. {
  2568. TDEConfig *config = KMKernel::config();
  2569. TDEConfigGroupSaver saver( config, "Composer" );
  2570. TQString encoding = TDEGlobal::charsets()->encodingForName(combo->currentText()).latin1();
  2571. TQStringList urls = config->readListEntry( "recent-urls" );
  2572. TQStringList encodings = config->readListEntry( "recent-encodings" );
  2573. // Prevent config file from growing without bound
  2574. // Would be nicer to get this constant from TDERecentFilesAction
  2575. uint mMaxRecentFiles = 30;
  2576. while (urls.count() > mMaxRecentFiles)
  2577. urls.erase( urls.fromLast() );
  2578. while (encodings.count() > mMaxRecentFiles)
  2579. encodings.erase( encodings.fromLast() );
  2580. // sanity check
  2581. if (urls.count() != encodings.count()) {
  2582. urls.clear();
  2583. encodings.clear();
  2584. }
  2585. urls.prepend( u.prettyURL() );
  2586. encodings.prepend( encoding );
  2587. config->writeEntry( "recent-urls", urls );
  2588. config->writeEntry( "recent-encodings", encodings );
  2589. mRecentAction->saveEntries( config );
  2590. }
  2591. slotInsertRecentFile(u);
  2592. }
  2593. //-----------------------------------------------------------------------------
  2594. void KMComposeWin::slotInsertRecentFile(const KURL& u)
  2595. {
  2596. if (u.fileName().isEmpty()) return;
  2597. TDEIO::Job *job = TDEIO::get(u);
  2598. atmLoadData ld;
  2599. ld.url = u;
  2600. ld.data = TQByteArray();
  2601. ld.insert = true;
  2602. // Get the encoding previously used when inserting this file
  2603. {
  2604. TDEConfig *config = KMKernel::config();
  2605. TDEConfigGroupSaver saver( config, "Composer" );
  2606. TQStringList urls = config->readListEntry( "recent-urls" );
  2607. TQStringList encodings = config->readListEntry( "recent-encodings" );
  2608. int index = urls.findIndex( u.prettyURL() );
  2609. if (index != -1) {
  2610. TQString encoding = encodings[ index ];
  2611. ld.encoding = encoding.latin1();
  2612. }
  2613. }
  2614. mMapAtmLoadData.insert(job, ld);
  2615. connect(job, TQT_SIGNAL(result(TDEIO::Job *)),
  2616. TQT_TQOBJECT(this), TQT_SLOT(slotAttachFileResult(TDEIO::Job *)));
  2617. connect(job, TQT_SIGNAL(data(TDEIO::Job *, const TQByteArray &)),
  2618. TQT_TQOBJECT(this), TQT_SLOT(slotAttachFileData(TDEIO::Job *, const TQByteArray &)));
  2619. }
  2620. //-----------------------------------------------------------------------------
  2621. void KMComposeWin::slotSetCharset()
  2622. {
  2623. if (mEncodingAction->currentItem() == 0)
  2624. {
  2625. mAutoCharset = true;
  2626. return;
  2627. }
  2628. mAutoCharset = false;
  2629. mCharset = TDEGlobal::charsets()->encodingForName( mEncodingAction->
  2630. currentText() ).latin1();
  2631. }
  2632. //-----------------------------------------------------------------------------
  2633. void KMComposeWin::slotSelectCryptoModule( bool init )
  2634. {
  2635. if ( !init ) {
  2636. setModified( true );
  2637. }
  2638. if( canSignEncryptAttachments() ) {
  2639. // if the encrypt/sign columns are hidden then show them
  2640. if( 0 == mAtmListView->columnWidth( mAtmColEncrypt ) ) {
  2641. // set/unset signing/encryption for all attachments according to the
  2642. // state of the global sign/encrypt action
  2643. if( !mAtmList.isEmpty() ) {
  2644. for( KMAtmListViewItem* lvi = static_cast<KMAtmListViewItem*>( mAtmItemList.first() );
  2645. lvi;
  2646. lvi = static_cast<KMAtmListViewItem*>( mAtmItemList.next() ) ) {
  2647. lvi->setSign( mSignAction->isChecked() );
  2648. lvi->setEncrypt( mEncryptAction->isChecked() );
  2649. }
  2650. }
  2651. int totalWidth = 0;
  2652. // determine the total width of the columns
  2653. for( int col=0; col < mAtmColEncrypt; col++ )
  2654. totalWidth += mAtmListView->columnWidth( col );
  2655. int reducedTotalWidth = totalWidth - mAtmEncryptColWidth
  2656. - mAtmSignColWidth;
  2657. // reduce the width of all columns so that the encrypt and sign column
  2658. // fit
  2659. int usedWidth = 0;
  2660. for( int col=0; col < mAtmColEncrypt-1; col++ ) {
  2661. int newWidth = mAtmListView->columnWidth( col ) * reducedTotalWidth
  2662. / totalWidth;
  2663. mAtmListView->setColumnWidth( col, newWidth );
  2664. usedWidth += newWidth;
  2665. }
  2666. // the last column before the encrypt column gets the remaining space
  2667. // (because of rounding errors the width of this column isn't calculated
  2668. // the same way as the width of the other columns)
  2669. mAtmListView->setColumnWidth( mAtmColEncrypt-1,
  2670. reducedTotalWidth - usedWidth );
  2671. mAtmListView->setColumnWidth( mAtmColEncrypt, mAtmEncryptColWidth );
  2672. mAtmListView->setColumnWidth( mAtmColSign, mAtmSignColWidth );
  2673. for( KMAtmListViewItem* lvi = static_cast<KMAtmListViewItem*>( mAtmItemList.first() );
  2674. lvi;
  2675. lvi = static_cast<KMAtmListViewItem*>( mAtmItemList.next() ) ) {
  2676. lvi->enableCryptoCBs( true );
  2677. }
  2678. }
  2679. } else {
  2680. // if the encrypt/sign columns are visible then hide them
  2681. if( 0 != mAtmListView->columnWidth( mAtmColEncrypt ) ) {
  2682. mAtmEncryptColWidth = mAtmListView->columnWidth( mAtmColEncrypt );
  2683. mAtmSignColWidth = mAtmListView->columnWidth( mAtmColSign );
  2684. int totalWidth = 0;
  2685. // determine the total width of the columns
  2686. for( int col=0; col < mAtmListView->columns(); col++ )
  2687. totalWidth += mAtmListView->columnWidth( col );
  2688. int reducedTotalWidth = totalWidth - mAtmEncryptColWidth
  2689. - mAtmSignColWidth;
  2690. // increase the width of all columns so that the visible columns take
  2691. // up the whole space
  2692. int usedWidth = 0;
  2693. for( int col=0; col < mAtmColEncrypt-1; col++ ) {
  2694. int newWidth = mAtmListView->columnWidth( col ) * totalWidth
  2695. / reducedTotalWidth;
  2696. mAtmListView->setColumnWidth( col, newWidth );
  2697. usedWidth += newWidth;
  2698. }
  2699. // the last column before the encrypt column gets the remaining space
  2700. // (because of rounding errors the width of this column isn't calculated
  2701. // the same way as the width of the other columns)
  2702. mAtmListView->setColumnWidth( mAtmColEncrypt-1, totalWidth - usedWidth );
  2703. mAtmListView->setColumnWidth( mAtmColEncrypt, 0 );
  2704. mAtmListView->setColumnWidth( mAtmColSign, 0 );
  2705. for( KMAtmListViewItem* lvi = static_cast<KMAtmListViewItem*>( mAtmItemList.first() );
  2706. lvi;
  2707. lvi = static_cast<KMAtmListViewItem*>( mAtmItemList.next() ) ) {
  2708. lvi->enableCryptoCBs( false );
  2709. }
  2710. }
  2711. }
  2712. }
  2713. static void showExportError( TQWidget * w, const GpgME::Error & err ) {
  2714. assert( err );
  2715. const TQString msg = i18n("<qt><p>An error occurred while trying to export "
  2716. "the key from the backend:</p>"
  2717. "<p><b>%1</b></p></qt>")
  2718. .arg( TQString::fromLocal8Bit( err.asString() ) );
  2719. KMessageBox::error( w, msg, i18n("Key Export Failed") );
  2720. }
  2721. //-----------------------------------------------------------------------------
  2722. void KMComposeWin::slotInsertMyPublicKey()
  2723. {
  2724. // get PGP user id for the chosen identity
  2725. mFingerprint =
  2726. kmkernel->identityManager()->identityForUoidOrDefault( mIdentity->currentIdentity() ).pgpEncryptionKey();
  2727. if ( !mFingerprint.isEmpty() )
  2728. startPublicKeyExport();
  2729. }
  2730. void KMComposeWin::startPublicKeyExport() {
  2731. if ( mFingerprint.isEmpty() || !Kleo::CryptoBackendFactory::instance()->openpgp() )
  2732. return;
  2733. Kleo::ExportJob * job = Kleo::CryptoBackendFactory::instance()->openpgp()->publicKeyExportJob( true );
  2734. assert( job );
  2735. connect( job, TQT_SIGNAL(result(const GpgME::Error&,const TQByteArray&)),
  2736. this, TQT_SLOT(slotPublicKeyExportResult(const GpgME::Error&,const TQByteArray&)) );
  2737. const GpgME::Error err = job->start( mFingerprint );
  2738. if ( err )
  2739. showExportError( this, err );
  2740. else
  2741. (void)new Kleo::ProgressDialog( job, i18n("Exporting key..."), this );
  2742. }
  2743. void KMComposeWin::slotPublicKeyExportResult( const GpgME::Error & err, const TQByteArray & keydata ) {
  2744. if ( err ) {
  2745. showExportError( this, err );
  2746. return;
  2747. }
  2748. // create message part
  2749. KMMessagePart * msgPart = new KMMessagePart();
  2750. msgPart->setName( i18n("OpenPGP key 0x%1").arg( mFingerprint ) );
  2751. msgPart->setTypeStr("application");
  2752. msgPart->setSubtypeStr("pgp-keys");
  2753. TQValueList<int> dummy;
  2754. msgPart->setBodyAndGuessCte(keydata, dummy, false);
  2755. msgPart->setContentDisposition( "attachment;\n\tfilename=0x" + TQCString( mFingerprint.latin1() ) + ".asc" );
  2756. // add the new attachment to the list
  2757. addAttach(msgPart);
  2758. rethinkFields(); //work around initial-size bug in TQt-1.32
  2759. }
  2760. //-----------------------------------------------------------------------------
  2761. void KMComposeWin::slotInsertPublicKey()
  2762. {
  2763. Kleo::KeySelectionDialog dlg( i18n("Attach Public OpenPGP Key"),
  2764. i18n("Select the public key which should "
  2765. "be attached."),
  2766. std::vector<GpgME::Key>(),
  2767. Kleo::KeySelectionDialog::PublicKeys|Kleo::KeySelectionDialog::OpenPGPKeys,
  2768. false /* no multi selection */,
  2769. false /* no remember choice box */,
  2770. this, "attach public key selection dialog" );
  2771. if ( dlg.exec() != TQDialog::Accepted )
  2772. return;
  2773. mFingerprint = dlg.fingerprint();
  2774. startPublicKeyExport();
  2775. }
  2776. //-----------------------------------------------------------------------------
  2777. void KMComposeWin::slotAttachPopupMenu(TQListViewItem *, const TQPoint &, int)
  2778. {
  2779. if (!mAttachMenu)
  2780. {
  2781. mAttachMenu = new TQPopupMenu(this);
  2782. mOpenId = mAttachMenu->insertItem(i18n("to open", "Open"), this,
  2783. TQT_SLOT(slotAttachOpen()));
  2784. mOpenWithId = mAttachMenu->insertItem(i18n("Open With..."), this,
  2785. TQT_SLOT(slotAttachOpenWith()));
  2786. mViewId = mAttachMenu->insertItem(i18n("to view", "View"), this,
  2787. TQT_SLOT(slotAttachView()));
  2788. mEditId = mAttachMenu->insertItem( i18n("Edit"), this, TQT_SLOT(slotAttachEdit()) );
  2789. mEditWithId = mAttachMenu->insertItem( i18n("Edit With..."), this,
  2790. TQT_SLOT(slotAttachEditWith()) );
  2791. mRemoveId = mAttachMenu->insertItem(i18n("Remove"), this, TQT_SLOT(slotAttachRemove()));
  2792. mSaveAsId = mAttachMenu->insertItem( SmallIconSet("filesaveas"), i18n("Save As..."), this,
  2793. TQT_SLOT( slotAttachSave() ) );
  2794. mPropertiesId = mAttachMenu->insertItem( i18n("Properties"), this,
  2795. TQT_SLOT( slotAttachProperties() ) );
  2796. mAttachMenu->insertSeparator();
  2797. mAttachMenu->insertItem(i18n("Add Attachment..."), this, TQT_SLOT(slotAttachFile()));
  2798. }
  2799. int selectedCount = 0;
  2800. for ( TQPtrListIterator<TQListViewItem> it(mAtmItemList); *it; ++it ) {
  2801. if ( (*it)->isSelected() ) {
  2802. ++selectedCount;
  2803. }
  2804. }
  2805. mAttachMenu->setItemEnabled( mOpenId, selectedCount > 0 );
  2806. mAttachMenu->setItemEnabled( mOpenWithId, selectedCount > 0 );
  2807. mAttachMenu->setItemEnabled( mViewId, selectedCount > 0 );
  2808. mAttachMenu->setItemEnabled( mEditId, selectedCount == 1 );
  2809. mAttachMenu->setItemEnabled( mEditWithId, selectedCount == 1 );
  2810. mAttachMenu->setItemEnabled( mRemoveId, selectedCount > 0 );
  2811. mAttachMenu->setItemEnabled( mSaveAsId, selectedCount == 1 );
  2812. mAttachMenu->setItemEnabled( mPropertiesId, selectedCount == 1 );
  2813. mAttachMenu->popup(TQCursor::pos());
  2814. }
  2815. //-----------------------------------------------------------------------------
  2816. int KMComposeWin::currentAttachmentNum()
  2817. {
  2818. int i = 0;
  2819. for ( TQPtrListIterator<TQListViewItem> it(mAtmItemList); *it; ++it, ++i )
  2820. if ( *it == mAtmListView->currentItem() )
  2821. return i;
  2822. return -1;
  2823. }
  2824. //-----------------------------------------------------------------------------
  2825. void KMComposeWin::slotAttachProperties()
  2826. {
  2827. int idx = currentAttachmentNum();
  2828. if (idx < 0) return;
  2829. KMMessagePart* msgPart = mAtmList.at(idx);
  2830. KMMsgPartDialogCompat dlg(mMainWidget);
  2831. dlg.setMsgPart(msgPart);
  2832. KMAtmListViewItem* listItem = (KMAtmListViewItem*)(mAtmItemList.at(idx));
  2833. if( canSignEncryptAttachments() && listItem ) {
  2834. dlg.setCanSign( true );
  2835. dlg.setCanEncrypt( true );
  2836. dlg.setSigned( listItem->isSign() );
  2837. dlg.setEncrypted( listItem->isEncrypt() );
  2838. } else {
  2839. dlg.setCanSign( false );
  2840. dlg.setCanEncrypt( false );
  2841. }
  2842. if (dlg.exec())
  2843. {
  2844. mAtmModified = true;
  2845. // values may have changed, so recreate the listbox line
  2846. if( listItem ) {
  2847. msgPartToItem(msgPart, listItem);
  2848. if( canSignEncryptAttachments() ) {
  2849. listItem->setSign( dlg.isSigned() );
  2850. listItem->setEncrypt( dlg.isEncrypted() );
  2851. }
  2852. }
  2853. }
  2854. if (msgPart->typeStr().lower() != "text") msgPart->setCharset(TQCString());
  2855. }
  2856. //-----------------------------------------------------------------------------
  2857. void KMComposeWin::compressAttach( int idx )
  2858. {
  2859. if (idx < 0) return;
  2860. unsigned int i;
  2861. for ( i = 0; i < mAtmItemList.count(); ++i )
  2862. if ( mAtmItemList.at( i )->itemPos() == idx )
  2863. break;
  2864. if ( i > mAtmItemList.count() )
  2865. return;
  2866. KMMessagePart* msgPart;
  2867. msgPart = mAtmList.at( i );
  2868. TQByteArray array;
  2869. TQBuffer dev( array );
  2870. KZip zip( &TQT_TQIODEVICE_OBJECT(dev) );
  2871. TQByteArray decoded = msgPart->bodyDecodedBinary();
  2872. if ( ! zip.open( IO_WriteOnly ) ) {
  2873. KMessageBox::sorry(0, i18n("KMail could not compress the file.") );
  2874. static_cast<KMAtmListViewItem*>( mAtmItemList.at( i ) )->setCompress( false );
  2875. return;
  2876. }
  2877. zip.setCompression( KZip::DeflateCompression );
  2878. if ( ! zip.writeFile( msgPart->name(), "", "", decoded.size(),
  2879. decoded.data() ) ) {
  2880. KMessageBox::sorry(0, i18n("KMail could not compress the file.") );
  2881. static_cast<KMAtmListViewItem*>( mAtmItemList.at( i ) )->setCompress( false );
  2882. return;
  2883. }
  2884. zip.close();
  2885. if ( array.size() >= decoded.size() ) {
  2886. if ( KMessageBox::questionYesNo( this, i18n("The compressed file is larger "
  2887. "than the original. Do you want to keep the original one?" ), TQString(), i18n("Keep"), i18n("Compress") )
  2888. == KMessageBox::Yes ) {
  2889. static_cast<KMAtmListViewItem*>( mAtmItemList.at( i ) )->setCompress( false );
  2890. return;
  2891. }
  2892. }
  2893. static_cast<KMAtmListViewItem*>( mAtmItemList.at( i ) )->setUncompressedCodec(
  2894. msgPart->cteStr() );
  2895. msgPart->setCteStr( "base64" );
  2896. msgPart->setBodyEncodedBinary( array );
  2897. TQString name = msgPart->name() + ".zip";
  2898. msgPart->setName( name );
  2899. TQCString cDisp = "attachment;";
  2900. TQCString encoding = KMMsgBase::autoDetectCharset( msgPart->charset(),
  2901. KMMessage::preferredCharsets(), name );
  2902. kdDebug(5006) << "encoding: " << encoding << endl;
  2903. if ( encoding.isEmpty() ) encoding = "utf-8";
  2904. kdDebug(5006) << "encoding after: " << encoding << endl;
  2905. TQCString encName;
  2906. if ( GlobalSettings::self()->outlookCompatibleAttachments() )
  2907. encName = KMMsgBase::encodeRFC2047String( name, encoding );
  2908. else
  2909. encName = KMMsgBase::encodeRFC2231String( name, encoding );
  2910. cDisp += "\n\tfilename";
  2911. if ( name != TQString( encName ) )
  2912. cDisp += "*=" + encName;
  2913. else
  2914. cDisp += "=\"" + encName + '"';
  2915. msgPart->setContentDisposition( cDisp );
  2916. static_cast<KMAtmListViewItem*>( mAtmItemList.at( i ) )->setUncompressedMimeType(
  2917. msgPart->typeStr(), msgPart->subtypeStr() );
  2918. msgPart->setTypeStr( "application" );
  2919. msgPart->setSubtypeStr( "x-zip" );
  2920. KMAtmListViewItem* listItem = static_cast<KMAtmListViewItem*>( mAtmItemList.at( i ) );
  2921. msgPartToItem( msgPart, listItem, false );
  2922. }
  2923. //-----------------------------------------------------------------------------
  2924. void KMComposeWin::uncompressAttach( int idx )
  2925. {
  2926. if (idx < 0) return;
  2927. unsigned int i;
  2928. for ( i = 0; i < mAtmItemList.count(); ++i )
  2929. if ( mAtmItemList.at( i )->itemPos() == idx )
  2930. break;
  2931. if ( i > mAtmItemList.count() )
  2932. return;
  2933. KMMessagePart* msgPart;
  2934. msgPart = mAtmList.at( i );
  2935. TQBuffer dev( msgPart->bodyDecodedBinary() );
  2936. KZip zip( &TQT_TQIODEVICE_OBJECT(dev) );
  2937. TQByteArray decoded;
  2938. decoded = msgPart->bodyDecodedBinary();
  2939. if ( ! zip.open( IO_ReadOnly ) ) {
  2940. KMessageBox::sorry(0, i18n("KMail could not uncompress the file.") );
  2941. static_cast<KMAtmListViewItem *>( mAtmItemList.at( i ) )->setCompress( true );
  2942. return;
  2943. }
  2944. const KArchiveDirectory *dir = zip.directory();
  2945. KZipFileEntry *entry;
  2946. if ( dir->entries().count() != 1 ) {
  2947. KMessageBox::sorry(0, i18n("KMail could not uncompress the file.") );
  2948. static_cast<KMAtmListViewItem *>( mAtmItemList.at( i ) )->setCompress( true );
  2949. return;
  2950. }
  2951. entry = (KZipFileEntry*)dir->entry( dir->entries()[0] );
  2952. msgPart->setCteStr(
  2953. static_cast<KMAtmListViewItem*>( mAtmItemList.at(i) )->uncompressedCodec() );
  2954. msgPart->setBodyEncodedBinary( entry->data() );
  2955. TQString name = entry->name();
  2956. msgPart->setName( name );
  2957. zip.close();
  2958. TQCString cDisp = "attachment;";
  2959. TQCString encoding = KMMsgBase::autoDetectCharset( msgPart->charset(),
  2960. KMMessage::preferredCharsets(), name );
  2961. if ( encoding.isEmpty() ) encoding = "utf-8";
  2962. TQCString encName;
  2963. if ( GlobalSettings::self()->outlookCompatibleAttachments() )
  2964. encName = KMMsgBase::encodeRFC2047String( name, encoding );
  2965. else
  2966. encName = KMMsgBase::encodeRFC2231String( name, encoding );
  2967. cDisp += "\n\tfilename";
  2968. if ( name != TQString( encName ) )
  2969. cDisp += "*=" + encName;
  2970. else
  2971. cDisp += "=\"" + encName + '"';
  2972. msgPart->setContentDisposition( cDisp );
  2973. TQCString type, subtype;
  2974. static_cast<KMAtmListViewItem*>( mAtmItemList.at( i ) )->uncompressedMimeType( type,
  2975. subtype );
  2976. msgPart->setTypeStr( type );
  2977. msgPart->setSubtypeStr( subtype );
  2978. KMAtmListViewItem* listItem = static_cast<KMAtmListViewItem*>(mAtmItemList.at( i ));
  2979. msgPartToItem( msgPart, listItem, false );
  2980. }
  2981. //-----------------------------------------------------------------------------
  2982. void KMComposeWin::slotAttachView()
  2983. {
  2984. int i = 0;
  2985. for ( TQPtrListIterator<TQListViewItem> it(mAtmItemList); *it; ++it, ++i ) {
  2986. if ( (*it)->isSelected() ) {
  2987. viewAttach( i );
  2988. }
  2989. }
  2990. }
  2991. //-----------------------------------------------------------------------------
  2992. void KMComposeWin::slotAttachOpen()
  2993. {
  2994. int i = 0;
  2995. for ( TQPtrListIterator<TQListViewItem> it(mAtmItemList); *it; ++it, ++i ) {
  2996. if ( (*it)->isSelected() ) {
  2997. openAttach( i, false );
  2998. }
  2999. }
  3000. }
  3001. //-----------------------------------------------------------------------------
  3002. void KMComposeWin::slotAttachOpenWith()
  3003. {
  3004. int i = 0;
  3005. for ( TQPtrListIterator<TQListViewItem> it(mAtmItemList); *it; ++it, ++i ) {
  3006. if ( (*it)->isSelected() ) {
  3007. openAttach( i, true );
  3008. }
  3009. }
  3010. }
  3011. void KMComposeWin::slotAttachEdit()
  3012. {
  3013. int i = 0;
  3014. for ( TQPtrListIterator<TQListViewItem> it(mAtmItemList); *it; ++it, ++i ) {
  3015. if ( (*it)->isSelected() ) {
  3016. editAttach( i, false );
  3017. }
  3018. }
  3019. }
  3020. void KMComposeWin::slotAttachEditWith()
  3021. {
  3022. int i = 0;
  3023. for ( TQPtrListIterator<TQListViewItem> it(mAtmItemList); *it; ++it, ++i ) {
  3024. if ( (*it)->isSelected() ) {
  3025. editAttach( i, true );
  3026. }
  3027. }
  3028. }
  3029. //-----------------------------------------------------------------------------
  3030. bool KMComposeWin::inlineSigningEncryptionSelected() {
  3031. if ( !mSignAction->isChecked() && !mEncryptAction->isChecked() )
  3032. return false;
  3033. return cryptoMessageFormat() == Kleo::InlineOpenPGPFormat;
  3034. }
  3035. //-----------------------------------------------------------------------------
  3036. void KMComposeWin::viewAttach( int index )
  3037. {
  3038. TQString pname;
  3039. KMMessagePart* msgPart;
  3040. msgPart = mAtmList.at(index);
  3041. pname = msgPart->name().stripWhiteSpace();
  3042. if (pname.isEmpty()) pname=msgPart->contentDescription();
  3043. if (pname.isEmpty()) pname="unnamed";
  3044. KTempFile* atmTempFile = new KTempFile();
  3045. mAtmTempList.append( atmTempFile );
  3046. atmTempFile->setAutoDelete( true );
  3047. KPIM::kByteArrayToFile(msgPart->bodyDecodedBinary(), atmTempFile->name(), false, false,
  3048. false);
  3049. KMReaderMainWin *win = new KMReaderMainWin(msgPart, false,
  3050. atmTempFile->name(), pname, mCharset );
  3051. win->show();
  3052. }
  3053. //-----------------------------------------------------------------------------
  3054. void KMComposeWin::openAttach( int index, bool with )
  3055. {
  3056. KMMessagePart* msgPart = mAtmList.at(index);
  3057. const TQString contentTypeStr =
  3058. ( msgPart->typeStr() + '/' + msgPart->subtypeStr() ).lower();
  3059. KMimeType::Ptr mimetype;
  3060. mimetype = KMimeType::mimeType( contentTypeStr );
  3061. KTempFile* atmTempFile = new KTempFile();
  3062. mAtmTempList.append( atmTempFile );
  3063. const bool autoDelete = true;
  3064. atmTempFile->setAutoDelete( autoDelete );
  3065. KURL url;
  3066. url.setPath( atmTempFile->name() );
  3067. KPIM::kByteArrayToFile( msgPart->bodyDecodedBinary(), atmTempFile->name(), false, false,
  3068. false );
  3069. if ( ::chmod( TQFile::encodeName( atmTempFile->name() ), S_IRUSR ) != 0) {
  3070. TQFile::remove(url.path());
  3071. return;
  3072. }
  3073. KService::Ptr offer =
  3074. KServiceTypeProfile::preferredService( mimetype->name(), "Application" );
  3075. if ( with || !offer || mimetype->name() == "application/octet-stream" ) {
  3076. if ( ( !KRun::displayOpenWithDialog( url, autoDelete ) ) && autoDelete ) {
  3077. TQFile::remove(url.path());
  3078. }
  3079. }
  3080. else {
  3081. if ( ( !KRun::run( *offer, url, autoDelete ) ) && autoDelete ) {
  3082. TQFile::remove( url.path() );
  3083. }
  3084. }
  3085. }
  3086. void KMComposeWin::editAttach(int index, bool openWith)
  3087. {
  3088. KMMessagePart* msgPart = mAtmList.at(index);
  3089. const TQString contentTypeStr =
  3090. ( msgPart->typeStr() + '/' + msgPart->subtypeStr() ).lower();
  3091. KTempFile* atmTempFile = new KTempFile();
  3092. mAtmTempList.append( atmTempFile );
  3093. atmTempFile->setAutoDelete( true );
  3094. atmTempFile->file()->writeBlock( msgPart->bodyDecodedBinary() );
  3095. atmTempFile->file()->flush();
  3096. KMail::EditorWatcher *watcher =
  3097. new KMail::EditorWatcher( KURL( atmTempFile->name() ), contentTypeStr, openWith,
  3098. TQT_TQOBJECT(this), this );
  3099. connect( watcher, TQT_SIGNAL(editDone(KMail::EditorWatcher*)), TQT_SLOT(slotEditDone(KMail::EditorWatcher*)) );
  3100. if ( watcher->start() ) {
  3101. mEditorMap.insert( watcher, msgPart );
  3102. mEditorTempFiles.insert( watcher, atmTempFile );
  3103. }
  3104. }
  3105. //-----------------------------------------------------------------------------
  3106. void KMComposeWin::slotAttachSave()
  3107. {
  3108. KMMessagePart* msgPart;
  3109. TQString fileName, pname;
  3110. int idx = currentAttachmentNum();
  3111. if (idx < 0) return;
  3112. msgPart = mAtmList.at(idx);
  3113. pname = msgPart->name();
  3114. if (pname.isEmpty()) pname="unnamed";
  3115. KURL url = KFileDialog::getSaveURL(pname, TQString(), 0, i18n("Save Attachment As"));
  3116. if( url.isEmpty() )
  3117. return;
  3118. kmkernel->byteArrayToRemoteFile(msgPart->bodyDecodedBinary(), url);
  3119. }
  3120. //-----------------------------------------------------------------------------
  3121. void KMComposeWin::slotAttachRemove()
  3122. {
  3123. mAtmSelectNew = 0;
  3124. bool attachmentRemoved = false;
  3125. int i = 0;
  3126. for ( TQPtrListIterator<TQListViewItem> it(mAtmItemList); *it; ) {
  3127. if ( (*it)->isSelected() ) {
  3128. removeAttach( i );
  3129. attachmentRemoved = true;
  3130. }
  3131. else {
  3132. ++it;
  3133. ++i;
  3134. }
  3135. }
  3136. if ( attachmentRemoved ) {
  3137. setModified( true );
  3138. slotUpdateAttachActions();
  3139. if ( mAtmSelectNew ) {
  3140. mAtmListView->setSelected( mAtmSelectNew, true );
  3141. mAtmListView->setCurrentItem( mAtmSelectNew );
  3142. }
  3143. }
  3144. }
  3145. //-----------------------------------------------------------------------------
  3146. void KMComposeWin::slotFind()
  3147. {
  3148. mEditor->search();
  3149. }
  3150. void KMComposeWin::slotSearchAgain()
  3151. {
  3152. mEditor->repeatSearch();
  3153. }
  3154. //-----------------------------------------------------------------------------
  3155. void KMComposeWin::slotReplace()
  3156. {
  3157. mEditor->replace();
  3158. }
  3159. //-----------------------------------------------------------------------------
  3160. void KMComposeWin::slotUpdateFont()
  3161. {
  3162. kdDebug() << "KMComposeWin::slotUpdateFont " << endl;
  3163. if ( ! mFixedFontAction ) {
  3164. return;
  3165. }
  3166. mEditor->setFont( mFixedFontAction->isChecked() ? mFixedFont : mBodyFont );
  3167. }
  3168. TQString KMComposeWin::quotePrefixName() const
  3169. {
  3170. if ( !msg() )
  3171. return TQString();
  3172. int languageNr = GlobalSettings::self()->replyCurrentLanguage();
  3173. ReplyPhrases replyPhrases( TQString::number(languageNr) );
  3174. replyPhrases.readConfig();
  3175. TQString quotePrefix = msg()->formatString(
  3176. replyPhrases.indentPrefix() );
  3177. quotePrefix = msg()->formatString(quotePrefix);
  3178. return quotePrefix;
  3179. }
  3180. void KMComposeWin::slotPasteClipboardAsQuotation()
  3181. {
  3182. if( mEditor->hasFocus() && msg() )
  3183. {
  3184. TQString s = TQApplication::clipboard()->text();
  3185. if (!s.isEmpty())
  3186. mEditor->insert(addQuotesToText(s));
  3187. }
  3188. }
  3189. void KMComposeWin::slotPasteClipboardAsAttachment()
  3190. {
  3191. KURL url( TQApplication::clipboard()->text( TQClipboard::Clipboard ) );
  3192. if ( url.isValid() ) {
  3193. addAttach(TQApplication::clipboard()->text( TQClipboard::Clipboard ) );
  3194. return;
  3195. }
  3196. TQMimeSource *mimeSource = TQApplication::clipboard()->data();
  3197. if ( TQImageDrag::canDecode(mimeSource) ) {
  3198. slotAttachPNGImageData(mimeSource->encodedData("image/png"));
  3199. }
  3200. else {
  3201. bool ok;
  3202. TQString attName = KInputDialog::getText( "KMail", i18n("Name of the attachment:"), TQString(), &ok, this );
  3203. if ( !ok )
  3204. return;
  3205. KMMessagePart *msgPart = new KMMessagePart;
  3206. msgPart->setName(attName);
  3207. TQValueList<int> dummy;
  3208. msgPart->setBodyAndGuessCte(TQCString(TQApplication::clipboard()->text().latin1()), dummy,
  3209. kmkernel->msgSender()->sendQuotedPrintable());
  3210. addAttach(msgPart);
  3211. }
  3212. }
  3213. void KMComposeWin::slotAddQuotes()
  3214. {
  3215. if( mEditor->hasFocus() && msg() )
  3216. {
  3217. // TODO: I think this is backwards.
  3218. // i.e, if no region is marked then add quotes to every line
  3219. // else add quotes only on the lines that are marked.
  3220. if ( mEditor->hasMarkedText() ) {
  3221. TQString s = mEditor->markedText();
  3222. if(!s.isEmpty())
  3223. mEditor->insert(addQuotesToText(s));
  3224. } else {
  3225. int l = mEditor->currentLine();
  3226. int c = mEditor->currentColumn();
  3227. TQString s = mEditor->textLine(l);
  3228. s.prepend(quotePrefixName());
  3229. mEditor->insertLine(s,l);
  3230. mEditor->removeLine(l+1);
  3231. mEditor->setCursorPosition(l,c+2);
  3232. }
  3233. }
  3234. }
  3235. TQString KMComposeWin::addQuotesToText(const TQString &inputText)
  3236. {
  3237. TQString answer = TQString( inputText );
  3238. TQString indentStr = quotePrefixName();
  3239. answer.replace( '\n', '\n' + indentStr);
  3240. answer.prepend( indentStr );
  3241. answer += '\n';
  3242. return KMMessage::smartQuote( answer, GlobalSettings::self()->lineWrapWidth() );
  3243. }
  3244. TQString KMComposeWin::removeQuotesFromText(const TQString &inputText)
  3245. {
  3246. TQString s = inputText;
  3247. // remove first leading quote
  3248. TQString quotePrefix = '^' + quotePrefixName();
  3249. TQRegExp rx(quotePrefix);
  3250. s.remove(rx);
  3251. // now remove all remaining leading quotes
  3252. quotePrefix = '\n' + quotePrefixName();
  3253. rx = quotePrefix;
  3254. s.replace(rx, "\n");
  3255. return s;
  3256. }
  3257. void KMComposeWin::slotRemoveQuotes()
  3258. {
  3259. if( mEditor->hasFocus() && msg() )
  3260. {
  3261. // TODO: I think this is backwards.
  3262. // i.e, if no region is marked then remove quotes from every line
  3263. // else remove quotes only on the lines that are marked.
  3264. if ( mEditor->hasMarkedText() ) {
  3265. TQString s = mEditor->markedText();
  3266. mEditor->insert(removeQuotesFromText(s));
  3267. } else {
  3268. int l = mEditor->currentLine();
  3269. int c = mEditor->currentColumn();
  3270. TQString s = mEditor->textLine(l);
  3271. mEditor->insertLine(removeQuotesFromText(s),l);
  3272. mEditor->removeLine(l+1);
  3273. mEditor->setCursorPosition(l,c-2);
  3274. }
  3275. }
  3276. }
  3277. //-----------------------------------------------------------------------------
  3278. void KMComposeWin::slotUndo()
  3279. {
  3280. TQWidget* fw = focusWidget();
  3281. if (!fw) return;
  3282. if ( ::tqqt_cast<KEdit*>(fw) )
  3283. static_cast<TQTextEdit*>(fw)->undo();
  3284. else if (::tqqt_cast<TQLineEdit*>(fw))
  3285. static_cast<TQLineEdit*>(fw)->undo();
  3286. }
  3287. void KMComposeWin::slotRedo()
  3288. {
  3289. TQWidget* fw = focusWidget();
  3290. if (!fw) return;
  3291. if (::tqqt_cast<KEdit*>(fw))
  3292. static_cast<KEdit*>(fw)->redo();
  3293. else if (::tqqt_cast<TQLineEdit*>(fw))
  3294. static_cast<TQLineEdit*>(fw)->redo();
  3295. }
  3296. //-----------------------------------------------------------------------------
  3297. void KMComposeWin::slotCut()
  3298. {
  3299. TQWidget* fw = focusWidget();
  3300. if (!fw) return;
  3301. if (::tqqt_cast<KEdit*>(fw))
  3302. static_cast<KEdit*>(fw)->cut();
  3303. else if (::tqqt_cast<TQLineEdit*>(fw))
  3304. static_cast<TQLineEdit*>(fw)->cut();
  3305. }
  3306. //-----------------------------------------------------------------------------
  3307. void KMComposeWin::slotCopy()
  3308. {
  3309. TQWidget* fw = focusWidget();
  3310. if (!fw) return;
  3311. #ifdef KeyPress
  3312. #undef KeyPress
  3313. #endif
  3314. TQKeyEvent k(TQEvent::KeyPress, Key_C, 0, ControlButton);
  3315. kapp->notify(TQT_TQOBJECT(fw), TQT_TQEVENT(&k));
  3316. }
  3317. //-----------------------------------------------------------------------------
  3318. void KMComposeWin::slotPasteClipboard()
  3319. {
  3320. paste( TQClipboard::Clipboard );
  3321. }
  3322. void KMComposeWin::paste( TQClipboard::Mode mode )
  3323. {
  3324. TQWidget* fw = focusWidget();
  3325. if (!fw) return;
  3326. TQMimeSource *mimeSource = TQApplication::clipboard()->data( mode );
  3327. if ( mimeSource->provides("image/png") ) {
  3328. slotAttachPNGImageData(mimeSource->encodedData("image/png"));
  3329. } else if ( KURLDrag::canDecode( mimeSource ) ) {
  3330. KURL::List urlList;
  3331. if( KURLDrag::decode( mimeSource, urlList ) ) {
  3332. const TQString asText = i18n("Add as Text");
  3333. const TQString asAttachment = i18n("Add as Attachment");
  3334. const TQString text = i18n("Please select whether you want to insert the content as text into the editor, "
  3335. "or append the referenced file as an attachment.");
  3336. const TQString caption = i18n("Paste as text or attachment?");
  3337. int id = KMessageBox::questionYesNoCancel( this, text, caption,
  3338. KGuiItem( asText ), KGuiItem( asAttachment) );
  3339. switch ( id) {
  3340. case KMessageBox::Yes:
  3341. for ( KURL::List::Iterator it = urlList.begin();
  3342. it != urlList.end(); ++it ) {
  3343. mEditor->insert( (*it).url() );
  3344. }
  3345. break;
  3346. case KMessageBox::No:
  3347. for ( KURL::List::Iterator it = urlList.begin();
  3348. it != urlList.end(); ++it ) {
  3349. addAttach( *it );
  3350. }
  3351. break;
  3352. }
  3353. }
  3354. } else if ( TQTextDrag::canDecode( mimeSource ) ) {
  3355. TQString s;
  3356. if ( TQTextDrag::decode( mimeSource, s ) )
  3357. mEditor->insert( s );
  3358. }
  3359. }
  3360. //-----------------------------------------------------------------------------
  3361. void KMComposeWin::slotMarkAll()
  3362. {
  3363. TQWidget* fw = focusWidget();
  3364. if (!fw) return;
  3365. if (::tqqt_cast<TQLineEdit*>(fw))
  3366. static_cast<TQLineEdit*>(fw)->selectAll();
  3367. else if (::tqqt_cast<KEdit*>(fw))
  3368. static_cast<KEdit*>(fw)->selectAll();
  3369. }
  3370. //-----------------------------------------------------------------------------
  3371. void KMComposeWin::slotClose()
  3372. {
  3373. close(false);
  3374. }
  3375. //-----------------------------------------------------------------------------
  3376. void KMComposeWin::slotNewComposer()
  3377. {
  3378. KMComposeWin* win;
  3379. KMMessage* msg = new KMMessage;
  3380. msg->initHeader();
  3381. win = new KMComposeWin(msg);
  3382. win->show();
  3383. }
  3384. //-----------------------------------------------------------------------------
  3385. void KMComposeWin::slotNewMailReader()
  3386. {
  3387. KMMainWin *kmmwin = new KMMainWin(0);
  3388. kmmwin->show();
  3389. //d->resize(d->size());
  3390. }
  3391. //-----------------------------------------------------------------------------
  3392. void KMComposeWin::slotUpdWinTitle(const TQString& text)
  3393. {
  3394. TQString s( text );
  3395. // Remove characters that show badly in most window decorations:
  3396. // newlines tend to become boxes.
  3397. if (text.isEmpty())
  3398. setCaption("("+i18n("unnamed")+")");
  3399. else setCaption( s.replace( TQChar('\n'), ' ' ) );
  3400. }
  3401. //-----------------------------------------------------------------------------
  3402. void KMComposeWin::slotEncryptToggled(bool on)
  3403. {
  3404. setEncryption( on, true /* set by the user */ );
  3405. slotUpdateSignatureAndEncrypionStateIndicators();
  3406. }
  3407. //-----------------------------------------------------------------------------
  3408. void KMComposeWin::setEncryption( bool encrypt, bool setByUser )
  3409. {
  3410. bool wasModified = isModified();
  3411. if ( setByUser )
  3412. setModified( true );
  3413. if ( !mEncryptAction->isEnabled() )
  3414. encrypt = false;
  3415. // check if the user wants to encrypt messages to himself and if he defined
  3416. // an encryption key for the current identity
  3417. else if ( encrypt && encryptToSelf() && !mLastIdentityHasEncryptionKey ) {
  3418. if ( setByUser ) {
  3419. KMessageBox::sorry( this,
  3420. i18n("<qt><p>You have requested that messages be "
  3421. "encrypted to yourself, but the currently selected "
  3422. "identity does not define an (OpenPGP or S/MIME) "
  3423. "encryption key to use for this.</p>"
  3424. "<p>Please select the key(s) to use "
  3425. "in the identity configuration.</p>"
  3426. "</qt>"),
  3427. i18n("Undefined Encryption Key") );
  3428. setModified( wasModified );
  3429. }
  3430. encrypt = false;
  3431. }
  3432. // make sure the mEncryptAction is in the right state
  3433. mEncryptAction->setChecked( encrypt );
  3434. // show the appropriate icon
  3435. if ( encrypt )
  3436. mEncryptAction->setIcon("encrypted");
  3437. else
  3438. mEncryptAction->setIcon("decrypted");
  3439. // mark the attachments for (no) encryption
  3440. if ( canSignEncryptAttachments() ) {
  3441. for ( KMAtmListViewItem* entry =
  3442. static_cast<KMAtmListViewItem*>( mAtmItemList.first() );
  3443. entry;
  3444. entry = static_cast<KMAtmListViewItem*>( mAtmItemList.next() ) )
  3445. entry->setEncrypt( encrypt );
  3446. }
  3447. }
  3448. //-----------------------------------------------------------------------------
  3449. void KMComposeWin::slotSignToggled(bool on)
  3450. {
  3451. setSigning( on, true /* set by the user */ );
  3452. slotUpdateSignatureAndEncrypionStateIndicators();
  3453. }
  3454. //-----------------------------------------------------------------------------
  3455. void KMComposeWin::setSigning( bool sign, bool setByUser )
  3456. {
  3457. bool wasModified = isModified();
  3458. if ( setByUser )
  3459. setModified( true );
  3460. if ( !mSignAction->isEnabled() )
  3461. sign = false;
  3462. // check if the user defined a signing key for the current identity
  3463. if ( sign && !mLastIdentityHasSigningKey ) {
  3464. if ( setByUser ) {
  3465. KMessageBox::sorry( this,
  3466. i18n("<qt><p>In order to be able to sign "
  3467. "this message you first have to "
  3468. "define the (OpenPGP or S/MIME) signing key "
  3469. "to use.</p>"
  3470. "<p>Please select the key to use "
  3471. "in the identity configuration.</p>"
  3472. "</qt>"),
  3473. i18n("Undefined Signing Key") );
  3474. setModified( wasModified );
  3475. }
  3476. sign = false;
  3477. }
  3478. // make sure the mSignAction is in the right state
  3479. mSignAction->setChecked( sign );
  3480. // mark the attachments for (no) signing
  3481. if ( canSignEncryptAttachments() ) {
  3482. for ( KMAtmListViewItem* entry =
  3483. static_cast<KMAtmListViewItem*>( mAtmItemList.first() );
  3484. entry;
  3485. entry = static_cast<KMAtmListViewItem*>( mAtmItemList.next() ) )
  3486. entry->setSign( sign );
  3487. }
  3488. }
  3489. //-----------------------------------------------------------------------------
  3490. void KMComposeWin::slotWordWrapToggled(bool on)
  3491. {
  3492. if (on)
  3493. {
  3494. mEditor->setWordWrap( TQTextEdit::FixedColumnWidth );
  3495. mEditor->setWrapColumnOrWidth( GlobalSettings::self()->lineWrapWidth() );
  3496. }
  3497. else
  3498. {
  3499. mEditor->setWordWrap( TQTextEdit::WidgetWidth );
  3500. }
  3501. }
  3502. void KMComposeWin::disableWordWrap()
  3503. {
  3504. mEditor->setWordWrap( TQTextEdit::NoWrap );
  3505. }
  3506. void KMComposeWin::disableRecipientNumberCheck()
  3507. {
  3508. mCheckForRecipients = false;
  3509. }
  3510. void KMComposeWin::disableForgottenAttachmentsCheck()
  3511. {
  3512. mCheckForForgottenAttachments = false;
  3513. }
  3514. void KMComposeWin::ignoreStickyFields()
  3515. {
  3516. mIgnoreStickyFields = true;
  3517. mBtnTransport->setChecked( false );
  3518. mBtnDictionary->setChecked( false );
  3519. mBtnIdentity->setChecked( false );
  3520. mBtnTransport->setEnabled( false );
  3521. mBtnDictionary->setEnabled( false );
  3522. mBtnIdentity->setEnabled( false );
  3523. }
  3524. //-----------------------------------------------------------------------------
  3525. void KMComposeWin::slotPrint()
  3526. {
  3527. mMessageWasModified = isModified();
  3528. connect( this, TQT_SIGNAL( applyChangesDone( bool ) ),
  3529. TQT_TQOBJECT(this), TQT_SLOT( slotContinuePrint( bool ) ) );
  3530. applyChanges( true );
  3531. }
  3532. void KMComposeWin::slotContinuePrint( bool rc )
  3533. {
  3534. disconnect( this, TQT_SIGNAL( applyChangesDone( bool ) ),
  3535. TQT_TQOBJECT(this), TQT_SLOT( slotContinuePrint( bool ) ) );
  3536. if( rc ) {
  3537. if ( mComposedMessages.isEmpty() ) {
  3538. kdDebug(5006) << "Composing the message failed." << endl;
  3539. return;
  3540. }
  3541. KMCommand *command = new KMPrintCommand( this, mComposedMessages.first() );
  3542. command->start();
  3543. setModified( mMessageWasModified );
  3544. }
  3545. }
  3546. //----------------------------------------------------------------------------
  3547. bool KMComposeWin::validateAddresses( TQWidget * parent, const TQString & addresses )
  3548. {
  3549. TQString brokenAddress;
  3550. KPIM::EmailParseResult errorCode = KMMessage::isValidEmailAddressList( KMMessage::expandAliases( addresses ), brokenAddress );
  3551. if ( !( errorCode == KPIM::AddressOk || errorCode == KPIM::AddressEmpty ) ) {
  3552. TQString errorMsg( "<qt><p><b>" + brokenAddress +
  3553. "</b></p><p>" + KPIM::emailParseResultToString( errorCode ) +
  3554. "</p></qt>" );
  3555. KMessageBox::sorry( parent, errorMsg, i18n("Invalid Email Address") );
  3556. return false;
  3557. }
  3558. return true;
  3559. }
  3560. //----------------------------------------------------------------------------
  3561. void KMComposeWin::doSend( KMail::MessageSender::SendMethod method,
  3562. KMComposeWin::SaveIn saveIn )
  3563. {
  3564. if ( method != KMail::MessageSender::SendLater && kmkernel->isOffline() ) {
  3565. KMessageBox::information( this,
  3566. i18n("KMail is currently in offline mode,"
  3567. "your messages will be kept in the outbox until you go online."),
  3568. i18n("Online/Offline"), "kmailIsOffline" );
  3569. mSendMethod = KMail::MessageSender::SendLater;
  3570. } else {
  3571. mSendMethod = method;
  3572. }
  3573. mSaveIn = saveIn;
  3574. if ( saveIn == KMComposeWin::None ) {
  3575. if ( KPIM::getFirstEmailAddress( from() ).isEmpty() ) {
  3576. if ( !( mShowHeaders & HDR_FROM ) ) {
  3577. mShowHeaders |= HDR_FROM;
  3578. rethinkFields( false );
  3579. }
  3580. mEdtFrom->setFocus();
  3581. KMessageBox::sorry( this,
  3582. i18n("You must enter your email address in the "
  3583. "From: field. You should also set your email "
  3584. "address for all identities, so that you do "
  3585. "not have to enter it for each message.") );
  3586. return;
  3587. }
  3588. if ( to().isEmpty() )
  3589. {
  3590. if ( cc().isEmpty() && bcc().isEmpty()) {
  3591. if ( mEdtTo ) mEdtTo->setFocus();
  3592. KMessageBox::information( this,
  3593. i18n("You must specify at least one receiver,"
  3594. "either in the To: field or as CC or as BCC.") );
  3595. return;
  3596. }
  3597. else {
  3598. if ( mEdtTo ) mEdtTo->setFocus();
  3599. int rc =
  3600. KMessageBox::questionYesNo( this,
  3601. i18n("To field is missing."
  3602. "Send message anyway?"),
  3603. i18n("No To: specified") );
  3604. if ( rc == KMessageBox::No ){
  3605. return;
  3606. }
  3607. }
  3608. }
  3609. // Validate the To:, CC: and BCC fields
  3610. if ( !validateAddresses( this, to().stripWhiteSpace() ) ) {
  3611. return;
  3612. }
  3613. if ( !validateAddresses( this, cc().stripWhiteSpace() ) ) {
  3614. return;
  3615. }
  3616. if ( !validateAddresses( this, bcc().stripWhiteSpace() ) ) {
  3617. return;
  3618. }
  3619. if (subject().isEmpty())
  3620. {
  3621. mEdtSubject->setFocus();
  3622. int rc =
  3623. KMessageBox::questionYesNo( this,
  3624. i18n("You did not specify a subject. "
  3625. "Send message anyway?"),
  3626. i18n("No Subject Specified"),
  3627. i18n("S&end as Is"),
  3628. i18n("&Specify the Subject"),
  3629. "no_subject_specified" );
  3630. if( rc == KMessageBox::No )
  3631. {
  3632. return;
  3633. }
  3634. }
  3635. if ( userForgotAttachment() )
  3636. return;
  3637. }
  3638. KCursorSaver busy(KBusyPtr::busy());
  3639. mMsg->setDateToday();
  3640. // If a user sets up their outgoing messages preferences wrong and then
  3641. // sends mail that gets 'stuck' in their outbox, they should be able to
  3642. // rectify the problem by editing their outgoing preferences and
  3643. // resending.
  3644. // Hence this following conditional
  3645. TQString hf = mMsg->headerField("X-KMail-Transport");
  3646. if ((mTransport->currentText() != mTransport->text(0)) ||
  3647. (!hf.isEmpty() && (hf != mTransport->text(0))))
  3648. mMsg->setHeaderField("X-KMail-Transport", mTransport->currentText());
  3649. mDisableBreaking = ( saveIn != KMComposeWin::None );
  3650. const bool neverEncrypt = ( mDisableBreaking && GlobalSettings::self()->neverEncryptDrafts() )
  3651. || mSigningAndEncryptionExplicitlyDisabled;
  3652. connect( this, TQT_SIGNAL( applyChangesDone( bool ) ),
  3653. TQT_SLOT( slotContinueDoSend( bool ) ) );
  3654. if ( mEditor->textFormat() == TQt::RichText )
  3655. mMsg->setHeaderField( "X-KMail-Markup", "true" );
  3656. else
  3657. mMsg->removeHeaderField( "X-KMail-Markup" );
  3658. if ( mEditor->textFormat() == TQt::RichText && inlineSigningEncryptionSelected() ) {
  3659. TQString keepBtnText = mEncryptAction->isChecked() ?
  3660. mSignAction->isChecked() ? i18n( "&Keep markup, do not sign/encrypt" )
  3661. : i18n( "&Keep markup, do not encrypt" )
  3662. : i18n( "&Keep markup, do not sign" );
  3663. TQString yesBtnText = mEncryptAction->isChecked() ?
  3664. mSignAction->isChecked() ? i18n("Sign/Encrypt (delete markup)")
  3665. : i18n( "Encrypt (delete markup)" )
  3666. : i18n( "Sign (delete markup)" );
  3667. int ret = KMessageBox::warningYesNoCancel(this,
  3668. i18n("<qt><p>Inline signing/encrypting of HTML messages is not possible;</p>"
  3669. "<p>do you want to delete your markup?</p></qt>"),
  3670. i18n("Sign/Encrypt Message?"),
  3671. KGuiItem( yesBtnText ),
  3672. KGuiItem( keepBtnText ) );
  3673. if ( KMessageBox::Cancel == ret )
  3674. return;
  3675. if ( KMessageBox::No == ret ) {
  3676. mEncryptAction->setChecked(false);
  3677. mSignAction->setChecked(false);
  3678. }
  3679. else {
  3680. toggleMarkup(false);
  3681. }
  3682. }
  3683. if (neverEncrypt && saveIn != KMComposeWin::None ) {
  3684. // we can't use the state of the mail itself, to remember the
  3685. // signing and encryption state, so let's add a header instead
  3686. mMsg->setHeaderField( "X-KMail-SignatureActionEnabled", mSignAction->isChecked()? "true":"false" );
  3687. mMsg->setHeaderField( "X-KMail-EncryptActionEnabled", mEncryptAction->isChecked()? "true":"false" );
  3688. mMsg->setHeaderField( "X-KMail-CryptoMessageFormat", TQString::number( cryptoMessageFormat() ) );
  3689. } else {
  3690. mMsg->removeHeaderField( "X-KMail-SignatureActionEnabled" );
  3691. mMsg->removeHeaderField( "X-KMail-EncryptActionEnabled" );
  3692. mMsg->removeHeaderField( "X-KMail-CryptoMessageFormat" );
  3693. }
  3694. kdDebug(5006) << "KMComposeWin::doSend() - calling applyChanges()"
  3695. << endl;
  3696. applyChanges( neverEncrypt );
  3697. }
  3698. bool KMComposeWin::saveDraftOrTemplate( const TQString &folderName,
  3699. KMMessage *msg )
  3700. {
  3701. KMFolder *theFolder = 0, *imapTheFolder = 0;
  3702. // get the draftsFolder
  3703. if ( !folderName.isEmpty() ) {
  3704. theFolder = kmkernel->folderMgr()->findIdString( folderName );
  3705. if ( theFolder == 0 )
  3706. // This is *NOT* supposed to be "imapDraftsFolder", because a
  3707. // dIMAP folder works like a normal folder
  3708. theFolder = kmkernel->dimapFolderMgr()->findIdString( folderName );
  3709. if ( theFolder == 0 )
  3710. imapTheFolder = kmkernel->imapFolderMgr()->findIdString( folderName );
  3711. if ( !theFolder && !imapTheFolder ) {
  3712. const KPIM::Identity & id = kmkernel->identityManager()
  3713. ->identityForUoidOrDefault( msg->headerField( "X-KMail-Identity" ).stripWhiteSpace().toUInt() );
  3714. KMessageBox::information( 0,
  3715. i18n("The custom drafts or templates folder for "
  3716. "identify \"%1\" does not exist (anymore); "
  3717. "therefore, the default drafts or templates "
  3718. "folder will be used.")
  3719. .arg( id.identityName() ) );
  3720. }
  3721. }
  3722. if ( imapTheFolder && imapTheFolder->noContent() )
  3723. imapTheFolder = 0;
  3724. bool didOpen = false;
  3725. if ( theFolder == 0 ) {
  3726. theFolder = ( mSaveIn==KMComposeWin::Drafts ?
  3727. kmkernel->draftsFolder() : kmkernel->templatesFolder() );
  3728. } else {
  3729. //XXX this looks really, really fishy
  3730. theFolder->open( "composer" );
  3731. didOpen = true;
  3732. }
  3733. kdDebug(5006) << k_funcinfo << "theFolder=" << theFolder->name() << endl;
  3734. if ( imapTheFolder )
  3735. kdDebug(5006) << k_funcinfo << "imapTheFolder=" << imapTheFolder->name() << endl;
  3736. bool sentOk = !( theFolder->addMsg( msg ) );
  3737. // Ensure the message is correctly and fully parsed
  3738. theFolder->unGetMsg( theFolder->count() - 1 );
  3739. msg = theFolder->getMsg( theFolder->count() - 1 );
  3740. // Does that assignment needs to be propagated out to the caller?
  3741. // Assuming the send is OK, the iterator is set to 0 immediately afterwards.
  3742. if ( imapTheFolder ) {
  3743. // move the message to the imap-folder and highlight it
  3744. imapTheFolder->moveMsg( msg );
  3745. (static_cast<KMFolderImap*>( imapTheFolder->storage() ))->getFolder();
  3746. }
  3747. if ( didOpen )
  3748. theFolder->close( "composer" );
  3749. return sentOk;
  3750. }
  3751. void KMComposeWin::slotContinueDoSend( bool sentOk )
  3752. {
  3753. kdDebug(5006) << "KMComposeWin::slotContinueDoSend( " << sentOk << " )"
  3754. << endl;
  3755. disconnect( this, TQT_SIGNAL( applyChangesDone( bool ) ),
  3756. TQT_TQOBJECT(this), TQT_SLOT( slotContinueDoSend( bool ) ) );
  3757. if ( !sentOk ) {
  3758. mDisableBreaking = false;
  3759. return;
  3760. }
  3761. for ( TQValueVector<KMMessage*>::iterator it = mComposedMessages.begin() ; it != mComposedMessages.end() ; ++it ) {
  3762. // remove fields that contain no data (e.g. an empty Cc: or Bcc:)
  3763. (*it)->cleanupHeader();
  3764. // needed for imap
  3765. (*it)->setComplete( true );
  3766. if ( mSaveIn==KMComposeWin::Drafts ) {
  3767. sentOk = saveDraftOrTemplate( (*it)->drafts(), (*it) );
  3768. } else if ( mSaveIn==KMComposeWin::Templates ) {
  3769. sentOk = saveDraftOrTemplate( (*it)->templates(), (*it) );
  3770. } else {
  3771. (*it)->setTo( KMMessage::expandAliases( to() ));
  3772. (*it)->setCc( KMMessage::expandAliases( cc() ));
  3773. if( !mComposer->originalBCC().isEmpty() )
  3774. (*it)->setBcc( KMMessage::expandAliases( mComposer->originalBCC() ));
  3775. TQString recips = (*it)->headerField( "X-KMail-Recipients" );
  3776. if( !recips.isEmpty() ) {
  3777. (*it)->setHeaderField( "X-KMail-Recipients", KMMessage::expandAliases( recips ), KMMessage::Address );
  3778. }
  3779. (*it)->cleanupHeader();
  3780. sentOk = kmkernel->msgSender()->send((*it), mSendMethod);
  3781. }
  3782. if (!sentOk)
  3783. return;
  3784. *it = 0; // don't kill it later...
  3785. }
  3786. RecentAddresses::self( KMKernel::config() )->add( bcc() );
  3787. RecentAddresses::self( KMKernel::config() )->add( cc() );
  3788. RecentAddresses::self( KMKernel::config() )->add( to() );
  3789. setModified( false );
  3790. mAutoDeleteMsg = false;
  3791. mFolder = 0;
  3792. cleanupAutoSave();
  3793. close();
  3794. return;
  3795. }
  3796. bool KMComposeWin::checkTransport() const
  3797. {
  3798. if ( KMail::TransportManager::transportNames().isEmpty() ) {
  3799. KMessageBox::information( mMainWidget,
  3800. i18n("Please create an account for sending and try again.") );
  3801. return false;
  3802. }
  3803. return true;
  3804. }
  3805. //----------------------------------------------------------------------------
  3806. void KMComposeWin::slotSendLater()
  3807. {
  3808. if ( !checkTransport() )
  3809. return;
  3810. if ( !checkRecipientNumber() )
  3811. return;
  3812. if ( mEditor->checkExternalEditorFinished() )
  3813. doSend( KMail::MessageSender::SendLater );
  3814. }
  3815. //----------------------------------------------------------------------------
  3816. void KMComposeWin::slotSaveDraft() {
  3817. if ( mEditor->checkExternalEditorFinished() )
  3818. doSend( KMail::MessageSender::SendLater, KMComposeWin::Drafts );
  3819. }
  3820. //----------------------------------------------------------------------------
  3821. void KMComposeWin::slotSaveTemplate() {
  3822. if ( mEditor->checkExternalEditorFinished() )
  3823. doSend( KMail::MessageSender::SendLater, KMComposeWin::Templates );
  3824. }
  3825. //----------------------------------------------------------------------------
  3826. void KMComposeWin::slotSendNowVia( int item )
  3827. {
  3828. TQStringList availTransports= KMail::TransportManager::transportNames();
  3829. TQString customTransport = availTransports[ item ];
  3830. mTransport->setCurrentText( customTransport );
  3831. slotSendNow();
  3832. }
  3833. //----------------------------------------------------------------------------
  3834. void KMComposeWin::slotSendLaterVia( int item )
  3835. {
  3836. TQStringList availTransports= KMail::TransportManager::transportNames();
  3837. TQString customTransport = availTransports[ item ];
  3838. mTransport->setCurrentText( customTransport );
  3839. slotSendLater();
  3840. }
  3841. //----------------------------------------------------------------------------
  3842. void KMComposeWin::slotSendNow() {
  3843. if ( !mEditor->checkExternalEditorFinished() )
  3844. return;
  3845. if ( !checkTransport() )
  3846. return;
  3847. if ( !checkRecipientNumber() )
  3848. return;
  3849. if ( GlobalSettings::self()->confirmBeforeSend() )
  3850. {
  3851. int rc = KMessageBox::warningYesNoCancel( mMainWidget,
  3852. i18n("About to send email..."),
  3853. i18n("Send Confirmation"),
  3854. i18n("&Send Now"),
  3855. i18n("Send &Later") );
  3856. if ( rc == KMessageBox::Yes )
  3857. doSend( KMail::MessageSender::SendImmediate );
  3858. else if ( rc == KMessageBox::No )
  3859. doSend( KMail::MessageSender::SendLater );
  3860. }
  3861. else
  3862. doSend( KMail::MessageSender::SendImmediate );
  3863. }
  3864. //----------------------------------------------------------------------------
  3865. bool KMComposeWin::checkRecipientNumber() const
  3866. {
  3867. uint thresHold = GlobalSettings::self()->recipientThreshold();
  3868. if ( mCheckForRecipients &&
  3869. GlobalSettings::self()->tooManyRecipients() &&
  3870. mRecipientsEditor->recipients().count() > thresHold ) {
  3871. if ( KMessageBox::questionYesNo( mMainWidget,
  3872. i18n("You are trying to send the mail to more than %1 recipients. Send message anyway?").arg(thresHold),
  3873. i18n("Too many receipients"),
  3874. i18n("&Send as Is"),
  3875. i18n("&Edit Recipients")) == KMessageBox::No ) {
  3876. return false;
  3877. }
  3878. }
  3879. return true;
  3880. }
  3881. //----------------------------------------------------------------------------
  3882. void KMComposeWin::slotAppendSignature()
  3883. {
  3884. insertSignature();
  3885. }
  3886. //----------------------------------------------------------------------------
  3887. void KMComposeWin::slotPrependSignature()
  3888. {
  3889. insertSignature( Prepend );
  3890. }
  3891. //----------------------------------------------------------------------------
  3892. void KMComposeWin::slotInsertSignatureAtCursor()
  3893. {
  3894. insertSignature( AtCursor );
  3895. }
  3896. //----------------------------------------------------------------------------
  3897. void KMComposeWin::insertSignature( SignaturePlacement placement )
  3898. {
  3899. bool mod = mEditor->isModified();
  3900. const KPIM::Identity &ident =
  3901. kmkernel->identityManager()->
  3902. identityForUoidOrDefault( mIdentity->currentIdentity() );
  3903. mOldSigText = GlobalSettings::self()->prependSignature()? ident.signature().rawText() : ident.signatureText();
  3904. if( !mOldSigText.isEmpty() )
  3905. {
  3906. mEditor->sync();
  3907. int paragraph, index;
  3908. mEditor->getCursorPosition( &paragraph, &index );
  3909. index = mEditor->indexOfCurrentLineStart( paragraph, index );
  3910. switch( placement ) {
  3911. case Append:
  3912. mEditor->setText( mEditor->text() + mOldSigText );
  3913. break;
  3914. case Prepend:
  3915. mOldSigText = "\n\n" + mOldSigText + "\n";
  3916. mEditor->insertAt( mOldSigText, paragraph, index );
  3917. break;
  3918. case AtCursor:
  3919. // If there is text in the same line, add a newline so that the stuff in
  3920. // the current line moves after the signature. Also remove a leading newline, it is not
  3921. // needed here.
  3922. if ( mEditor->paragraphLength( paragraph ) > 0 )
  3923. mOldSigText = mOldSigText + "\n";
  3924. if ( mOldSigText.startsWith( "\n" ) )
  3925. mOldSigText = mOldSigText.remove( 0, 1 );
  3926. // If we are inserting into a wordwrapped line, add a newline at the start to make
  3927. // the text edit hard-wrap the line here
  3928. if ( index != 0 )
  3929. mOldSigText = "\n" + mOldSigText;
  3930. mEditor->insertAt( mOldSigText, paragraph, index );
  3931. break;
  3932. }
  3933. mEditor->update();
  3934. mEditor->setModified(mod);
  3935. if ( mPreserveUserCursorPosition ) {
  3936. mEditor->setCursorPositionFromStart( (unsigned int) mMsg->getCursorPos() );
  3937. // Only keep the cursor from the mMsg *once* based on the
  3938. // preserve-cursor-position setting; this handles the case where
  3939. // the message comes from a template with a specific cursor
  3940. // position set and the signature is appended automatically.
  3941. mPreserveUserCursorPosition = false;
  3942. } else {
  3943. // for append and prepend, move the cursor to 0,0, for insertAt,
  3944. // keep it in the same row, but move to first column
  3945. if ( index == 0 ) {
  3946. mEditor->setCursorPosition( paragraph, 0 );
  3947. } else {
  3948. // For word-wrapped lines, we have created a new paragraph, so change to that one
  3949. mEditor->setCursorPosition( paragraph + 1, 0 );
  3950. }
  3951. if ( placement == Prepend || placement == Append )
  3952. mEditor->setContentsPos( 0, 0 );
  3953. }
  3954. mEditor->sync();
  3955. }
  3956. }
  3957. //-----------------------------------------------------------------------------
  3958. void KMComposeWin::slotHelp()
  3959. {
  3960. kapp->invokeHelp();
  3961. }
  3962. //-----------------------------------------------------------------------------
  3963. void KMComposeWin::slotCleanSpace()
  3964. {
  3965. // Originally we simply used the KEdit::cleanWhiteSpace() method,
  3966. // but that code doesn't handle quoted-lines or signatures, so instead
  3967. // we now simply use regexp's to squeeze sequences of tabs and spaces
  3968. // into a single space, and make sure all our lines are single-spaced.
  3969. //
  3970. // Yes, extra space in a quote string is squeezed.
  3971. // Signatures are respected (i.e. not cleaned).
  3972. TQString s;
  3973. if ( mEditor->hasMarkedText() ) {
  3974. s = mEditor->markedText();
  3975. if( s.isEmpty() )
  3976. return;
  3977. } else {
  3978. s = mEditor->text();
  3979. }
  3980. // Remove the signature for now.
  3981. TQString sig;
  3982. bool restore = false;
  3983. const KPIM::Identity & ident =
  3984. kmkernel->identityManager()->identityForUoid( mId );
  3985. if ( !ident.isNull() ) {
  3986. sig = ident.signatureText();
  3987. if( !sig.isEmpty() ) {
  3988. if( s.endsWith( sig ) ) {
  3989. s.truncate( s.length() - sig.length() );
  3990. restore = true;
  3991. }
  3992. }
  3993. }
  3994. // Squeeze tabs and spaces
  3995. TQRegExp squeeze( "[\t ]+" );
  3996. s.replace( squeeze, TQChar( ' ' ) );
  3997. // Remove trailing whitespace
  3998. TQRegExp trailing( "\\s+$" );
  3999. s.replace( trailing, TQChar( '\n' ) );
  4000. // Single space lines
  4001. TQRegExp singleSpace( "[\n]{2,}" );
  4002. s.replace( singleSpace, TQChar( '\n' ) );
  4003. // Restore the signature
  4004. if ( restore )
  4005. s.append( sig );
  4006. // Put the new text in place.
  4007. // The lines below do not clear the undo history, but unfortuately cause
  4008. // the side-effect that you need to press Ctrl-Z twice (first Ctrl-Z will
  4009. // show cleared text area) to get back the original, pre-cleaned text.
  4010. // If you use mEditor->setText( s ) then the undo history is cleared so
  4011. // that isn't a good solution either.
  4012. // TODO: is TQt4 better at handling the undo history??
  4013. if ( !mEditor->hasMarkedText() )
  4014. mEditor->clear();
  4015. mEditor->insert( s );
  4016. }
  4017. //-----------------------------------------------------------------------------
  4018. void KMComposeWin::slotToggleMarkup()
  4019. {
  4020. if ( markupAction->isChecked() ) {
  4021. mHtmlMarkup = true;
  4022. toolBar("htmlToolBar")->show();
  4023. // markup will be toggled as soon as markup is actually used
  4024. fontChanged( mEditor->currentFont() ); // set buttons in correct position
  4025. mSaveFont = mEditor->currentFont();
  4026. }
  4027. else
  4028. toggleMarkup(false);
  4029. }
  4030. //-----------------------------------------------------------------------------
  4031. void KMComposeWin::toggleMarkup(bool markup)
  4032. {
  4033. if ( markup ) {
  4034. if ( !mUseHTMLEditor ) {
  4035. kdDebug(5006) << "setting RichText editor" << endl;
  4036. mUseHTMLEditor = true; // set it directly to true. setColor hits another toggleMarkup
  4037. mHtmlMarkup = true;
  4038. // set all highlighted text caused by spelling back to black
  4039. int paraFrom, indexFrom, paraTo, indexTo;
  4040. mEditor->getSelection ( &paraFrom, &indexFrom, &paraTo, &indexTo);
  4041. mEditor->selectAll();
  4042. // save the buttonstates because setColor calls fontChanged
  4043. bool _bold = textBoldAction->isChecked();
  4044. bool _italic = textItalicAction->isChecked();
  4045. mEditor->setColor(TQColor(0,0,0));
  4046. textBoldAction->setChecked(_bold);
  4047. textItalicAction->setChecked(_italic);
  4048. mEditor->setSelection ( paraFrom, indexFrom, paraTo, indexTo);
  4049. mEditor->setTextFormat(TQt::RichText);
  4050. mEditor->setModified(true);
  4051. markupAction->setChecked(true);
  4052. toolBar( "htmlToolBar" )->show();
  4053. mEditor->deleteAutoSpellChecking();
  4054. mAutoSpellCheckingAction->setChecked(false);
  4055. slotAutoSpellCheckingToggled(false);
  4056. }
  4057. } else { // markup is to be turned off
  4058. kdDebug(5006) << "setting PlainText editor" << endl;
  4059. mHtmlMarkup = false;
  4060. toolBar("htmlToolBar")->hide();
  4061. if ( mUseHTMLEditor ) { // it was turned on
  4062. mUseHTMLEditor = false;
  4063. mEditor->setTextFormat(TQt::PlainText);
  4064. TQString text = mEditor->text();
  4065. mEditor->setText(text); // otherwise the text still looks formatted
  4066. mEditor->setModified(true);
  4067. slotAutoSpellCheckingToggled(true);
  4068. }
  4069. }
  4070. }
  4071. void KMComposeWin::htmlToolBarVisibilityChanged( bool visible )
  4072. {
  4073. // disable markup if the user hides the HTML toolbar
  4074. if ( !visible ) {
  4075. markupAction->setChecked( false );
  4076. toggleMarkup( false );
  4077. }
  4078. }
  4079. void KMComposeWin::slotSubjectTextSpellChecked()
  4080. {
  4081. mSubjectTextWasSpellChecked = true;
  4082. }
  4083. //-----------------------------------------------------------------------------
  4084. void KMComposeWin::slotAutoSpellCheckingToggled( bool on )
  4085. {
  4086. if ( mEditor->autoSpellChecking(on) == -1 ) {
  4087. mAutoSpellCheckingAction->setChecked(false); // set it to false again
  4088. }
  4089. TQString temp;
  4090. if ( on )
  4091. temp = i18n( "Spellcheck: on" );
  4092. else
  4093. temp = i18n( "Spellcheck: off" );
  4094. statusBar()->changeItem( temp, 3 );
  4095. }
  4096. //-----------------------------------------------------------------------------
  4097. void KMComposeWin::slotSpellcheck()
  4098. {
  4099. if (mSpellCheckInProgress) return;
  4100. mSubjectTextWasSpellChecked = false;
  4101. mSpellCheckInProgress=true;
  4102. /*
  4103. connect (mEditor, TQT_SIGNAL (spellcheck_progress (unsigned)),
  4104. this, TQT_SLOT (spell_progress (unsigned)));
  4105. */
  4106. mEditor->spellcheck();
  4107. }
  4108. //-----------------------------------------------------------------------------
  4109. void KMComposeWin::slotUpdateSignatureActions()
  4110. {
  4111. //Check if an identity has signature or not and turn on/off actions in the
  4112. //edit menu accordingly.
  4113. const KPIM::Identity & ident =
  4114. kmkernel->identityManager()->identityForUoidOrDefault( mIdentity->currentIdentity() );
  4115. TQString sig = ident.signatureText();
  4116. if ( sig.isEmpty() ) {
  4117. mAppendSignatureAction->setEnabled( false );
  4118. mPrependSignatureAction->setEnabled( false );
  4119. mInsertSignatureAction->setEnabled( false );
  4120. }
  4121. else {
  4122. mAppendSignatureAction->setEnabled( true );
  4123. mPrependSignatureAction->setEnabled( true );
  4124. mInsertSignatureAction->setEnabled( true );
  4125. }
  4126. }
  4127. void KMComposeWin::polish()
  4128. {
  4129. // Ensure the html toolbar is appropriately shown/hidden
  4130. markupAction->setChecked(mHtmlMarkup);
  4131. if (mHtmlMarkup)
  4132. toolBar("htmlToolBar")->show();
  4133. else
  4134. toolBar("htmlToolBar")->hide();
  4135. KMail::Composer::polish();
  4136. }
  4137. //-----------------------------------------------------------------------------
  4138. void KMComposeWin::slotSpellcheckDone(int result)
  4139. {
  4140. kdDebug(5006) << "spell check complete: result = " << result << endl;
  4141. mSpellCheckInProgress=false;
  4142. switch( result )
  4143. {
  4144. case KS_CANCEL:
  4145. statusBar()->changeItem(i18n(" Spell check canceled."),0);
  4146. break;
  4147. case KS_STOP:
  4148. statusBar()->changeItem(i18n(" Spell check stopped."),0);
  4149. break;
  4150. default:
  4151. statusBar()->changeItem(i18n(" Spell check complete."),0);
  4152. break;
  4153. }
  4154. TQTimer::singleShot( 2000, this, TQT_SLOT(slotSpellcheckDoneClearStatus()) );
  4155. }
  4156. void KMComposeWin::slotSpellcheckDoneClearStatus()
  4157. {
  4158. statusBar()->changeItem("", 0);
  4159. }
  4160. //-----------------------------------------------------------------------------
  4161. void KMComposeWin::slotIdentityChanged( uint uoid )
  4162. {
  4163. const KPIM::Identity & ident =
  4164. kmkernel->identityManager()->identityForUoid( uoid );
  4165. if( ident.isNull() ) return;
  4166. //Turn on/off signature actions if identity has no signature.
  4167. slotUpdateSignatureActions();
  4168. if( !ident.fullEmailAddr().isNull() )
  4169. mEdtFrom->setText(ident.fullEmailAddr());
  4170. // make sure the From field is shown if it does not contain a valid email address
  4171. if ( KPIM::getFirstEmailAddress( from() ).isEmpty() )
  4172. mShowHeaders |= HDR_FROM;
  4173. if ( mEdtReplyTo ) mEdtReplyTo->setText(ident.replyToAddr());
  4174. if ( mRecipientsEditor ) {
  4175. // remove BCC of old identity and add BCC of new identity (if they differ)
  4176. const KPIM::Identity & oldIdentity =
  4177. kmkernel->identityManager()->identityForUoidOrDefault( mId );
  4178. if ( oldIdentity.bcc() != ident.bcc() ) {
  4179. mRecipientsEditor->removeRecipient( oldIdentity.bcc(), Recipient::Bcc );
  4180. mRecipientsEditor->addRecipient( ident.bcc(), Recipient::Bcc );
  4181. mRecipientsEditor->setFocusBottom();
  4182. }
  4183. }
  4184. // don't overwrite the BCC field under certain circomstances
  4185. // NOT edited and preset BCC from the identity
  4186. if( mEdtBcc && !mEdtBcc->edited() && !ident.bcc().isEmpty() ) {
  4187. // BCC NOT empty AND contains a diff adress then the preset BCC
  4188. // of the new identity
  4189. if( !mEdtBcc->text().isEmpty() && mEdtBcc->text() != ident.bcc() && !mEdtBcc->edited() ) {
  4190. mEdtBcc->setText( ident.bcc() );
  4191. } else {
  4192. // user type into the editbox an address that != to the preset bcc
  4193. // of the identity, we assume that since the user typed it
  4194. // they want to keep it
  4195. if ( mEdtBcc->text() != ident.bcc() && !mEdtBcc->text().isEmpty() ) {
  4196. TQString temp_string( mEdtBcc->text() + TQString::fromLatin1(",") + ident.bcc() );
  4197. mEdtBcc->setText( temp_string );
  4198. } else {
  4199. // if the user typed the same address as the preset BCC
  4200. // from the identity we will overwrite it to avoid duplicates.
  4201. mEdtBcc->setText( ident.bcc() );
  4202. }
  4203. }
  4204. }
  4205. // user edited the bcc box and has a preset bcc in the identity
  4206. // we will append whatever the user typed to the preset address
  4207. // allowing the user to keep all addresses
  4208. if( mEdtBcc && mEdtBcc->edited() && !ident.bcc().isEmpty() ) {
  4209. if( !mEdtBcc->text().isEmpty() ) {
  4210. TQString temp_string ( mEdtBcc->text() + TQString::fromLatin1(",") + ident.bcc() );
  4211. mEdtBcc->setText( temp_string );
  4212. } else {
  4213. mEdtBcc->setText( ident.bcc() );
  4214. }
  4215. }
  4216. // user typed nothing and the identity does not have a preset bcc
  4217. // we then reset the value to get rid of any previous
  4218. // values if the user changed identity mid way through.
  4219. if( mEdtBcc && !mEdtBcc->edited() && ident.bcc().isEmpty() ) {
  4220. mEdtBcc->setText( ident.bcc() );
  4221. }
  4222. // make sure the BCC field is shown because else it's ignored
  4223. if ( !ident.bcc().isEmpty() ) {
  4224. mShowHeaders |= HDR_BCC;
  4225. }
  4226. if ( ident.organization().isEmpty() )
  4227. mMsg->removeHeaderField("Organization");
  4228. else
  4229. mMsg->setHeaderField("Organization", ident.organization());
  4230. if (!ident.isXFaceEnabled() || ident.xface().isEmpty())
  4231. mMsg->removeHeaderField("X-Face");
  4232. else
  4233. {
  4234. TQString xface = ident.xface();
  4235. if (!xface.isEmpty())
  4236. {
  4237. int numNL = ( xface.length() - 1 ) / 70;
  4238. for ( int i = numNL; i > 0; --i )
  4239. xface.insert( i*70, "\n\t" );
  4240. mMsg->setHeaderField("X-Face", xface);
  4241. }
  4242. }
  4243. if ( !mBtnTransport->isChecked() && !mIgnoreStickyFields ) {
  4244. TQString transp = ident.transport();
  4245. if ( transp.isEmpty() )
  4246. {
  4247. mMsg->removeHeaderField("X-KMail-Transport");
  4248. transp = GlobalSettings::self()->defaultTransport();
  4249. }
  4250. else
  4251. mMsg->setHeaderField("X-KMail-Transport", transp);
  4252. setTransport( transp );
  4253. }
  4254. if ( !mBtnDictionary->isChecked() && !mIgnoreStickyFields ) {
  4255. mDictionaryCombo->setCurrentByDictionary( ident.dictionary() );
  4256. }
  4257. if ( !mBtnFcc->isChecked() && !mPreventFccOverwrite ) {
  4258. setFcc( ident.fcc() );
  4259. }
  4260. TQString edtText = mEditor->text();
  4261. if ( mOldSigText.isEmpty() ) {
  4262. const KPIM::Identity &id =
  4263. kmkernel->
  4264. identityManager()->
  4265. identityForUoidOrDefault( mMsg->headerField( "X-KMail-Identity" ).
  4266. stripWhiteSpace().toUInt() );
  4267. mOldSigText = GlobalSettings::self()->prependSignature() ? id.signature().rawText() : id.signatureText();
  4268. }
  4269. if ( !GlobalSettings::prependSignature() ) {
  4270. // try to truncate the old sig
  4271. // First remove any trailing whitespace
  4272. while ( !edtText.isEmpty() && edtText[edtText.length()-1].isSpace() )
  4273. edtText.truncate( edtText.length() - 1 );
  4274. // From the sig too, just in case
  4275. while ( !mOldSigText.isEmpty() && mOldSigText[mOldSigText.length()-1].isSpace() )
  4276. mOldSigText.truncate( mOldSigText.length() - 1 );
  4277. if ( edtText.endsWith( mOldSigText ) )
  4278. edtText.truncate( edtText.length() - mOldSigText.length() );
  4279. // now append the new sig
  4280. mOldSigText = ident.signatureText();
  4281. if( ( !mOldSigText.isEmpty() ) &&
  4282. ( GlobalSettings::self()->autoTextSignature() == "auto" ) ) {
  4283. edtText.append( mOldSigText );
  4284. }
  4285. mEditor->setText( edtText );
  4286. } else {
  4287. const int pos = edtText.find( mOldSigText );
  4288. if ( pos >= 0 && !mOldSigText.isEmpty() ) {
  4289. const int oldLength = mOldSigText.length();
  4290. mOldSigText = "\n\n"+ ident.signature().rawText() + "\n"; // see insertSignature()
  4291. edtText = edtText.replace( pos, oldLength, mOldSigText );
  4292. mEditor->setText( edtText );
  4293. } else {
  4294. insertSignature( Append );
  4295. }
  4296. }
  4297. // disable certain actions if there is no PGP user identity set
  4298. // for this profile
  4299. bool bNewIdentityHasSigningKey = !ident.pgpSigningKey().isEmpty() || !ident.smimeSigningKey().isEmpty();
  4300. bool bNewIdentityHasEncryptionKey = !ident.pgpSigningKey().isEmpty() || !ident.smimeSigningKey().isEmpty();
  4301. mAttachMPK->setEnabled( Kleo::CryptoBackendFactory::instance()->openpgp() &&
  4302. !ident.pgpEncryptionKey().isEmpty() );
  4303. // save the state of the sign and encrypt button
  4304. if ( !bNewIdentityHasEncryptionKey && mLastIdentityHasEncryptionKey ) {
  4305. mLastEncryptActionState = mEncryptAction->isChecked();
  4306. setEncryption( false );
  4307. }
  4308. if ( !bNewIdentityHasSigningKey && mLastIdentityHasSigningKey ) {
  4309. mLastSignActionState = mSignAction->isChecked();
  4310. setSigning( false );
  4311. }
  4312. // restore the last state of the sign and encrypt button
  4313. if ( bNewIdentityHasEncryptionKey && !mLastIdentityHasEncryptionKey )
  4314. setEncryption( mLastEncryptActionState );
  4315. if ( bNewIdentityHasSigningKey && !mLastIdentityHasSigningKey )
  4316. setSigning( mLastSignActionState );
  4317. mLastIdentityHasSigningKey = bNewIdentityHasSigningKey;
  4318. mLastIdentityHasEncryptionKey = bNewIdentityHasEncryptionKey;
  4319. setModified( true );
  4320. mId = uoid;
  4321. // make sure the From and BCC fields are shown if necessary
  4322. rethinkFields( false );
  4323. }
  4324. //-----------------------------------------------------------------------------
  4325. void KMComposeWin::slotSpellcheckConfig()
  4326. {
  4327. KDialogBase dlg(KDialogBase::Plain, i18n("Spellchecker"),
  4328. KDialogBase::Ok|KDialogBase::Cancel, KDialogBase::Ok,
  4329. TQT_TQWIDGET(this), 0, true, true );
  4330. KWin twin;
  4331. TQTabDialog qtd (this, "tabdialog", true);
  4332. KSpellConfig mKSpellConfig (&qtd);
  4333. mKSpellConfig.layout()->setMargin( KDialog::marginHint() );
  4334. qtd.addTab (&mKSpellConfig, i18n("Spellchecker"));
  4335. qtd.setCancelButton ();
  4336. twin.setIcons (qtd.winId(), kapp->icon(), kapp->miniIcon());
  4337. qtd.setCancelButton(KStdGuiItem::cancel().text());
  4338. qtd.setOkButton(KStdGuiItem::ok().text());
  4339. if (qtd.exec())
  4340. mKSpellConfig.writeGlobalSettings();
  4341. }
  4342. //-----------------------------------------------------------------------------
  4343. void KMComposeWin::slotStatusMessage(const TQString &message)
  4344. {
  4345. statusBar()->changeItem( message, 0 );
  4346. }
  4347. void KMComposeWin::slotEditToolbars()
  4348. {
  4349. saveMainWindowSettings(KMKernel::config(), "Composer");
  4350. KEditToolbar dlg(guiFactory(), this);
  4351. connect( &dlg, TQT_SIGNAL(newToolbarConfig()),
  4352. TQT_SLOT(slotUpdateToolbars()) );
  4353. dlg.exec();
  4354. }
  4355. void KMComposeWin::slotUpdateToolbars()
  4356. {
  4357. createGUI("kmcomposerui.rc");
  4358. applyMainWindowSettings(KMKernel::config(), "Composer");
  4359. }
  4360. void KMComposeWin::slotEditKeys()
  4361. {
  4362. KKeyDialog::configure( actionCollection(),
  4363. false /*don't allow one-letter shortcuts*/
  4364. );
  4365. }
  4366. void KMComposeWin::setReplyFocus( bool hasMessage )
  4367. {
  4368. mEditor->setFocus();
  4369. if ( hasMessage ) {
  4370. if( mMsg->getCursorPos() ) {
  4371. mEditor->setCursorPositionFromStart( (unsigned int) mMsg->getCursorPos() );
  4372. } else {
  4373. mEditor->setCursorPosition( 1, 0 );
  4374. }
  4375. }
  4376. }
  4377. void KMComposeWin::setFocusToSubject()
  4378. {
  4379. mEdtSubject->setFocus();
  4380. }
  4381. int KMComposeWin::autoSaveInterval() const
  4382. {
  4383. return GlobalSettings::self()->autosaveInterval() * 1000 * 60;
  4384. }
  4385. void KMComposeWin::initAutoSave()
  4386. {
  4387. kdDebug(5006) << k_funcinfo << endl;
  4388. // make sure the autosave folder exists
  4389. KMFolderMaildir::createMaildirFolders( KMKernel::localDataPath() + "autosave" );
  4390. if ( mAutoSaveFilename.isEmpty() ) {
  4391. mAutoSaveFilename = KMFolderMaildir::constructValidFileName();
  4392. }
  4393. updateAutoSave();
  4394. }
  4395. void KMComposeWin::updateAutoSave()
  4396. {
  4397. if ( autoSaveInterval() == 0 ) {
  4398. delete mAutoSaveTimer; mAutoSaveTimer = 0;
  4399. }
  4400. else {
  4401. if ( !mAutoSaveTimer ) {
  4402. mAutoSaveTimer = new TQTimer( this, "mAutoSaveTimer" );
  4403. connect( mAutoSaveTimer, TQT_SIGNAL( timeout() ),
  4404. TQT_TQOBJECT(this), TQT_SLOT( autoSaveMessage() ) );
  4405. }
  4406. mAutoSaveTimer->start( autoSaveInterval() );
  4407. }
  4408. }
  4409. void KMComposeWin::setAutoSaveFilename( const TQString & filename )
  4410. {
  4411. mAutoSaveFilename = filename;
  4412. }
  4413. void KMComposeWin::cleanupAutoSave()
  4414. {
  4415. delete mAutoSaveTimer; mAutoSaveTimer = 0;
  4416. if ( !mAutoSaveFilename.isEmpty() ) {
  4417. kdDebug(5006) << k_funcinfo << "deleting autosave file "
  4418. << mAutoSaveFilename << endl;
  4419. KMFolderMaildir::removeFile( KMKernel::localDataPath() + "autosave",
  4420. mAutoSaveFilename );
  4421. mAutoSaveFilename = TQString();
  4422. }
  4423. }
  4424. void KMComposeWin::slotCompletionModeChanged( TDEGlobalSettings::Completion mode)
  4425. {
  4426. GlobalSettings::self()->setCompletionMode( (int) mode );
  4427. // sync all the lineedits to the same completion mode
  4428. mEdtFrom->setCompletionMode( mode );
  4429. mEdtReplyTo->setCompletionMode( mode );
  4430. if ( mClassicalRecipients ) {
  4431. mEdtTo->setCompletionMode( mode );
  4432. mEdtCc->setCompletionMode( mode );
  4433. mEdtBcc->setCompletionMode( mode );
  4434. }else
  4435. mRecipientsEditor->setCompletionMode( mode );
  4436. }
  4437. void KMComposeWin::slotConfigChanged()
  4438. {
  4439. readConfig( true /*reload*/);
  4440. updateAutoSave();
  4441. rethinkFields();
  4442. slotWordWrapToggled( mWordWrapAction->isChecked() );
  4443. }
  4444. /*
  4445. * checks if the drafts-folder has been deleted
  4446. * that is not nice so we set the system-drafts-folder
  4447. */
  4448. void KMComposeWin::slotFolderRemoved(KMFolder* folder)
  4449. {
  4450. // TODO: need to handle templates here?
  4451. if ( (mFolder) && (folder->idString() == mFolder->idString()) )
  4452. {
  4453. mFolder = kmkernel->draftsFolder();
  4454. kdDebug(5006) << "restoring drafts to " << mFolder->idString() << endl;
  4455. }
  4456. if (mMsg) mMsg->setParent(0);
  4457. }
  4458. void KMComposeWin::editorFocusChanged(bool gained)
  4459. {
  4460. mPasteQuotation->setEnabled(gained);
  4461. }
  4462. void KMComposeWin::slotSetAlwaysSend( bool bAlways )
  4463. {
  4464. mAlwaysSend = bAlways;
  4465. }
  4466. void KMComposeWin::slotListAction( const TQString& style )
  4467. {
  4468. toggleMarkup(true);
  4469. if ( style == i18n( "Standard" ) )
  4470. mEditor->setParagType( TQStyleSheetItem::DisplayBlock, TQStyleSheetItem::ListDisc );
  4471. else if ( style == i18n( "Bulleted List (Disc)" ) )
  4472. mEditor->setParagType( TQStyleSheetItem::DisplayListItem, TQStyleSheetItem::ListDisc );
  4473. else if ( style == i18n( "Bulleted List (Circle)" ) )
  4474. mEditor->setParagType( TQStyleSheetItem::DisplayListItem, TQStyleSheetItem::ListCircle );
  4475. else if ( style == i18n( "Bulleted List (Square)" ) )
  4476. mEditor->setParagType( TQStyleSheetItem::DisplayListItem, TQStyleSheetItem::ListSquare );
  4477. else if ( style == i18n( "Ordered List (Decimal)" ))
  4478. mEditor->setParagType( TQStyleSheetItem::DisplayListItem, TQStyleSheetItem::ListDecimal );
  4479. else if ( style == i18n( "Ordered List (Alpha lower)" ) )
  4480. mEditor->setParagType( TQStyleSheetItem::DisplayListItem, TQStyleSheetItem::ListLowerAlpha );
  4481. else if ( style == i18n( "Ordered List (Alpha upper)" ) )
  4482. mEditor->setParagType( TQStyleSheetItem::DisplayListItem, TQStyleSheetItem::ListUpperAlpha );
  4483. mEditor->viewport()->setFocus();
  4484. }
  4485. void KMComposeWin::slotFontAction( const TQString& font)
  4486. {
  4487. toggleMarkup(true);
  4488. mEditor->TQTextEdit::setFamily( font );
  4489. mEditor->viewport()->setFocus();
  4490. }
  4491. void KMComposeWin::slotSizeAction( int size )
  4492. {
  4493. toggleMarkup(true);
  4494. mEditor->setPointSize( size );
  4495. mEditor->viewport()->setFocus();
  4496. }
  4497. void KMComposeWin::slotAlignLeft()
  4498. {
  4499. toggleMarkup(true);
  4500. mEditor->TQTextEdit::setAlignment( AlignLeft );
  4501. }
  4502. void KMComposeWin::slotAlignCenter()
  4503. {
  4504. toggleMarkup(true);
  4505. mEditor->TQTextEdit::setAlignment( AlignHCenter );
  4506. }
  4507. void KMComposeWin::slotAlignRight()
  4508. {
  4509. toggleMarkup(true);
  4510. mEditor->TQTextEdit::setAlignment( AlignRight );
  4511. }
  4512. void KMComposeWin::slotTextBold()
  4513. {
  4514. toggleMarkup(true);
  4515. mEditor->TQTextEdit::setBold( textBoldAction->isChecked() );
  4516. }
  4517. void KMComposeWin::slotTextItalic()
  4518. {
  4519. toggleMarkup(true);
  4520. mEditor->TQTextEdit::setItalic( textItalicAction->isChecked() );
  4521. }
  4522. void KMComposeWin::slotTextUnder()
  4523. {
  4524. toggleMarkup(true);
  4525. mEditor->TQTextEdit::setUnderline( textUnderAction->isChecked() );
  4526. }
  4527. void KMComposeWin::slotFormatReset()
  4528. {
  4529. mEditor->setColor(mForeColor);
  4530. mEditor->setCurrentFont( mSaveFont ); // fontChanged is called now
  4531. }
  4532. void KMComposeWin::slotTextColor()
  4533. {
  4534. TQColor color = mEditor->color();
  4535. if ( KColorDialog::getColor( color, this ) ) {
  4536. toggleMarkup(true);
  4537. mEditor->setColor( color );
  4538. }
  4539. }
  4540. void KMComposeWin::fontChanged( const TQFont &f )
  4541. {
  4542. TQFont fontTemp = f;
  4543. fontTemp.setBold( true );
  4544. fontTemp.setItalic( true );
  4545. TQFontInfo fontInfo( fontTemp );
  4546. if ( fontInfo.bold() ) {
  4547. textBoldAction->setChecked( f.bold() );
  4548. textBoldAction->setEnabled( true ) ;
  4549. } else {
  4550. textBoldAction->setEnabled( false );
  4551. }
  4552. if ( fontInfo.italic() ) {
  4553. textItalicAction->setChecked( f.italic() );
  4554. textItalicAction->setEnabled( true ) ;
  4555. } else {
  4556. textItalicAction->setEnabled( false );
  4557. }
  4558. textUnderAction->setChecked( f.underline() );
  4559. fontAction->setFont( f.family() );
  4560. fontSizeAction->setFontSize( f.pointSize() );
  4561. }
  4562. void KMComposeWin::alignmentChanged( int a )
  4563. {
  4564. //toggleMarkup();
  4565. alignLeftAction->setChecked( ( a == AlignAuto ) || ( a & AlignLeft ) );
  4566. alignCenterAction->setChecked( ( a & AlignHCenter ) );
  4567. alignRightAction->setChecked( ( a & AlignRight ) );
  4568. }
  4569. namespace {
  4570. class TDEToggleActionResetter {
  4571. TDEToggleAction * mAction;
  4572. bool mOn;
  4573. public:
  4574. TDEToggleActionResetter( TDEToggleAction * action, bool on )
  4575. : mAction( action ), mOn( on ) {}
  4576. ~TDEToggleActionResetter() {
  4577. if ( mAction )
  4578. mAction->setChecked( mOn );
  4579. }
  4580. void disable() { mAction = 0; }
  4581. };
  4582. }
  4583. void KMComposeWin::slotEncryptChiasmusToggled( bool on ) {
  4584. mEncryptWithChiasmus = false;
  4585. if ( !on )
  4586. return;
  4587. TDEToggleActionResetter resetter( mEncryptChiasmusAction, false );
  4588. const Kleo::CryptoBackend::Protocol * chiasmus =
  4589. Kleo::CryptoBackendFactory::instance()->protocol( "Chiasmus" );
  4590. if ( !chiasmus ) {
  4591. const TQString msg = Kleo::CryptoBackendFactory::instance()->knowsAboutProtocol( "Chiasmus" )
  4592. ? i18n( "Please configure a Crypto Backend to use for "
  4593. "Chiasmus encryption first.\n"
  4594. "You can do this in the Crypto Backends tab of "
  4595. "the configure dialog's Security page." )
  4596. : i18n( "It looks as though libkleopatra was compiled without "
  4597. "Chiasmus support. You might want to recompile "
  4598. "libkleopatra with --enable-chiasmus.");
  4599. KMessageBox::information( this, msg, i18n("No Chiasmus Backend Configured" ) );
  4600. return;
  4601. }
  4602. STD_NAMESPACE_PREFIX auto_ptr<Kleo::SpecialJob> job( chiasmus->specialJob( "x-obtain-keys", TQMap<TQString,TQVariant>() ) );
  4603. if ( !job.get() ) {
  4604. const TQString msg = i18n( "Chiasmus backend does not offer the "
  4605. "\"x-obtain-keys\" function. Please report this bug." );
  4606. KMessageBox::error( this, msg, i18n( "Chiasmus Backend Error" ) );
  4607. return;
  4608. }
  4609. if ( job->exec() ) {
  4610. job->showErrorDialog( this, i18n( "Chiasmus Backend Error" ) );
  4611. return;
  4612. }
  4613. const TQVariant result = job->property( "result" );
  4614. if ( result.type() != TQVariant::StringList ) {
  4615. const TQString msg = i18n( "Unexpected return value from Chiasmus backend: "
  4616. "The \"x-obtain-keys\" function did not return a "
  4617. "string list. Please report this bug." );
  4618. KMessageBox::error( this, msg, i18n( "Chiasmus Backend Error" ) );
  4619. return;
  4620. }
  4621. const TQStringList keys = result.toStringList();
  4622. if ( keys.empty() ) {
  4623. const TQString msg = i18n( "No keys have been found. Please check that a "
  4624. "valid key path has been set in the Chiasmus "
  4625. "configuration." );
  4626. KMessageBox::information( this, msg, i18n( "No Chiasmus Keys Found" ) );
  4627. return;
  4628. }
  4629. ChiasmusKeySelector selectorDlg( this, i18n( "Chiasmus Encryption Key Selection" ),
  4630. keys, GlobalSettings::chiasmusKey(),
  4631. GlobalSettings::chiasmusOptions() );
  4632. if ( selectorDlg.exec() != TQDialog::Accepted )
  4633. return;
  4634. GlobalSettings::setChiasmusOptions( selectorDlg.options() );
  4635. GlobalSettings::setChiasmusKey( selectorDlg.key() );
  4636. assert( !GlobalSettings::chiasmusKey().isEmpty() );
  4637. mEncryptWithChiasmus = true;
  4638. resetter.disable();
  4639. }
  4640. void KMComposeWin::slotEditDone(KMail::EditorWatcher * watcher)
  4641. {
  4642. kdDebug(5006) << k_funcinfo << endl;
  4643. KMMessagePart *part = mEditorMap[ watcher ];
  4644. KTempFile *tf = mEditorTempFiles[ watcher ];
  4645. mEditorMap.remove( watcher );
  4646. mEditorTempFiles.remove( watcher );
  4647. if ( !watcher->fileChanged() )
  4648. return;
  4649. tf->file()->reset();
  4650. TQByteArray data = tf->file()->readAll();
  4651. part->setBodyEncodedBinary( data );
  4652. }
  4653. void KMComposeWin::slotUpdateSignatureAndEncrypionStateIndicators()
  4654. {
  4655. const bool showIndicatorsAlways = false; // FIXME config option?
  4656. mSignatureStateIndicator->setText( mSignAction->isChecked()? i18n("Message will be signed") : i18n("Message will not be signed") );
  4657. mEncryptionStateIndicator->setText( mEncryptAction->isChecked()? i18n("Message will be encrypted") : i18n("Message will not be encrypted") );
  4658. if ( !showIndicatorsAlways ) {
  4659. mSignatureStateIndicator->setShown( mSignAction->isChecked() );
  4660. mEncryptionStateIndicator->setShown( mEncryptAction->isChecked() );
  4661. }
  4662. }
  4663. void KMComposeWin::slotAttachmentDragStarted()
  4664. {
  4665. kdDebug(5006) << k_funcinfo << endl;
  4666. int idx = 0;
  4667. TQStringList filenames;
  4668. for ( TQPtrListIterator<TQListViewItem> it(mAtmItemList); *it; ++it, ++idx ) {
  4669. if ( (*it)->isSelected() ) {
  4670. KMMessagePart* msgPart = mAtmList.at(idx);
  4671. KTempDir * tempDir = new KTempDir(); // will be deleted on composer close
  4672. tempDir->setAutoDelete( true );
  4673. mTempDirs.insert( tempDir );
  4674. const TQString fileName = tempDir->name() + "/" + msgPart->name();
  4675. KPIM::kByteArrayToFile(msgPart->bodyDecodedBinary(),
  4676. fileName,
  4677. false, false, false);
  4678. KURL url;
  4679. url.setPath( fileName );
  4680. filenames << url.path();
  4681. }
  4682. }
  4683. if ( filenames.isEmpty() ) return;
  4684. TQUriDrag *drag = new TQUriDrag( mAtmListView );
  4685. drag->setFileNames( filenames );
  4686. drag->dragCopy();
  4687. }
  4688. void KMComposeWin::recipientEditorSizeHintChanged()
  4689. {
  4690. TQTimer::singleShot( 1, this, TQT_SLOT(setMaximumHeaderSize()) );
  4691. }
  4692. void KMComposeWin::setMaximumHeaderSize()
  4693. {
  4694. mHeadersArea->setMaximumHeight( mHeadersArea->sizeHint().height() );
  4695. }