message.el 301 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601
  1. ;;; message.el --- composing mail and news messages
  2. ;; Copyright (C) 1996-2015 Free Software Foundation, Inc.
  3. ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
  4. ;; Keywords: mail, news
  5. ;; This file is part of GNU Emacs.
  6. ;; GNU Emacs is free software: you can redistribute it and/or modify
  7. ;; it under the terms of the GNU General Public License as published by
  8. ;; the Free Software Foundation, either version 3 of the License, or
  9. ;; (at your option) any later version.
  10. ;; GNU Emacs is distributed in the hope that it will be useful,
  11. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ;; GNU General Public License for more details.
  14. ;; You should have received a copy of the GNU General Public License
  15. ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
  16. ;;; Commentary:
  17. ;; This mode provides mail-sending facilities from within Emacs. It
  18. ;; consists mainly of large chunks of code from the sendmail.el,
  19. ;; gnus-msg.el and rnewspost.el files.
  20. ;;; Code:
  21. (eval-when-compile
  22. (require 'cl))
  23. (require 'mailheader)
  24. (require 'gmm-utils)
  25. (require 'mail-utils)
  26. ;; Only for the trivial macros mail-header-from, mail-header-date
  27. ;; mail-header-references, mail-header-subject, mail-header-id
  28. (eval-when-compile (require 'nnheader))
  29. ;; This is apparently necessary even though things are autoloaded.
  30. ;; Because we dynamically bind mail-abbrev-mode-regexp, we'd better
  31. ;; require mailabbrev here.
  32. (if (featurep 'xemacs)
  33. (require 'mail-abbrevs)
  34. (require 'mailabbrev))
  35. (require 'mail-parse)
  36. (require 'mml)
  37. (require 'rfc822)
  38. (require 'format-spec)
  39. (require 'dired)
  40. (autoload 'mailclient-send-it "mailclient") ;; Emacs 22 or contrib/
  41. (defvar gnus-message-group-art)
  42. (defvar gnus-list-identifiers) ; gnus-sum is required where necessary
  43. (defvar rmail-enable-mime-composing)
  44. (defgroup message '((user-mail-address custom-variable)
  45. (user-full-name custom-variable))
  46. "Mail and news message composing."
  47. :link '(custom-manual "(message)Top")
  48. :group 'mail
  49. :group 'news)
  50. (put 'user-mail-address 'custom-type 'string)
  51. (put 'user-full-name 'custom-type 'string)
  52. (defgroup message-various nil
  53. "Various Message Variables."
  54. :link '(custom-manual "(message)Various Message Variables")
  55. :group 'message)
  56. (defgroup message-buffers nil
  57. "Message Buffers."
  58. :link '(custom-manual "(message)Message Buffers")
  59. :group 'message)
  60. (defgroup message-sending nil
  61. "Message Sending."
  62. :link '(custom-manual "(message)Sending Variables")
  63. :group 'message)
  64. (defgroup message-interface nil
  65. "Message Interface."
  66. :link '(custom-manual "(message)Interface")
  67. :group 'message)
  68. (defgroup message-forwarding nil
  69. "Message Forwarding."
  70. :link '(custom-manual "(message)Forwarding")
  71. :group 'message-interface)
  72. (defgroup message-insertion nil
  73. "Message Insertion."
  74. :link '(custom-manual "(message)Insertion")
  75. :group 'message)
  76. (defgroup message-headers nil
  77. "Message Headers."
  78. :link '(custom-manual "(message)Message Headers")
  79. :group 'message)
  80. (defgroup message-news nil
  81. "Composing News Messages."
  82. :group 'message)
  83. (defgroup message-mail nil
  84. "Composing Mail Messages."
  85. :group 'message)
  86. (defgroup message-faces nil
  87. "Faces used for message composing."
  88. :group 'message
  89. :group 'faces)
  90. (defcustom message-directory "~/Mail/"
  91. "*Directory from which all other mail file variables are derived."
  92. :group 'message-various
  93. :type 'directory)
  94. (defcustom message-max-buffers 10
  95. "*How many buffers to keep before starting to kill them off."
  96. :group 'message-buffers
  97. :type 'integer)
  98. (defcustom message-send-rename-function nil
  99. "Function called to rename the buffer after sending it."
  100. :group 'message-buffers
  101. :type '(choice function (const nil)))
  102. (defcustom message-fcc-handler-function 'message-output
  103. "*A function called to save outgoing articles.
  104. This function will be called with the name of the file to store the
  105. article in. The default function is `message-output' which saves in Unix
  106. mailbox format."
  107. :type '(radio (function-item message-output)
  108. (function :tag "Other"))
  109. :group 'message-sending)
  110. (defcustom message-fcc-externalize-attachments nil
  111. "If non-nil, attachments are included as external parts in Fcc copies."
  112. :version "22.1"
  113. :type 'boolean
  114. :group 'message-sending)
  115. (defcustom message-courtesy-message
  116. "The following message is a courtesy copy of an article\nthat has been posted to %s as well.\n\n"
  117. "*This is inserted at the start of a mailed copy of a posted message.
  118. If the string contains the format spec \"%s\", the Newsgroups
  119. the article has been posted to will be inserted there.
  120. If this variable is nil, no such courtesy message will be added."
  121. :group 'message-sending
  122. :type '(radio string (const nil)))
  123. (defcustom message-ignored-bounced-headers
  124. "^\\(Received\\|Return-Path\\|Delivered-To\\):"
  125. "*Regexp that matches headers to be removed in resent bounced mail."
  126. :group 'message-interface
  127. :type 'regexp)
  128. (defcustom message-from-style mail-from-style
  129. "Specifies how \"From\" headers look.
  130. If nil, they contain just the return address like:
  131. king@grassland.com
  132. If `parens', they look like:
  133. king@grassland.com (Elvis Parsley)
  134. If `angles', they look like:
  135. Elvis Parsley <king@grassland.com>
  136. Otherwise, most addresses look like `angles', but they look like
  137. `parens' if `angles' would need quoting and `parens' would not."
  138. :version "23.2"
  139. :type '(choice (const :tag "simple" nil)
  140. (const parens)
  141. (const angles)
  142. (const default))
  143. :group 'message-headers)
  144. (defcustom message-insert-canlock t
  145. "Whether to insert a Cancel-Lock header in news postings."
  146. :version "22.1"
  147. :group 'message-headers
  148. :type 'boolean)
  149. (defcustom message-syntax-checks
  150. (if message-insert-canlock '((sender . disabled)) nil)
  151. ;; Guess this one shouldn't be easy to customize...
  152. "*Controls what syntax checks should not be performed on outgoing posts.
  153. To disable checking of long signatures, for instance, add
  154. `(signature . disabled)' to this list.
  155. Don't touch this variable unless you really know what you're doing.
  156. Checks include `approved', `bogus-recipient', `continuation-headers',
  157. `control-chars', `empty', `existing-newsgroups', `from', `illegible-text',
  158. `invisible-text', `long-header-lines', `long-lines', `message-id',
  159. `multiple-headers', `new-text', `newsgroups', `quoting-style',
  160. `repeated-newsgroups', `reply-to', `sender', `sendsys', `shoot',
  161. `shorten-followup-to', `signature', `size', `subject', `subject-cmsg'
  162. and `valid-newsgroups'."
  163. :group 'message-news
  164. :type '(repeat sexp)) ; Fixme: improve this
  165. (defcustom message-required-headers '((optional . References)
  166. From)
  167. "*Headers to be generated or prompted for when sending a message.
  168. Also see `message-required-news-headers' and
  169. `message-required-mail-headers'."
  170. :version "22.1"
  171. :group 'message-news
  172. :group 'message-headers
  173. :link '(custom-manual "(message)Message Headers")
  174. :type '(repeat sexp))
  175. (defcustom message-draft-headers '(References From Date)
  176. "*Headers to be generated when saving a draft message."
  177. :version "22.1"
  178. :group 'message-news
  179. :group 'message-headers
  180. :link '(custom-manual "(message)Message Headers")
  181. :type '(repeat sexp))
  182. (defcustom message-required-news-headers
  183. '(From Newsgroups Subject Date Message-ID
  184. (optional . Organization)
  185. (optional . User-Agent))
  186. "*Headers to be generated or prompted for when posting an article.
  187. RFC977 and RFC1036 require From, Date, Newsgroups, Subject,
  188. Message-ID. Organization, Lines, In-Reply-To, Expires, and
  189. User-Agent are optional. If you don't want message to insert some
  190. header, remove it from this list."
  191. :group 'message-news
  192. :group 'message-headers
  193. :link '(custom-manual "(message)Message Headers")
  194. :type '(repeat sexp))
  195. (defcustom message-required-mail-headers
  196. '(From Subject Date (optional . In-Reply-To) Message-ID
  197. (optional . User-Agent))
  198. "*Headers to be generated or prompted for when mailing a message.
  199. It is recommended that From, Date, To, Subject and Message-ID be
  200. included. Organization and User-Agent are optional."
  201. :group 'message-mail
  202. :group 'message-headers
  203. :link '(custom-manual "(message)Message Headers")
  204. :type '(repeat sexp))
  205. (defcustom message-prune-recipient-rules nil
  206. "Rules for how to prune the list of recipients when doing wide replies.
  207. This is a list of regexps and regexp matches."
  208. :version "24.1"
  209. :group 'message-mail
  210. :group 'message-headers
  211. :link '(custom-manual "(message)Wide Reply")
  212. :type '(repeat regexp))
  213. (defcustom message-deletable-headers '(Message-ID Date Lines)
  214. "Headers to be deleted if they already exist and were generated by message previously."
  215. :group 'message-headers
  216. :link '(custom-manual "(message)Message Headers")
  217. :type 'sexp)
  218. (defcustom message-ignored-news-headers
  219. "^NNTP-Posting-Host:\\|^Xref:\\|^[BGF]cc:\\|^Resent-Fcc:\\|^X-Draft-From:\\|^X-Gnus-Agent-Meta-Information:\\|^X-Message-SMTP-Method:\\|^X-Gnus-Delayed:"
  220. "*Regexp of headers to be removed unconditionally before posting."
  221. :group 'message-news
  222. :group 'message-headers
  223. :link '(custom-manual "(message)Message Headers")
  224. :type '(repeat :value-to-internal (lambda (widget value)
  225. (custom-split-regexp-maybe value))
  226. :match (lambda (widget value)
  227. (or (stringp value)
  228. (widget-editable-list-match widget value)))
  229. regexp))
  230. (defcustom message-ignored-mail-headers
  231. "^\\([GF]cc\\|Resent-Fcc\\|Xref\\|X-Draft-From\\|X-Gnus-Agent-Meta-Information\\):"
  232. "*Regexp of headers to be removed unconditionally before mailing."
  233. :group 'message-mail
  234. :group 'message-headers
  235. :link '(custom-manual "(message)Mail Headers")
  236. :type 'regexp)
  237. (defcustom message-ignored-supersedes-headers "^Path:\\|^Date\\|^NNTP-Posting-Host:\\|^Xref:\\|^Lines:\\|^Received:\\|^X-From-Line:\\|^X-Trace:\\|^X-ID:\\|^X-Complaints-To:\\|Return-Path:\\|^Supersedes:\\|^NNTP-Posting-Date:\\|^X-Trace:\\|^X-Complaints-To:\\|^Cancel-Lock:\\|^Cancel-Key:\\|^X-Hashcash:\\|^X-Payment:\\|^Approved:\\|^Injection-Date:\\|^Injection-Info:"
  238. "*Header lines matching this regexp will be deleted before posting.
  239. It's best to delete old Path and Date headers before posting to avoid
  240. any confusion."
  241. :group 'message-interface
  242. :link '(custom-manual "(message)Superseding")
  243. :type '(repeat :value-to-internal (lambda (widget value)
  244. (custom-split-regexp-maybe value))
  245. :match (lambda (widget value)
  246. (or (stringp value)
  247. (widget-editable-list-match widget value)))
  248. regexp))
  249. (defcustom message-subject-re-regexp
  250. "^[ \t]*\\([Rr][Ee]\\(\\[[0-9]*\\]\\)*:[ \t]*\\)*[ \t]*"
  251. "*Regexp matching \"Re: \" in the subject line."
  252. :group 'message-various
  253. :link '(custom-manual "(message)Message Headers")
  254. :type 'regexp)
  255. ;;; Start of variables adopted from `message-utils.el'.
  256. (defcustom message-subject-trailing-was-query t
  257. "*What to do with trailing \"(was: <old subject>)\" in subject lines.
  258. If nil, leave the subject unchanged. If it is the symbol `ask', query
  259. the user what do do. In this case, the subject is matched against
  260. `message-subject-trailing-was-ask-regexp'. If
  261. `message-subject-trailing-was-query' is t, always strip the trailing
  262. old subject. In this case, `message-subject-trailing-was-regexp' is
  263. used."
  264. :version "24.1"
  265. :type '(choice (const :tag "never" nil)
  266. (const :tag "always strip" t)
  267. (const ask))
  268. :link '(custom-manual "(message)Message Headers")
  269. :group 'message-various)
  270. (defcustom message-subject-trailing-was-ask-regexp
  271. "[ \t]*\\([[(]+[Ww][Aa][Ss]:?[ \t]*.*[])]+\\)"
  272. "*Regexp matching \"(was: <old subject>)\" in the subject line.
  273. The function `message-strip-subject-trailing-was' uses this regexp if
  274. `message-subject-trailing-was-query' is set to the symbol `ask'. If
  275. the variable is t instead of `ask', use
  276. `message-subject-trailing-was-regexp' instead.
  277. It is okay to create some false positives here, as the user is asked."
  278. :version "22.1"
  279. :group 'message-various
  280. :link '(custom-manual "(message)Message Headers")
  281. :type 'regexp)
  282. (defcustom message-subject-trailing-was-regexp
  283. "[ \t]*\\((*[Ww][Aa][Ss]:[ \t]*.*)\\)"
  284. "*Regexp matching \"(was: <old subject>)\" in the subject line.
  285. If `message-subject-trailing-was-query' is set to t, the subject is
  286. matched against `message-subject-trailing-was-regexp' in
  287. `message-strip-subject-trailing-was'. You should use a regexp creating very
  288. few false positives here."
  289. :version "22.1"
  290. :group 'message-various
  291. :link '(custom-manual "(message)Message Headers")
  292. :type 'regexp)
  293. ;;; marking inserted text
  294. (defcustom message-mark-insert-begin
  295. "--8<---------------cut here---------------start------------->8---\n"
  296. "How to mark the beginning of some inserted text."
  297. :version "22.1"
  298. :type 'string
  299. :link '(custom-manual "(message)Insertion Variables")
  300. :group 'message-various)
  301. (defcustom message-mark-insert-end
  302. "--8<---------------cut here---------------end--------------->8---\n"
  303. "How to mark the end of some inserted text."
  304. :version "22.1"
  305. :type 'string
  306. :link '(custom-manual "(message)Insertion Variables")
  307. :group 'message-various)
  308. (defcustom message-archive-header "X-No-Archive: Yes\n"
  309. "Header to insert when you don't want your article to be archived.
  310. Archives \(such as groups.google.com\) respect this header."
  311. :version "22.1"
  312. :type 'string
  313. :link '(custom-manual "(message)Header Commands")
  314. :group 'message-various)
  315. (defcustom message-archive-note
  316. "X-No-Archive: Yes - save http://groups.google.com/"
  317. "Note to insert why you wouldn't want this posting archived.
  318. If nil, don't insert any text in the body."
  319. :version "22.1"
  320. :type '(radio string (const nil))
  321. :link '(custom-manual "(message)Header Commands")
  322. :group 'message-various)
  323. ;;; Crossposts and Followups
  324. ;; inspired by JoH-followup-to by Jochem Huhman <joh at gmx.de>
  325. ;; new suggestions by R. Weikusat <rw at another.de>
  326. (defvar message-cross-post-old-target nil
  327. "Old target for cross-posts or follow-ups.")
  328. (make-variable-buffer-local 'message-cross-post-old-target)
  329. (defcustom message-cross-post-default t
  330. "When non-nil `message-cross-post-followup-to' will perform a crosspost.
  331. If nil, `message-cross-post-followup-to' will only do a followup. Note that
  332. you can explicitly override this setting by calling
  333. `message-cross-post-followup-to' with a prefix."
  334. :version "22.1"
  335. :type 'boolean
  336. :group 'message-various)
  337. (defcustom message-cross-post-note "Crosspost & Followup-To: "
  338. "Note to insert before signature to notify of cross-post and follow-up."
  339. :version "22.1"
  340. :type 'string
  341. :group 'message-various)
  342. (defcustom message-followup-to-note "Followup-To: "
  343. "Note to insert before signature to notify of follow-up only."
  344. :version "22.1"
  345. :type 'string
  346. :group 'message-various)
  347. (defcustom message-cross-post-note-function 'message-cross-post-insert-note
  348. "Function to use to insert note about Crosspost or Followup-To.
  349. The function will be called with four arguments. The function should not only
  350. insert a note, but also ensure old notes are deleted. See the documentation
  351. for `message-cross-post-insert-note'."
  352. :version "22.1"
  353. :type 'function
  354. :group 'message-various)
  355. ;;; End of variables adopted from `message-utils.el'.
  356. (defcustom message-signature-separator "^-- $"
  357. "Regexp matching the signature separator.
  358. This variable is used to strip off the signature from quoted text
  359. when `message-cite-function' is
  360. `message-cite-original-without-signature'. Most useful values
  361. are \"^-- $\" (strict) and \"^-- *$\" (loose; allow missing
  362. whitespace)."
  363. :type '(choice (const :tag "strict" "^-- $")
  364. (const :tag "loose" "^-- *$")
  365. regexp)
  366. :version "22.3" ;; Gnus 5.10.12 (changed default)
  367. :link '(custom-manual "(message)Various Message Variables")
  368. :group 'message-various)
  369. (defcustom message-elide-ellipsis "\n[...]\n\n"
  370. "*The string which is inserted for elided text.
  371. This is a format-spec string, and you can use %l to say how many
  372. lines were removed, and %c to say how many characters were
  373. removed."
  374. :type 'string
  375. :link '(custom-manual "(message)Various Commands")
  376. :group 'message-various)
  377. (defcustom message-interactive mail-interactive
  378. "Non-nil means when sending a message wait for and display errors.
  379. A value of nil means let mailer mail back a message to report errors."
  380. :version "23.2"
  381. :group 'message-sending
  382. :group 'message-mail
  383. :link '(custom-manual "(message)Sending Variables")
  384. :type 'boolean)
  385. (defcustom message-confirm-send nil
  386. "When non-nil, ask for confirmation when sending a message."
  387. :group 'message-sending
  388. :group 'message-mail
  389. :version "23.1" ;; No Gnus
  390. :link '(custom-manual "(message)Sending Variables")
  391. :type 'boolean)
  392. (defcustom message-generate-new-buffers 'unsent
  393. "*Say whether to create a new message buffer to compose a message.
  394. Valid values include:
  395. nil
  396. Generate the buffer name in the Message way (e.g., *mail*, *news*,
  397. *mail to whom*, *news on group*, etc.) and continue editing in the
  398. existing buffer of that name. If there is no such buffer, it will
  399. be newly created.
  400. `unique' or t
  401. Create the new buffer with the name generated in the Message way.
  402. `unsent'
  403. Similar to `unique' but the buffer name begins with \"*unsent \".
  404. `standard'
  405. Similar to nil but the buffer name is simpler like *mail message*.
  406. function
  407. If this is a function, call that function with three parameters:
  408. The type, the To address and the group name (any of these may be nil).
  409. The function should return the new buffer name."
  410. :version "24.1"
  411. :group 'message-buffers
  412. :link '(custom-manual "(message)Message Buffers")
  413. :type '(choice (const nil)
  414. (sexp :tag "unique" :format "unique\n" :value unique
  415. :match (lambda (widget value) (memq value '(unique t))))
  416. (const unsent)
  417. (const standard)
  418. (function :format "\n %{%t%}: %v")))
  419. (defcustom message-kill-buffer-on-exit nil
  420. "*Non-nil means that the message buffer will be killed after sending a message."
  421. :group 'message-buffers
  422. :link '(custom-manual "(message)Message Buffers")
  423. :type 'boolean)
  424. (defcustom message-kill-buffer-query t
  425. "*Non-nil means that killing a modified message buffer has to be confirmed.
  426. This is used by `message-kill-buffer'."
  427. :version "23.1" ;; No Gnus
  428. :group 'message-buffers
  429. :type 'boolean)
  430. (defcustom message-user-organization
  431. (or (getenv "ORGANIZATION") t)
  432. "String to be used as an Organization header.
  433. If t, use `message-user-organization-file'."
  434. :group 'message-headers
  435. :type '(choice string
  436. (const :tag "consult file" t)))
  437. (defcustom message-user-organization-file
  438. (let (orgfile)
  439. (dolist (f (list "/etc/organization"
  440. "/etc/news/organization"
  441. "/usr/lib/news/organization"))
  442. (when (file-readable-p f)
  443. (setq orgfile f)))
  444. orgfile)
  445. "*Local news organization file."
  446. :type '(choice (const nil) file)
  447. :link '(custom-manual "(message)News Headers")
  448. :group 'message-headers)
  449. (defcustom message-make-forward-subject-function
  450. #'message-forward-subject-name-subject
  451. "*List of functions called to generate subject headers for forwarded messages.
  452. The subject generated by the previous function is passed into each
  453. successive function.
  454. The provided functions are:
  455. * `message-forward-subject-author-subject' Source of article (author or
  456. newsgroup), in brackets followed by the subject
  457. * `message-forward-subject-name-subject' Source of article (name of author
  458. or newsgroup), in brackets followed by the subject
  459. * `message-forward-subject-fwd' Subject of article with `Fwd:' prepended
  460. to it."
  461. :group 'message-forwarding
  462. :link '(custom-manual "(message)Forwarding")
  463. :type '(radio (function-item message-forward-subject-author-subject)
  464. (function-item message-forward-subject-fwd)
  465. (function-item message-forward-subject-name-subject)
  466. (repeat :tag "List of functions" function)))
  467. (defcustom message-forward-as-mime t
  468. "*Non-nil means forward messages as an inline/rfc822 MIME section.
  469. Otherwise, directly inline the old message in the forwarded message."
  470. :version "21.1"
  471. :group 'message-forwarding
  472. :link '(custom-manual "(message)Forwarding")
  473. :type 'boolean)
  474. (defcustom message-forward-show-mml 'best
  475. "*Non-nil means show forwarded messages as MML (decoded from MIME).
  476. Otherwise, forwarded messages are unchanged.
  477. Can also be the symbol `best' to indicate that MML should be
  478. used, except when it is a bad idea to use MML. One example where
  479. it is a bad idea is when forwarding a signed or encrypted
  480. message, because converting MIME to MML would invalidate the
  481. digital signature."
  482. :version "21.1"
  483. :group 'message-forwarding
  484. :type '(choice (const :tag "use MML" t)
  485. (const :tag "don't use MML " nil)
  486. (const :tag "use MML when appropriate" best)))
  487. (defcustom message-forward-before-signature t
  488. "*Non-nil means put forwarded message before signature, else after."
  489. :group 'message-forwarding
  490. :type 'boolean)
  491. (defcustom message-wash-forwarded-subjects nil
  492. "*Non-nil means try to remove as much cruft as possible from the subject.
  493. Done before generating the new subject of a forward."
  494. :group 'message-forwarding
  495. :link '(custom-manual "(message)Forwarding")
  496. :type 'boolean)
  497. (defcustom message-ignored-resent-headers
  498. ;; `Delivered-To' needs to be removed because some mailers use it to
  499. ;; detect loops, so if you resend a message to an address that ultimately
  500. ;; comes back to you (e.g. a mailing-list to which you subscribe, in which
  501. ;; case you may be removed from the list on the grounds that mail to you
  502. ;; bounced with a "mailing loop" error).
  503. "^Return-receipt\\|^X-Gnus\\|^Gnus-Warning:\\|^>?From \\|^Delivered-To:\
  504. \\|^X-Content-Length:\\|^X-UIDL:"
  505. "*All headers that match this regexp will be deleted when resending a message."
  506. :version "24.4"
  507. :group 'message-interface
  508. :link '(custom-manual "(message)Resending")
  509. :type '(repeat :value-to-internal (lambda (widget value)
  510. (custom-split-regexp-maybe value))
  511. :match (lambda (widget value)
  512. (or (stringp value)
  513. (widget-editable-list-match widget value)))
  514. regexp))
  515. (defcustom message-forward-ignored-headers "^Content-Transfer-Encoding:\\|^X-Gnus"
  516. "*All headers that match this regexp will be deleted when forwarding a message.
  517. This may also be a list of regexps."
  518. :version "21.1"
  519. :group 'message-forwarding
  520. :type '(repeat :value-to-internal (lambda (widget value)
  521. (custom-split-regexp-maybe value))
  522. :match (lambda (widget value)
  523. (or (stringp value)
  524. (widget-editable-list-match widget value)))
  525. regexp))
  526. (defcustom message-forward-included-headers nil
  527. "If non-nil, delete non-matching headers when forwarding a message.
  528. Only headers that match this regexp will be included. This
  529. variable should be a regexp or a list of regexps."
  530. :version "25.1"
  531. :group 'message-forwarding
  532. :type '(repeat :value-to-internal (lambda (widget value)
  533. (custom-split-regexp-maybe value))
  534. :match (lambda (widget value)
  535. (or (stringp value)
  536. (widget-editable-list-match widget value)))
  537. regexp))
  538. (defcustom message-ignored-cited-headers "."
  539. "*Delete these headers from the messages you yank."
  540. :group 'message-insertion
  541. :link '(custom-manual "(message)Insertion Variables")
  542. :type 'regexp)
  543. (defcustom message-cite-prefix-regexp mail-citation-prefix-regexp
  544. "*Regexp matching the longest possible citation prefix on a line."
  545. :version "24.1"
  546. :group 'message-insertion
  547. :link '(custom-manual "(message)Insertion Variables")
  548. :type 'regexp
  549. :set (lambda (symbol value)
  550. (prog1
  551. (custom-set-default symbol value)
  552. (if (boundp 'gnus-message-cite-prefix-regexp)
  553. (setq gnus-message-cite-prefix-regexp
  554. (concat "^\\(?:" value "\\)"))))))
  555. (defcustom message-cancel-message "I am canceling my own article.\n"
  556. "Message to be inserted in the cancel message."
  557. :group 'message-interface
  558. :link '(custom-manual "(message)Canceling News")
  559. :type 'string)
  560. (defun message-send-mail-function ()
  561. "Return suitable value for the variable `message-send-mail-function'."
  562. (cond ((and (require 'sendmail)
  563. (boundp 'sendmail-program)
  564. sendmail-program
  565. (executable-find sendmail-program))
  566. 'message-send-mail-with-sendmail)
  567. ((and (locate-library "smtpmail")
  568. (boundp 'smtpmail-default-smtp-server)
  569. smtpmail-default-smtp-server)
  570. 'message-smtpmail-send-it)
  571. ((locate-library "mailclient")
  572. 'message-send-mail-with-mailclient)
  573. (t
  574. (error "Don't know how to send mail. Please customize `message-send-mail-function'"))))
  575. (defun message-default-send-mail-function ()
  576. (cond ((eq send-mail-function 'smtpmail-send-it) 'message-smtpmail-send-it)
  577. ((eq send-mail-function 'feedmail-send-it) 'feedmail-send-it)
  578. ((eq send-mail-function 'sendmail-query-once) 'sendmail-query-once)
  579. ((eq send-mail-function 'mailclient-send-it)
  580. 'message-send-mail-with-mailclient)
  581. (t (message-send-mail-function))))
  582. ;; Useful to set in site-init.el
  583. (defcustom message-send-mail-function (message-default-send-mail-function)
  584. "Function to call to send the current buffer as mail.
  585. The headers should be delimited by a line whose contents match the
  586. variable `mail-header-separator'.
  587. Valid values include `message-send-mail-with-sendmail'
  588. `message-send-mail-with-mh', `message-send-mail-with-qmail',
  589. `message-smtpmail-send-it', `smtpmail-send-it',
  590. `feedmail-send-it' and `message-send-mail-with-mailclient'. The
  591. default is system dependent and determined by the function
  592. `message-send-mail-function'.
  593. See also `send-mail-function'."
  594. :type '(radio (function-item message-send-mail-with-sendmail)
  595. (function-item message-send-mail-with-mh)
  596. (function-item message-send-mail-with-qmail)
  597. (function-item message-smtpmail-send-it)
  598. (function-item smtpmail-send-it)
  599. (function-item feedmail-send-it)
  600. (function-item message-send-mail-with-mailclient
  601. :tag "Use Mailclient package")
  602. (function :tag "Other"))
  603. :group 'message-sending
  604. :version "23.2"
  605. :initialize 'custom-initialize-default
  606. :link '(custom-manual "(message)Mail Variables")
  607. :group 'message-mail)
  608. (defcustom message-send-news-function 'message-send-news
  609. "Function to call to send the current buffer as news.
  610. The headers should be delimited by a line whose contents match the
  611. variable `mail-header-separator'."
  612. :group 'message-sending
  613. :group 'message-news
  614. :link '(custom-manual "(message)News Variables")
  615. :type 'function)
  616. (defcustom message-reply-to-function nil
  617. "If non-nil, function that should return a list of headers.
  618. This function should pick out addresses from the To, Cc, and From headers
  619. and respond with new To and Cc headers."
  620. :group 'message-interface
  621. :link '(custom-manual "(message)Reply")
  622. :type '(choice function (const nil)))
  623. (defcustom message-wide-reply-to-function nil
  624. "If non-nil, function that should return a list of headers.
  625. This function should pick out addresses from the To, Cc, and From headers
  626. and respond with new To and Cc headers."
  627. :group 'message-interface
  628. :link '(custom-manual "(message)Wide Reply")
  629. :type '(choice function (const nil)))
  630. (defcustom message-followup-to-function nil
  631. "If non-nil, function that should return a list of headers.
  632. This function should pick out addresses from the To, Cc, and From headers
  633. and respond with new To and Cc headers."
  634. :group 'message-interface
  635. :link '(custom-manual "(message)Followup")
  636. :type '(choice function (const nil)))
  637. (defcustom message-extra-wide-headers nil
  638. "If non-nil, a list of additional address headers.
  639. These are used when composing a wide reply."
  640. :group 'message-sending
  641. :type '(repeat string))
  642. (defcustom message-use-followup-to 'ask
  643. "*Specifies what to do with Followup-To header.
  644. If nil, always ignore the header. If it is t, use its value, but
  645. query before using the \"poster\" value. If it is the symbol `ask',
  646. always query the user whether to use the value. If it is the symbol
  647. `use', always use the value."
  648. :group 'message-interface
  649. :link '(custom-manual "(message)Followup")
  650. :type '(choice (const :tag "ignore" nil)
  651. (const :tag "use & query" t)
  652. (const use)
  653. (const ask)))
  654. (defcustom message-use-mail-followup-to 'use
  655. "*Specifies what to do with Mail-Followup-To header.
  656. If nil, always ignore the header. If it is the symbol `ask', always
  657. query the user whether to use the value. If it is the symbol `use',
  658. always use the value."
  659. :version "22.1"
  660. :group 'message-interface
  661. :link '(custom-manual "(message)Mailing Lists")
  662. :type '(choice (const :tag "ignore" nil)
  663. (const use)
  664. (const ask)))
  665. (defcustom message-subscribed-address-functions nil
  666. "*Specifies functions for determining list subscription.
  667. If nil, do not attempt to determine list subscription with functions.
  668. If non-nil, this variable contains a list of functions which return
  669. regular expressions to match lists. These functions can be used in
  670. conjunction with `message-subscribed-regexps' and
  671. `message-subscribed-addresses'."
  672. :version "22.1"
  673. :group 'message-interface
  674. :link '(custom-manual "(message)Mailing Lists")
  675. :type '(repeat sexp))
  676. (defcustom message-subscribed-address-file nil
  677. "*A file containing addresses the user is subscribed to.
  678. If nil, do not look at any files to determine list subscriptions. If
  679. non-nil, each line of this file should be a mailing list address."
  680. :version "22.1"
  681. :group 'message-interface
  682. :link '(custom-manual "(message)Mailing Lists")
  683. :type '(radio file (const nil)))
  684. (defcustom message-subscribed-addresses nil
  685. "*Specifies a list of addresses the user is subscribed to.
  686. If nil, do not use any predefined list subscriptions. This list of
  687. addresses can be used in conjunction with
  688. `message-subscribed-address-functions' and `message-subscribed-regexps'."
  689. :version "22.1"
  690. :group 'message-interface
  691. :link '(custom-manual "(message)Mailing Lists")
  692. :type '(repeat string))
  693. (defcustom message-subscribed-regexps nil
  694. "*Specifies a list of addresses the user is subscribed to.
  695. If nil, do not use any predefined list subscriptions. This list of
  696. regular expressions can be used in conjunction with
  697. `message-subscribed-address-functions' and `message-subscribed-addresses'."
  698. :version "22.1"
  699. :group 'message-interface
  700. :link '(custom-manual "(message)Mailing Lists")
  701. :type '(repeat regexp))
  702. (defcustom message-allow-no-recipients 'ask
  703. "Specifies what to do when there are no recipients other than Gcc/Fcc.
  704. If it is the symbol `always', the posting is allowed. If it is the
  705. symbol `never', the posting is not allowed. If it is the symbol
  706. `ask', you are prompted."
  707. :version "22.1"
  708. :group 'message-interface
  709. :link '(custom-manual "(message)Message Headers")
  710. :type '(choice (const always)
  711. (const never)
  712. (const ask)))
  713. (defcustom message-sendmail-f-is-evil nil
  714. "*Non-nil means don't add \"-f username\" to the sendmail command line.
  715. Doing so would be even more evil than leaving it out."
  716. :group 'message-sending
  717. :link '(custom-manual "(message)Mail Variables")
  718. :type 'boolean)
  719. (defcustom message-sendmail-envelope-from
  720. ;; `mail-envelope-from' is unavailable unless sendmail.el is loaded.
  721. (if (boundp 'mail-envelope-from) mail-envelope-from)
  722. "*Envelope-from when sending mail with sendmail.
  723. If this is nil, use `user-mail-address'. If it is the symbol
  724. `header', use the From: header of the message."
  725. :version "23.2"
  726. :type '(choice (string :tag "From name")
  727. (const :tag "Use From: header from message" header)
  728. (const :tag "Use `user-mail-address'" nil))
  729. :link '(custom-manual "(message)Mail Variables")
  730. :group 'message-sending)
  731. (defcustom message-sendmail-extra-arguments nil
  732. "Additional arguments to `sendmail-program'."
  733. ;; E.g. '("-a" "account") for msmtp
  734. :version "23.1" ;; No Gnus
  735. :type '(repeat string)
  736. ;; :link '(custom-manual "(message)Mail Variables")
  737. :group 'message-sending)
  738. ;; qmail-related stuff
  739. (defcustom message-qmail-inject-program "/var/qmail/bin/qmail-inject"
  740. "Location of the qmail-inject program."
  741. :group 'message-sending
  742. :link '(custom-manual "(message)Mail Variables")
  743. :type 'file)
  744. (defcustom message-qmail-inject-args nil
  745. "Arguments passed to qmail-inject programs.
  746. This should be a list of strings, one string for each argument.
  747. It may also be a function.
  748. For e.g., if you wish to set the envelope sender address so that bounces
  749. go to the right place or to deal with listserv's usage of that address, you
  750. might set this variable to '(\"-f\" \"you@some.where\")."
  751. :group 'message-sending
  752. :link '(custom-manual "(message)Mail Variables")
  753. :type '(choice (function)
  754. (repeat string)))
  755. (defvar gnus-post-method)
  756. (defvar gnus-select-method)
  757. (defcustom message-post-method
  758. (cond ((and (boundp 'gnus-post-method)
  759. (listp gnus-post-method)
  760. gnus-post-method)
  761. gnus-post-method)
  762. ((boundp 'gnus-select-method)
  763. gnus-select-method)
  764. (t '(nnspool "")))
  765. "*Method used to post news.
  766. Note that when posting from inside Gnus, for instance, this
  767. variable isn't used."
  768. :group 'message-news
  769. :group 'message-sending
  770. ;; This should be the `gnus-select-method' widget, but that might
  771. ;; create a dependence to `gnus.el'.
  772. :type 'sexp)
  773. (defcustom message-generate-headers-first nil
  774. "Which headers should be generated before starting to compose a message.
  775. If t, generate all required headers. This can also be a list of headers to
  776. generate. The variables `message-required-news-headers' and
  777. `message-required-mail-headers' specify which headers to generate.
  778. Note that the variable `message-deletable-headers' specifies headers which
  779. are to be deleted and then re-generated before sending, so this variable
  780. will not have a visible effect for those headers."
  781. :group 'message-headers
  782. :link '(custom-manual "(message)Message Headers")
  783. :type '(choice (const :tag "None" nil)
  784. (const :tag "All" t)
  785. (repeat (sexp :tag "Header"))))
  786. (defcustom message-fill-column 72
  787. "Column beyond which automatic line-wrapping should happen.
  788. Local value for message buffers. If non-nil, also turn on
  789. auto-fill in message buffers."
  790. :group 'message-various
  791. ;; :link '(custom-manual "(message)Message Headers")
  792. :type '(choice (const :tag "Don't turn on auto fill" nil)
  793. (integer)))
  794. (defcustom message-setup-hook nil
  795. "Normal hook, run each time a new outgoing message is initialized.
  796. The function `message-setup' runs this hook."
  797. :group 'message-various
  798. :link '(custom-manual "(message)Various Message Variables")
  799. :type 'hook)
  800. (defcustom message-cancel-hook nil
  801. "Hook run when canceling articles."
  802. :group 'message-various
  803. :link '(custom-manual "(message)Various Message Variables")
  804. :type 'hook)
  805. (defcustom message-signature-setup-hook nil
  806. "Normal hook, run each time a new outgoing message is initialized.
  807. It is run after the headers have been inserted and before
  808. the signature is inserted."
  809. :group 'message-various
  810. :link '(custom-manual "(message)Various Message Variables")
  811. :type 'hook)
  812. (defcustom message-mode-hook nil
  813. "Hook run in message mode buffers."
  814. :group 'message-various
  815. :type 'hook)
  816. (defcustom message-header-hook nil
  817. "Hook run in a message mode buffer narrowed to the headers."
  818. :group 'message-various
  819. :type 'hook)
  820. (defcustom message-header-setup-hook nil
  821. "Hook called narrowed to the headers when setting up a message buffer."
  822. :group 'message-various
  823. :link '(custom-manual "(message)Various Message Variables")
  824. :type 'hook)
  825. (defcustom message-minibuffer-local-map
  826. (let ((map (make-sparse-keymap 'message-minibuffer-local-map)))
  827. (set-keymap-parent map minibuffer-local-map)
  828. map)
  829. "Keymap for `message-read-from-minibuffer'."
  830. ;; FIXME improve type.
  831. :type '(restricted-sexp :match-alternatives (symbolp keymapp))
  832. :version "22.1"
  833. :group 'message-various)
  834. (defcustom message-citation-line-function 'message-insert-citation-line
  835. "*Function called to insert the \"Whomever writes:\" line.
  836. Predefined functions include `message-insert-citation-line' and
  837. `message-insert-formatted-citation-line' (see the variable
  838. `message-citation-line-format').
  839. Note that Gnus provides a feature where the reader can click on
  840. `writes:' to hide the cited text. If you change this line too much,
  841. people who read your message will have to change their Gnus
  842. configuration. See the variable `gnus-cite-attribution-suffix'."
  843. :type '(choice
  844. (function-item :tag "plain" message-insert-citation-line)
  845. (function-item :tag "formatted" message-insert-formatted-citation-line)
  846. (function :tag "Other"))
  847. :link '(custom-manual "(message)Insertion Variables")
  848. :group 'message-insertion)
  849. (defcustom message-citation-line-format "On %a, %b %d %Y, %N wrote:\n"
  850. "Format of the \"Whomever writes:\" line.
  851. The string is formatted using `format-spec'. The following constructs
  852. are replaced:
  853. %f The full From, e.g. \"John Doe <john.doe@example.invalid>\".
  854. %n The mail address, e.g. \"john.doe@example.invalid\".
  855. %N The real name if present, e.g.: \"John Doe\", else fall
  856. back to the mail address.
  857. %F The first name if present, e.g.: \"John\", else fall
  858. back to the mail address.
  859. %L The last name if present, e.g.: \"Doe\".
  860. %Z, %z The time zone in the numeric form, e.g.:\"+0000\".
  861. All other format specifiers are passed to `format-time-string'
  862. which is called using the date from the article your replying to, but
  863. the date in the formatted string will be expressed in the author's
  864. time zone as much as possible.
  865. Extracting the first (%F) and last name (%L) is done heuristically,
  866. so you should always check it yourself.
  867. Please also read the note in the documentation of
  868. `message-citation-line-function'."
  869. :type '(choice (const :tag "Plain" "%f writes:")
  870. (const :tag "Include date" "On %a, %b %d %Y, %n wrote:")
  871. string)
  872. :link '(custom-manual "(message)Insertion Variables")
  873. :version "23.1" ;; No Gnus
  874. :group 'message-insertion)
  875. (defcustom message-yank-prefix mail-yank-prefix
  876. "*Prefix inserted on the lines of yanked messages.
  877. Fix `message-cite-prefix-regexp' if it is set to an abnormal value.
  878. See also `message-yank-cited-prefix' and `message-yank-empty-prefix'."
  879. :version "23.2"
  880. :type 'string
  881. :link '(custom-manual "(message)Insertion Variables")
  882. :group 'message-insertion)
  883. (defcustom message-yank-cited-prefix ">"
  884. "*Prefix inserted on cited lines of yanked messages.
  885. Fix `message-cite-prefix-regexp' if it is set to an abnormal value.
  886. See also `message-yank-prefix' and `message-yank-empty-prefix'."
  887. :version "22.1"
  888. :type 'string
  889. :link '(custom-manual "(message)Insertion Variables")
  890. :group 'message-insertion)
  891. (defcustom message-yank-empty-prefix ">"
  892. "*Prefix inserted on empty lines of yanked messages.
  893. See also `message-yank-prefix' and `message-yank-cited-prefix'."
  894. :version "22.1"
  895. :type 'string
  896. :link '(custom-manual "(message)Insertion Variables")
  897. :group 'message-insertion)
  898. (defcustom message-indentation-spaces mail-indentation-spaces
  899. "*Number of spaces to insert at the beginning of each cited line.
  900. Used by `message-yank-original' via `message-yank-cite'."
  901. :version "23.2"
  902. :group 'message-insertion
  903. :link '(custom-manual "(message)Insertion Variables")
  904. :type 'integer)
  905. (defcustom message-cite-function 'message-cite-original-without-signature
  906. "*Function for citing an original message.
  907. Predefined functions include `message-cite-original' and
  908. `message-cite-original-without-signature'.
  909. Note that these functions use `mail-citation-hook' if that is non-nil."
  910. :type '(radio (function-item message-cite-original)
  911. (function-item message-cite-original-without-signature)
  912. (function-item sc-cite-original)
  913. (function :tag "Other"))
  914. :link '(custom-manual "(message)Insertion Variables")
  915. :version "22.3" ;; Gnus 5.10.12 (changed default)
  916. :group 'message-insertion)
  917. (defcustom message-indent-citation-function 'message-indent-citation
  918. "*Function for modifying a citation just inserted in the mail buffer.
  919. This can also be a list of functions. Each function can find the
  920. citation between (point) and (mark t). And each function should leave
  921. point and mark around the citation text as modified."
  922. :type 'function
  923. :link '(custom-manual "(message)Insertion Variables")
  924. :group 'message-insertion)
  925. (defcustom message-signature mail-signature
  926. "*String to be inserted at the end of the message buffer.
  927. If t, the `message-signature-file' file will be inserted instead.
  928. If a function, the result from the function will be used instead.
  929. If a form, the result from the form will be used instead."
  930. :version "23.2"
  931. :type 'sexp
  932. :link '(custom-manual "(message)Insertion Variables")
  933. :group 'message-insertion)
  934. (defcustom message-signature-file mail-signature-file
  935. "*Name of file containing the text inserted at end of message buffer.
  936. Ignored if the named file doesn't exist.
  937. If nil, don't insert a signature.
  938. If a path is specified, the value of `message-signature-directory' is ignored,
  939. even if set."
  940. :version "23.2"
  941. :type '(choice file (const :tags "None" nil))
  942. :link '(custom-manual "(message)Insertion Variables")
  943. :group 'message-insertion)
  944. (defcustom message-signature-directory nil
  945. "*Name of directory containing signature files.
  946. Comes in handy if you have many such files, handled via posting styles for
  947. instance.
  948. If nil, `message-signature-file' is expected to specify the directory if
  949. needed."
  950. :type '(choice string (const :tags "None" nil))
  951. :link '(custom-manual "(message)Insertion Variables")
  952. :group 'message-insertion)
  953. (defcustom message-signature-insert-empty-line t
  954. "*If non-nil, insert an empty line before the signature separator."
  955. :version "22.1"
  956. :type 'boolean
  957. :link '(custom-manual "(message)Insertion Variables")
  958. :group 'message-insertion)
  959. (defcustom message-cite-reply-position 'traditional
  960. "*Where the reply should be positioned.
  961. If `traditional', reply inline.
  962. If `above', reply above quoted text.
  963. If `below', reply below quoted text.
  964. Note: Many newsgroups frown upon nontraditional reply styles. You
  965. probably want to set this variable only for specific groups,
  966. e.g. using `gnus-posting-styles':
  967. (eval (set (make-local-variable 'message-cite-reply-position) 'above))"
  968. :version "24.1"
  969. :type '(choice (const :tag "Reply inline" traditional)
  970. (const :tag "Reply above" above)
  971. (const :tag "Reply below" below))
  972. :group 'message-insertion)
  973. (defcustom message-cite-style nil
  974. "*The overall style to be used when yanking cited text.
  975. Value is either nil (no variable overrides) or a let-style list
  976. of pairs (VARIABLE VALUE) that will be bound in
  977. `message-yank-original' to do the quoting.
  978. Presets to impersonate popular mail agents are found in the
  979. message-cite-style-* variables. This variable is intended for
  980. use in `gnus-posting-styles', such as:
  981. ((posting-from-work-p) (eval (set (make-local-variable 'message-cite-style) message-cite-style-outlook)))"
  982. :version "24.1"
  983. :group 'message-insertion
  984. :type '(choice (const :tag "Do not override variables" :value nil)
  985. (const :tag "MS Outlook" :value message-cite-style-outlook)
  986. (const :tag "Mozilla Thunderbird" :value message-cite-style-thunderbird)
  987. (const :tag "Gmail" :value message-cite-style-gmail)
  988. (variable :tag "User-specified")))
  989. (defconst message-cite-style-outlook
  990. '((message-cite-function 'message-cite-original)
  991. (message-citation-line-function 'message-insert-formatted-citation-line)
  992. (message-cite-reply-position 'above)
  993. (message-yank-prefix "")
  994. (message-yank-cited-prefix "")
  995. (message-yank-empty-prefix "")
  996. (message-citation-line-format "\n\n-----------------------\nOn %a, %b %d %Y, %N wrote:\n"))
  997. "Message citation style used by MS Outlook. Use with message-cite-style.")
  998. (defconst message-cite-style-thunderbird
  999. '((message-cite-function 'message-cite-original)
  1000. (message-citation-line-function 'message-insert-formatted-citation-line)
  1001. (message-cite-reply-position 'above)
  1002. (message-yank-prefix "> ")
  1003. (message-yank-cited-prefix ">")
  1004. (message-yank-empty-prefix ">")
  1005. (message-citation-line-format "On %D %R %p, %N wrote:"))
  1006. "Message citation style used by Mozilla Thunderbird. Use with message-cite-style.")
  1007. (defconst message-cite-style-gmail
  1008. '((message-cite-function 'message-cite-original)
  1009. (message-citation-line-function 'message-insert-formatted-citation-line)
  1010. (message-cite-reply-position 'above)
  1011. (message-yank-prefix " ")
  1012. (message-yank-cited-prefix " ")
  1013. (message-yank-empty-prefix " ")
  1014. (message-citation-line-format "On %e %B %Y %R, %f wrote:\n"))
  1015. "Message citation style used by Gmail. Use with message-cite-style.")
  1016. (defcustom message-distribution-function nil
  1017. "*Function called to return a Distribution header."
  1018. :group 'message-news
  1019. :group 'message-headers
  1020. :link '(custom-manual "(message)News Headers")
  1021. :type '(choice function (const nil)))
  1022. (defcustom message-expires 14
  1023. "Number of days before your article expires."
  1024. :group 'message-news
  1025. :group 'message-headers
  1026. :link '(custom-manual "(message)News Headers")
  1027. :type 'integer)
  1028. (defcustom message-user-path nil
  1029. "If nil, use the NNTP server name in the Path header.
  1030. If stringp, use this; if non-nil, use no host name (user name only)."
  1031. :group 'message-news
  1032. :group 'message-headers
  1033. :link '(custom-manual "(message)News Headers")
  1034. :type '(choice (const :tag "nntp" nil)
  1035. (string :tag "name")
  1036. (sexp :tag "none" :format "%t" t)))
  1037. ;; This can be the name of a buffer, or a cons cell (FUNCTION . ARGS)
  1038. ;; for yanking the original buffer.
  1039. (defvar message-reply-buffer nil)
  1040. (defvar message-reply-headers nil
  1041. "The headers of the current replied article.
  1042. It is a vector of the following headers:
  1043. \[number subject from date id references chars lines xref extra].")
  1044. (defvar message-newsreader nil)
  1045. (defvar message-mailer nil)
  1046. (defvar message-sent-message-via nil)
  1047. (defvar message-checksum nil)
  1048. (defvar message-send-actions nil
  1049. "A list of actions to be performed upon successful sending of a message.")
  1050. (defvar message-return-action nil
  1051. "Action to return to the caller after sending or postponing a message.")
  1052. (defvar message-exit-actions nil
  1053. "A list of actions to be performed upon exiting after sending a message.")
  1054. (defvar message-kill-actions nil
  1055. "A list of actions to be performed before killing a message buffer.")
  1056. (defvar message-postpone-actions nil
  1057. "A list of actions to be performed after postponing a message.")
  1058. (define-widget 'message-header-lines 'text
  1059. "All header lines must be LFD terminated."
  1060. :format "%{%t%}:%n%v"
  1061. :valid-regexp "^\\'"
  1062. :error "All header lines must be newline terminated")
  1063. (defcustom message-default-headers ""
  1064. "Header lines to be inserted in outgoing messages.
  1065. This can be set to a string containing or a function returning
  1066. header lines to be inserted before you edit the message, so you
  1067. can edit or delete these lines. If set to a function, it is
  1068. called and its result is inserted."
  1069. :version "23.2"
  1070. :group 'message-headers
  1071. :link '(custom-manual "(message)Message Headers")
  1072. :type '(choice
  1073. (message-header-lines :tag "String")
  1074. (function :tag "Function")))
  1075. (defcustom message-default-mail-headers
  1076. ;; Ease the transition from mail-mode to message-mode. See bugs#4431, 5555.
  1077. (concat (if (and (boundp 'mail-default-reply-to)
  1078. (stringp mail-default-reply-to))
  1079. (format "Reply-to: %s\n" mail-default-reply-to))
  1080. (if (and (boundp 'mail-self-blind)
  1081. mail-self-blind)
  1082. (format "BCC: %s\n" user-mail-address))
  1083. (if (and (boundp 'mail-archive-file-name)
  1084. (stringp mail-archive-file-name))
  1085. (format "FCC: %s\n" mail-archive-file-name))
  1086. ;; Use the value of `mail-default-headers' if available.
  1087. ;; Note: as for XEmacs 21.4 and 21.5, it is unavailable
  1088. ;; unless sendmail.el is loaded.
  1089. (if (boundp 'mail-default-headers)
  1090. mail-default-headers))
  1091. "*A string of header lines to be inserted in outgoing mails."
  1092. :version "23.2"
  1093. :group 'message-headers
  1094. :group 'message-mail
  1095. :link '(custom-manual "(message)Mail Headers")
  1096. :type 'message-header-lines)
  1097. (defcustom message-default-news-headers ""
  1098. "*A string of header lines to be inserted in outgoing news articles."
  1099. :group 'message-headers
  1100. :group 'message-news
  1101. :link '(custom-manual "(message)News Headers")
  1102. :type 'message-header-lines)
  1103. ;; Note: could use /usr/ucb/mail instead of sendmail;
  1104. ;; options -t, and -v if not interactive.
  1105. (defcustom message-mailer-swallows-blank-line
  1106. (if (and (string-match "sparc-sun-sunos\\(\\'\\|[^5]\\)"
  1107. system-configuration)
  1108. (file-readable-p "/etc/sendmail.cf")
  1109. (with-temp-buffer
  1110. (insert-file-contents "/etc/sendmail.cf")
  1111. (goto-char (point-min))
  1112. (let ((case-fold-search nil))
  1113. (re-search-forward "^OR\\>" nil t))))
  1114. ;; According to RFC822, "The field-name must be composed of printable
  1115. ;; ASCII characters (i. e., characters that have decimal values between
  1116. ;; 33 and 126, except colon)", i. e., any chars except ctl chars,
  1117. ;; space, or colon.
  1118. '(looking-at "[ \t]\\|[][!\"#$%&'()*+,-./0-9;<=>?@A-Z\\\\^_`a-z{|}~]+:"))
  1119. "*Set this non-nil if the system's mailer runs the header and body together.
  1120. \(This problem exists on Sunos 4 when sendmail is run in remote mode.)
  1121. The value should be an expression to test whether the problem will
  1122. actually occur."
  1123. :group 'message-sending
  1124. :link '(custom-manual "(message)Mail Variables")
  1125. :type 'sexp)
  1126. ;;;###autoload
  1127. (define-mail-user-agent 'message-user-agent
  1128. 'message-mail 'message-send-and-exit
  1129. 'message-kill-buffer 'message-send-hook)
  1130. (defvar message-mh-deletable-headers '(Message-ID Date Lines Sender)
  1131. "If non-nil, delete the deletable headers before feeding to mh.")
  1132. (defvar message-send-method-alist
  1133. '((news message-news-p message-send-via-news)
  1134. (mail message-mail-p message-send-via-mail))
  1135. "Alist of ways to send outgoing messages.
  1136. Each element has the form
  1137. \(TYPE PREDICATE FUNCTION)
  1138. where TYPE is a symbol that names the method; PREDICATE is a function
  1139. called without any parameters to determine whether the message is
  1140. a message of type TYPE; and FUNCTION is a function to be called if
  1141. PREDICATE returns non-nil. FUNCTION is called with one parameter --
  1142. the prefix.")
  1143. (defcustom message-mail-alias-type 'abbrev
  1144. "*What alias expansion type to use in Message buffers.
  1145. The default is `abbrev', which uses mailabbrev. `ecomplete' uses
  1146. an electric completion mode. nil switches mail aliases off.
  1147. This can also be a list of values."
  1148. :group 'message
  1149. :link '(custom-manual "(message)Mail Aliases")
  1150. :type '(choice (const :tag "Use Mailabbrev" abbrev)
  1151. (const :tag "Use ecomplete" ecomplete)
  1152. (const :tag "No expansion" nil)))
  1153. (defcustom message-self-insert-commands '(self-insert-command)
  1154. "List of `self-insert-command's used to trigger ecomplete.
  1155. When one of those commands is invoked to enter a character in To or Cc
  1156. header, ecomplete will suggest the candidates of recipients (see also
  1157. `message-mail-alias-type'). If you use some tool to enter non-ASCII
  1158. text and it replaces `self-insert-command' with the other command, e.g.
  1159. `egg-self-insert-command', you may want to add it to this list."
  1160. :group 'message-various
  1161. :type '(repeat function))
  1162. (defcustom message-auto-save-directory
  1163. (if (file-writable-p message-directory)
  1164. (file-name-as-directory (expand-file-name "drafts" message-directory))
  1165. "~/")
  1166. "*Directory where Message auto-saves buffers if Gnus isn't running.
  1167. If nil, Message won't auto-save."
  1168. :group 'message-buffers
  1169. :link '(custom-manual "(message)Various Message Variables")
  1170. :type '(choice directory (const :tag "Don't auto-save" nil)))
  1171. (defcustom message-default-charset
  1172. (and (not (mm-multibyte-p)) 'iso-8859-1)
  1173. "Default charset used in non-MULE Emacsen.
  1174. If nil, you might be asked to input the charset."
  1175. :version "21.1"
  1176. :group 'message
  1177. :link '(custom-manual "(message)Various Message Variables")
  1178. :type 'symbol)
  1179. (defcustom message-dont-reply-to-names
  1180. (and (boundp 'mail-dont-reply-to-names) mail-dont-reply-to-names)
  1181. "*Addresses to prune when doing wide replies.
  1182. This can be a regexp or a list of regexps. Also, a value of nil means
  1183. exclude your own user name only."
  1184. :version "24.3"
  1185. :group 'message
  1186. :link '(custom-manual "(message)Wide Reply")
  1187. :type '(choice (const :tag "Yourself" nil)
  1188. regexp
  1189. (repeat :tag "Regexp List" regexp)))
  1190. (defsubst message-dont-reply-to-names ()
  1191. (gmm-regexp-concat message-dont-reply-to-names))
  1192. (defvar message-shoot-gnksa-feet nil
  1193. "*A list of GNKSA feet you are allowed to shoot.
  1194. Gnus gives you all the opportunity you could possibly want for
  1195. shooting yourself in the foot. Also, Gnus allows you to shoot the
  1196. feet of Good Net-Keeping Seal of Approval. The following are foot
  1197. candidates:
  1198. `empty-article' Allow you to post an empty article;
  1199. `quoted-text-only' Allow you to post quoted text only;
  1200. `multiple-copies' Allow you to post multiple copies;
  1201. `cancel-messages' Allow you to cancel or supersede messages from
  1202. your other email addresses;
  1203. `canlock-verify' Allow you to cancel messages without verifying canlock.")
  1204. (defsubst message-gnksa-enable-p (feature)
  1205. (or (not (listp message-shoot-gnksa-feet))
  1206. (memq feature message-shoot-gnksa-feet)))
  1207. (defcustom message-hidden-headers '("^References:" "^Face:" "^X-Face:"
  1208. "^X-Draft-From:")
  1209. "Regexp of headers to be hidden when composing new messages.
  1210. This can also be a list of regexps to match headers. Or a list
  1211. starting with `not' and followed by regexps."
  1212. :version "22.1"
  1213. :group 'message
  1214. :link '(custom-manual "(message)Message Headers")
  1215. :type '(choice
  1216. :format "%{%t%}: %[Value Type%] %v"
  1217. (regexp :menu-tag "regexp" :format "regexp\n%t: %v")
  1218. (repeat :menu-tag "(regexp ...)" :format "(regexp ...)\n%v%i"
  1219. (regexp :format "%t: %v"))
  1220. (cons :menu-tag "(not regexp ...)" :format "(not regexp ...)\n%v"
  1221. (const not)
  1222. (repeat :format "%v%i"
  1223. (regexp :format "%t: %v")))))
  1224. (defcustom message-cite-articles-with-x-no-archive t
  1225. "If non-nil, cite text from articles that has X-No-Archive set."
  1226. :group 'message
  1227. :type 'boolean)
  1228. ;;; Internal variables.
  1229. ;;; Well, not really internal.
  1230. (defvar message-mode-syntax-table
  1231. (let ((table (copy-syntax-table text-mode-syntax-table)))
  1232. (modify-syntax-entry ?% ". " table)
  1233. (modify-syntax-entry ?> ". " table)
  1234. (modify-syntax-entry ?< ". " table)
  1235. table)
  1236. "Syntax table used while in Message mode.")
  1237. (defface message-header-to
  1238. '((((class color)
  1239. (background dark))
  1240. (:foreground "DarkOliveGreen1" :bold t))
  1241. (((class color)
  1242. (background light))
  1243. (:foreground "MidnightBlue" :bold t))
  1244. (t
  1245. (:bold t :italic t)))
  1246. "Face used for displaying From headers."
  1247. :group 'message-faces)
  1248. ;; backward-compatibility alias
  1249. (put 'message-header-to-face 'face-alias 'message-header-to)
  1250. (put 'message-header-to-face 'obsolete-face "22.1")
  1251. (defface message-header-cc
  1252. '((((class color)
  1253. (background dark))
  1254. (:foreground "chartreuse1" :bold t))
  1255. (((class color)
  1256. (background light))
  1257. (:foreground "MidnightBlue"))
  1258. (t
  1259. (:bold t)))
  1260. "Face used for displaying Cc headers."
  1261. :group 'message-faces)
  1262. ;; backward-compatibility alias
  1263. (put 'message-header-cc-face 'face-alias 'message-header-cc)
  1264. (put 'message-header-cc-face 'obsolete-face "22.1")
  1265. (defface message-header-subject
  1266. '((((class color)
  1267. (background dark))
  1268. (:foreground "OliveDrab1"))
  1269. (((class color)
  1270. (background light))
  1271. (:foreground "navy blue" :bold t))
  1272. (t
  1273. (:bold t)))
  1274. "Face used for displaying subject headers."
  1275. :group 'message-faces)
  1276. ;; backward-compatibility alias
  1277. (put 'message-header-subject-face 'face-alias 'message-header-subject)
  1278. (put 'message-header-subject-face 'obsolete-face "22.1")
  1279. (defface message-header-newsgroups
  1280. '((((class color)
  1281. (background dark))
  1282. (:foreground "yellow" :bold t :italic t))
  1283. (((class color)
  1284. (background light))
  1285. (:foreground "blue4" :bold t :italic t))
  1286. (t
  1287. (:bold t :italic t)))
  1288. "Face used for displaying newsgroups headers."
  1289. :group 'message-faces)
  1290. ;; backward-compatibility alias
  1291. (put 'message-header-newsgroups-face 'face-alias 'message-header-newsgroups)
  1292. (put 'message-header-newsgroups-face 'obsolete-face "22.1")
  1293. (defface message-header-other
  1294. '((((class color)
  1295. (background dark))
  1296. (:foreground "VioletRed1"))
  1297. (((class color)
  1298. (background light))
  1299. (:foreground "steel blue"))
  1300. (t
  1301. (:bold t :italic t)))
  1302. "Face used for displaying newsgroups headers."
  1303. :group 'message-faces)
  1304. ;; backward-compatibility alias
  1305. (put 'message-header-other-face 'face-alias 'message-header-other)
  1306. (put 'message-header-other-face 'obsolete-face "22.1")
  1307. (defface message-header-name
  1308. '((((class color)
  1309. (background dark))
  1310. (:foreground "green"))
  1311. (((class color)
  1312. (background light))
  1313. (:foreground "cornflower blue"))
  1314. (t
  1315. (:bold t)))
  1316. "Face used for displaying header names."
  1317. :group 'message-faces)
  1318. ;; backward-compatibility alias
  1319. (put 'message-header-name-face 'face-alias 'message-header-name)
  1320. (put 'message-header-name-face 'obsolete-face "22.1")
  1321. (defface message-header-xheader
  1322. '((((class color)
  1323. (background dark))
  1324. (:foreground "DeepSkyBlue1"))
  1325. (((class color)
  1326. (background light))
  1327. (:foreground "blue"))
  1328. (t
  1329. (:bold t)))
  1330. "Face used for displaying X-Header headers."
  1331. :group 'message-faces)
  1332. ;; backward-compatibility alias
  1333. (put 'message-header-xheader-face 'face-alias 'message-header-xheader)
  1334. (put 'message-header-xheader-face 'obsolete-face "22.1")
  1335. (defface message-separator
  1336. '((((class color)
  1337. (background dark))
  1338. (:foreground "LightSkyBlue1"))
  1339. (((class color)
  1340. (background light))
  1341. (:foreground "brown"))
  1342. (t
  1343. (:bold t)))
  1344. "Face used for displaying the separator."
  1345. :group 'message-faces)
  1346. ;; backward-compatibility alias
  1347. (put 'message-separator-face 'face-alias 'message-separator)
  1348. (put 'message-separator-face 'obsolete-face "22.1")
  1349. (defface message-cited-text
  1350. '((((class color)
  1351. (background dark))
  1352. (:foreground "LightPink1"))
  1353. (((class color)
  1354. (background light))
  1355. (:foreground "red"))
  1356. (t
  1357. (:bold t)))
  1358. "Face used for displaying cited text names."
  1359. :group 'message-faces)
  1360. ;; backward-compatibility alias
  1361. (put 'message-cited-text-face 'face-alias 'message-cited-text)
  1362. (put 'message-cited-text-face 'obsolete-face "22.1")
  1363. (defface message-mml
  1364. '((((class color)
  1365. (background dark))
  1366. (:foreground "MediumSpringGreen"))
  1367. (((class color)
  1368. (background light))
  1369. (:foreground "ForestGreen"))
  1370. (t
  1371. (:bold t)))
  1372. "Face used for displaying MML."
  1373. :group 'message-faces)
  1374. ;; backward-compatibility alias
  1375. (put 'message-mml-face 'face-alias 'message-mml)
  1376. (put 'message-mml-face 'obsolete-face "22.1")
  1377. (defun message-font-lock-make-header-matcher (regexp)
  1378. (let ((form
  1379. `(lambda (limit)
  1380. (let ((start (point)))
  1381. (save-restriction
  1382. (widen)
  1383. (goto-char (point-min))
  1384. (if (re-search-forward
  1385. (concat "^" (regexp-quote mail-header-separator) "$")
  1386. nil t)
  1387. (setq limit (min limit (match-beginning 0))))
  1388. (goto-char start))
  1389. (and (< start limit)
  1390. (re-search-forward ,regexp limit t))))))
  1391. (if (featurep 'bytecomp)
  1392. (byte-compile form)
  1393. form)))
  1394. (defvar message-font-lock-keywords
  1395. (let ((content "[ \t]*\\(.+\\(\n[ \t].*\\)*\\)\n?"))
  1396. `((,(message-font-lock-make-header-matcher
  1397. (concat "^\\([Tt]o:\\)" content))
  1398. (1 'message-header-name)
  1399. (2 'message-header-to nil t))
  1400. (,(message-font-lock-make-header-matcher
  1401. (concat "^\\(^[GBF]?[Cc][Cc]:\\|^[Rr]eply-[Tt]o:\\)" content))
  1402. (1 'message-header-name)
  1403. (2 'message-header-cc nil t))
  1404. (,(message-font-lock-make-header-matcher
  1405. (concat "^\\([Ss]ubject:\\)" content))
  1406. (1 'message-header-name)
  1407. (2 'message-header-subject nil t))
  1408. (,(message-font-lock-make-header-matcher
  1409. (concat "^\\([Nn]ewsgroups:\\|Followup-[Tt]o:\\)" content))
  1410. (1 'message-header-name)
  1411. (2 'message-header-newsgroups nil t))
  1412. (,(message-font-lock-make-header-matcher
  1413. (concat "^\\(X-[A-Za-z0-9-]+:\\|In-Reply-To:\\)" content))
  1414. (1 'message-header-name)
  1415. (2 'message-header-xheader))
  1416. (,(message-font-lock-make-header-matcher
  1417. (concat "^\\([A-Z][^: \n\t]+:\\)" content))
  1418. (1 'message-header-name)
  1419. (2 'message-header-other nil t))
  1420. ,@(if (and mail-header-separator
  1421. (not (equal mail-header-separator "")))
  1422. `((,(concat "^\\(" (regexp-quote mail-header-separator) "\\)$")
  1423. 1 'message-separator))
  1424. nil)
  1425. ((lambda (limit)
  1426. (re-search-forward (concat "^\\("
  1427. message-cite-prefix-regexp
  1428. "\\).*")
  1429. limit t))
  1430. (0 'message-cited-text))
  1431. ("<#/?\\(multipart\\|part\\|external\\|mml\\|secure\\)[^>]*>"
  1432. (0 'message-mml))))
  1433. "Additional expressions to highlight in Message mode.")
  1434. ;; XEmacs does it like this. For Emacs, we have to set the
  1435. ;; `font-lock-defaults' buffer-local variable.
  1436. (put 'message-mode 'font-lock-defaults '(message-font-lock-keywords t))
  1437. (defvar message-face-alist
  1438. '((bold . message-bold-region)
  1439. (underline . underline-region)
  1440. (default . (lambda (b e)
  1441. (message-unbold-region b e)
  1442. (ununderline-region b e))))
  1443. "Alist of mail and news faces for facemenu.
  1444. The cdr of each entry is a function for applying the face to a region.")
  1445. (defcustom message-send-hook nil
  1446. "Hook run before sending messages.
  1447. This hook is run quite early when sending."
  1448. :group 'message-various
  1449. :options '(ispell-message)
  1450. :link '(custom-manual "(message)Various Message Variables")
  1451. :type 'hook)
  1452. (defcustom message-send-mail-hook nil
  1453. "Hook run before sending mail messages.
  1454. This hook is run very late -- just before the message is sent as
  1455. mail."
  1456. :group 'message-various
  1457. :link '(custom-manual "(message)Various Message Variables")
  1458. :type 'hook)
  1459. (defcustom message-send-news-hook nil
  1460. "Hook run before sending news messages.
  1461. This hook is run very late -- just before the message is sent as
  1462. news."
  1463. :group 'message-various
  1464. :link '(custom-manual "(message)Various Message Variables")
  1465. :type 'hook)
  1466. (defcustom message-sent-hook nil
  1467. "Hook run after sending messages."
  1468. :group 'message-various
  1469. :type 'hook)
  1470. (defvar message-send-coding-system 'binary
  1471. "Coding system to encode outgoing mail.")
  1472. (defvar message-draft-coding-system
  1473. mm-auto-save-coding-system
  1474. "*Coding system to compose mail.
  1475. If you'd like to make it possible to share draft files between XEmacs
  1476. and Emacs, you may use `iso-2022-7bit' for this value at your own risk.
  1477. Note that the coding-system `iso-2022-7bit' isn't suitable to all data.")
  1478. (defcustom message-send-mail-partially-limit nil
  1479. "The limitation of messages sent as message/partial.
  1480. The lower bound of message size in characters, beyond which the message
  1481. should be sent in several parts. If it is nil, the size is unlimited."
  1482. :version "24.1"
  1483. :group 'message-buffers
  1484. :link '(custom-manual "(message)Mail Variables")
  1485. :type '(choice (const :tag "unlimited" nil)
  1486. (integer 1000000)))
  1487. (defcustom message-alternative-emails nil
  1488. "*Regexp matching alternative email addresses.
  1489. The first address in the To, Cc or From headers of the original
  1490. article matching this variable is used as the From field of
  1491. outgoing messages.
  1492. This variable has precedence over posting styles and anything that runs
  1493. off `message-setup-hook'."
  1494. :group 'message-headers
  1495. :link '(custom-manual "(message)Message Headers")
  1496. :type '(choice (const :tag "Always use primary" nil)
  1497. regexp))
  1498. (defcustom message-hierarchical-addresses nil
  1499. "A list of hierarchical mail address definitions.
  1500. Inside each entry, the first address is the \"top\" address, and
  1501. subsequent addresses are subaddresses; this is used to indicate that
  1502. mail sent to the first address will automatically be delivered to the
  1503. subaddresses. So if the first address appears in the recipient list
  1504. for a message, the subaddresses will be removed (if present) before
  1505. the mail is sent. All addresses in this structure should be
  1506. downcased."
  1507. :version "22.1"
  1508. :group 'message-headers
  1509. :type '(repeat (repeat string)))
  1510. (defcustom message-mail-user-agent nil
  1511. "Like `mail-user-agent'.
  1512. Except if it is nil, use Gnus native MUA; if it is t, use
  1513. `mail-user-agent'."
  1514. :version "22.1"
  1515. :type '(radio (const :tag "Gnus native"
  1516. :format "%t\n"
  1517. nil)
  1518. (const :tag "`mail-user-agent'"
  1519. :format "%t\n"
  1520. t)
  1521. (function-item :tag "Default Emacs mail"
  1522. :format "%t\n"
  1523. sendmail-user-agent)
  1524. (function-item :tag "Emacs interface to MH"
  1525. :format "%t\n"
  1526. mh-e-user-agent)
  1527. (function :tag "Other"))
  1528. :version "21.1"
  1529. :group 'message)
  1530. (defcustom message-wide-reply-confirm-recipients nil
  1531. "Whether to confirm a wide reply to multiple email recipients.
  1532. If this variable is nil, don't ask whether to reply to all recipients.
  1533. If this variable is non-nil, pose the question \"Reply to all
  1534. recipients?\" before a wide reply to multiple recipients. If the user
  1535. answers yes, reply to all recipients as usual. If the user answers
  1536. no, only reply back to the author."
  1537. :version "22.1"
  1538. :group 'message-headers
  1539. :link '(custom-manual "(message)Wide Reply")
  1540. :type 'boolean)
  1541. (defcustom message-user-fqdn nil
  1542. "*Domain part of Message-Ids."
  1543. :version "22.1"
  1544. :group 'message-headers
  1545. :link '(custom-manual "(message)News Headers")
  1546. :type '(radio (const :format "%v " nil)
  1547. (string :format "FQDN: %v")))
  1548. (defcustom message-use-idna
  1549. (and (or (mm-coding-system-p 'utf-8)
  1550. (condition-case nil
  1551. (let (mucs-ignore-version-incompatibilities)
  1552. (require 'un-define))
  1553. (error)))
  1554. (condition-case nil
  1555. (require 'idna)
  1556. (file-error)
  1557. (invalid-operation))
  1558. idna-program
  1559. (executable-find idna-program)
  1560. (string= (idna-to-ascii "räksmörgås") "xn--rksmrgs-5wao1o")
  1561. t)
  1562. "Whether to encode non-ASCII in domain names into ASCII according to IDNA.
  1563. GNU Libidn, and in particular the elisp package \"idna.el\" and
  1564. the external program \"idn\", must be installed for this
  1565. functionality to work."
  1566. :version "22.1"
  1567. :group 'message-headers
  1568. :link '(custom-manual "(message)IDNA")
  1569. :type '(choice (const :tag "Ask" ask)
  1570. (const :tag "Never" nil)
  1571. (const :tag "Always" t)))
  1572. (defcustom message-generate-hashcash (if (executable-find "hashcash") 'opportunistic)
  1573. "*Whether to generate X-Hashcash: headers.
  1574. If t, always generate hashcash headers. If `opportunistic',
  1575. only generate hashcash headers if it can be done without the user
  1576. waiting (i.e., only asynchronously).
  1577. You must have the \"hashcash\" binary installed, see `hashcash-path'."
  1578. :version "24.1"
  1579. :group 'message-headers
  1580. :link '(custom-manual "(message)Mail Headers")
  1581. :type '(choice (const :tag "Always" t)
  1582. (const :tag "Never" nil)
  1583. (const :tag "Opportunistic" opportunistic)))
  1584. ;;; Internal variables.
  1585. (defvar message-sending-message "Sending...")
  1586. (defvar message-buffer-list nil)
  1587. (defvar message-this-is-news nil)
  1588. (defvar message-this-is-mail nil)
  1589. (defvar message-draft-article nil)
  1590. (defvar message-mime-part nil)
  1591. (defvar message-posting-charset nil)
  1592. (defvar message-inserted-headers nil)
  1593. (defvar message-inhibit-ecomplete nil)
  1594. ;; Byte-compiler warning
  1595. (defvar gnus-active-hashtb)
  1596. (defvar gnus-read-active-file)
  1597. ;;; Regexp matching the delimiter of messages in UNIX mail format
  1598. ;;; (UNIX From lines), minus the initial ^. It should be a copy
  1599. ;;; of rmail.el's rmail-unix-mail-delimiter.
  1600. (defvar message-unix-mail-delimiter
  1601. (let ((time-zone-regexp
  1602. (concat "\\([A-Z]?[A-Z]?[A-Z][A-Z]\\( DST\\)?"
  1603. "\\|[-+]?[0-9][0-9][0-9][0-9]"
  1604. "\\|"
  1605. "\\) *")))
  1606. (concat
  1607. "From "
  1608. ;; Many things can happen to an RFC 822 mailbox before it is put into
  1609. ;; a `From' line. The leading phrase can be stripped, e.g.
  1610. ;; `Joe <@w.x:joe@y.z>' -> `<@w.x:joe@y.z>'. The <> can be stripped, e.g.
  1611. ;; `<@x.y:joe@y.z>' -> `@x.y:joe@y.z'. Everything starting with a CRLF
  1612. ;; can be removed, e.g.
  1613. ;; From: joe@y.z (Joe K
  1614. ;; User)
  1615. ;; can yield `From joe@y.z (Joe K Fri Mar 22 08:11:15 1996', and
  1616. ;; From: Joe User
  1617. ;; <joe@y.z>
  1618. ;; can yield `From Joe User Fri Mar 22 08:11:15 1996'.
  1619. ;; The mailbox can be removed or be replaced by white space, e.g.
  1620. ;; From: "Joe User"{space}{tab}
  1621. ;; <joe@y.z>
  1622. ;; can yield `From {space}{tab} Fri Mar 22 08:11:15 1996',
  1623. ;; where {space} and {tab} represent the Ascii space and tab characters.
  1624. ;; We want to match the results of any of these manglings.
  1625. ;; The following regexp rejects names whose first characters are
  1626. ;; obviously bogus, but after that anything goes.
  1627. "\\([^\0-\b\n-\r\^?].*\\)?"
  1628. ;; The time the message was sent.
  1629. "\\([^\0-\r \^?]+\\) +" ; day of the week
  1630. "\\([^\0-\r \^?]+\\) +" ; month
  1631. "\\([0-3]?[0-9]\\) +" ; day of month
  1632. "\\([0-2][0-9]:[0-5][0-9]\\(:[0-6][0-9]\\)?\\) *" ; time of day
  1633. ;; Perhaps a time zone, specified by an abbreviation, or by a
  1634. ;; numeric offset.
  1635. time-zone-regexp
  1636. ;; The year.
  1637. " \\([0-9][0-9]+\\) *"
  1638. ;; On some systems the time zone can appear after the year, too.
  1639. time-zone-regexp
  1640. ;; Old uucp cruft.
  1641. "\\(remote from .*\\)?"
  1642. "\n"))
  1643. "Regexp matching the delimiter of messages in UNIX mail format.")
  1644. (defvar message-unsent-separator
  1645. (concat "^ *---+ +Unsent message follows +---+ *$\\|"
  1646. "^ *---+ +Returned message +---+ *$\\|"
  1647. "^Start of returned message$\\|"
  1648. "^ *---+ +Original message +---+ *$\\|"
  1649. "^ *--+ +begin message +--+ *$\\|"
  1650. "^ *---+ +Original message follows +---+ *$\\|"
  1651. "^ *---+ +Undelivered message follows +---+ *$\\|"
  1652. "^------ This is a copy of the message, including all the headers. ------ *$\\|"
  1653. "^|? *---+ +Message text follows: +---+ *|?$")
  1654. "A regexp that matches the separator before the text of a failed message.")
  1655. (defvar message-field-fillers
  1656. '((To message-fill-field-address)
  1657. (Cc message-fill-field-address)
  1658. (From message-fill-field-address))
  1659. "Alist of header names/filler functions.")
  1660. (defvar message-header-format-alist
  1661. `((From)
  1662. (Newsgroups)
  1663. (To)
  1664. (Cc)
  1665. (Subject)
  1666. (In-Reply-To)
  1667. (Fcc)
  1668. (Bcc)
  1669. (Date)
  1670. (Organization)
  1671. (Distribution)
  1672. (Lines)
  1673. (Expires)
  1674. (Message-ID)
  1675. (References . message-shorten-references)
  1676. (User-Agent))
  1677. "Alist used for formatting headers.")
  1678. (defvar message-options nil
  1679. "Some saved answers when sending message.")
  1680. ;; FIXME: On XEmacs this causes problems since let-binding like:
  1681. ;; (let ((message-options message-options)) ...)
  1682. ;; as in `message-send' and `mml-preview' loses to buffer-local
  1683. ;; variable initialization.
  1684. (unless (featurep 'xemacs)
  1685. (make-variable-buffer-local 'message-options))
  1686. (defvar message-send-mail-real-function nil
  1687. "Internal send mail function.")
  1688. (defvar message-bogus-system-names "\\`localhost\\.\\|\\.local\\'"
  1689. "The regexp of bogus system names.")
  1690. (defcustom message-valid-fqdn-regexp
  1691. (concat "[a-z0-9][-.a-z0-9]+\\." ;; [hostname.subdomain.]domain.
  1692. ;; valid TLDs:
  1693. "\\([a-z][a-z]\\|" ;; two letter country TDLs
  1694. "aero\\|arpa\\|asia\\|bitnet\\|biz\\|bofh\\|"
  1695. "cat\\|com\\|coop\\|edu\\|gov\\|"
  1696. "info\\|int\\|jobs\\|"
  1697. "mil\\|mobi\\|museum\\|name\\|net\\|"
  1698. "org\\|pro\\|tel\\|travel\\|uucp\\|"
  1699. ;; ICANN-era generic top-level domains
  1700. "academy\\|actor\\|agency\\|airforce\\|archi\\|associates\\|axa\\|"
  1701. "bar\\|bargains\\|bayern\\|beer\\|berlin\\|best\\|bid\\|bike\\|"
  1702. "biz\\|black\\|blackfriday\\|blue\\|boutique\\|build\\|builders\\|"
  1703. "buzz\\|cab\\|camera\\|camp\\|capital\\|cards\\|care\\|career\\|"
  1704. "careers\\|cash\\|catering\\|center\\|ceo\\|cheap\\|christmas\\|"
  1705. "church\\|citic\\|cleaning\\|clinic\\|clothing\\|club\\|codes\\|"
  1706. "coffee\\|college\\|cologne\\|com\\|community\\|company\\|computer\\|"
  1707. "construction\\|contractors\\|cooking\\|cool\\|country\\|creditcard\\|"
  1708. "cruises\\|dance\\|dating\\|democrat\\|dental\\|desi\\|design\\|"
  1709. "diamonds\\|directory\\|discount\\|domains\\|education\\|email\\|"
  1710. "engineering\\|enterprises\\|equipment\\|estate\\|eus\\|events\\|"
  1711. "exchange\\|expert\\|exposed\\|fail\\|farm\\|feedback\\|finance\\|"
  1712. "financial\\|fish\\|fishing\\|fitness\\|flights\\|florist\\|foo\\|"
  1713. "foundation\\|frogans\\|fund\\|furniture\\|futbol\\|gal\\|"
  1714. "gallery\\|gift\\|glass\\|globo\\|gmo\\|gop\\|graphics\\|gratis\\|"
  1715. "gripe\\|guide\\|guitars\\|guru\\|hamburg\\|haus\\|hiphop\\|"
  1716. "holdings\\|holiday\\|homes\\|horse\\|house\\|immobilien\\|"
  1717. "industries\\|info\\|ink\\|institute\\|insure\\|international\\|"
  1718. "investments\\|jetzt\\|juegos\\|kaufen\\|kim\\|kitchen\\|kiwi\\|"
  1719. "koeln\\|kred\\|land\\|lat\\|latino\\|lease\\|life\\|lighting\\|"
  1720. "limited\\|limo\\|link\\|loans\\|london\\|luxe\\|luxury\\|"
  1721. "management\\|mango\\|marketing\\|media\\|meet\\|menu\\|miami\\|"
  1722. "moda\\|moe\\|monash\\|moscow\\|motorcycles\\|nagoya\\|name\\|"
  1723. "net\\|neustar\\|ninja\\|nyc\\|okinawa\\|onl\\|org\\|paris\\|"
  1724. "partners\\|parts\\|photo\\|photography\\|photos\\|pics\\|"
  1725. "pictures\\|pink\\|plumbing\\|pro\\|productions\\|properties\\|"
  1726. "pub\\|qpon\\|quebec\\|recipes\\|red\\|reisen\\|ren\\|rentals\\|"
  1727. "repair\\|report\\|rest\\|reviews\\|rich\\|rocks\\|rodeo\\|"
  1728. "ruhr\\|ryukyu\\|saarland\\|schule\\|scot\\|services\\|sexy\\|"
  1729. "shiksha\\|shoes\\|singles\\|social\\|sohu\\|solar\\|solutions\\|"
  1730. "soy\\|supplies\\|supply\\|support\\|surgery\\|systems\\|tattoo\\|"
  1731. "tax\\|technology\\|tienda\\|tips\\|today\\|tokyo\\|tools\\|"
  1732. "town\\|toys\\|trade\\|training\\|university\\|uno\\|vacations\\|"
  1733. "vegas\\|ventures\\|viajes\\|villas\\|vision\\|vodka\\|vote\\|"
  1734. "voting\\|voto\\|voyage\\|wang\\|watch\\|webcam\\|wed\\|wien\\|"
  1735. "wiki\\|works\\|wtc\\|wtf\\|xyz\\|yachts\\|yokohama\\|you\\|"
  1736. "zone\\)")
  1737. ;; http://en.wikipedia.org/wiki/List_of_Internet_top-level_domains
  1738. ;; http://en.wikipedia.org/wiki/GTLD
  1739. ;; `approved, but not yet in operation': .xxx
  1740. ;; "dead" nato bitnet uucp
  1741. "Regular expression that matches a valid FQDN."
  1742. ;; see also: gnus-button-valid-fqdn-regexp
  1743. :version "25.1"
  1744. :group 'message-headers
  1745. :type 'regexp)
  1746. (autoload 'gnus-alive-p "gnus-util")
  1747. (autoload 'gnus-delay-article "gnus-delay")
  1748. (autoload 'gnus-extract-address-components "gnus-util")
  1749. (autoload 'gnus-find-method-for-group "gnus")
  1750. (autoload 'gnus-group-decoded-name "gnus-group")
  1751. (autoload 'gnus-group-name-charset "gnus-group")
  1752. (autoload 'gnus-group-name-decode "gnus-group")
  1753. (autoload 'gnus-groups-from-server "gnus")
  1754. (autoload 'gnus-make-local-hook "gnus-util")
  1755. (autoload 'gnus-open-server "gnus-int")
  1756. (autoload 'gnus-output-to-mail "gnus-util")
  1757. (autoload 'gnus-output-to-rmail "gnus-util")
  1758. (autoload 'gnus-request-post "gnus-int")
  1759. (autoload 'gnus-select-frame-set-input-focus "gnus-util")
  1760. (autoload 'gnus-server-string "gnus")
  1761. (autoload 'idna-to-ascii "idna")
  1762. (autoload 'message-setup-toolbar "messagexmas")
  1763. (autoload 'mh-new-draft-name "mh-comp")
  1764. (autoload 'mh-send-letter "mh-comp")
  1765. (autoload 'nndraft-request-associate-buffer "nndraft")
  1766. (autoload 'nndraft-request-expire-articles "nndraft")
  1767. (autoload 'nnvirtual-find-group-art "nnvirtual")
  1768. (autoload 'rmail-msg-is-pruned "rmail")
  1769. (autoload 'rmail-output "rmailout")
  1770. ;; Emacs < 24.1 do not have mail-dont-reply-to
  1771. (unless (fboundp 'mail-dont-reply-to)
  1772. (defalias 'mail-dont-reply-to 'rmail-dont-reply-to))
  1773. (eval-and-compile
  1774. (if (featurep 'emacs)
  1775. (progn
  1776. (defun message-kill-all-overlays ()
  1777. (mapcar #'delete-overlay (overlays-in (point-min) (point-max))))
  1778. (defalias 'message-window-inside-pixel-edges
  1779. 'window-inside-pixel-edges))
  1780. (defun message-kill-all-overlays ()
  1781. (map-extents (lambda (extent ignore) (delete-extent extent))))
  1782. (defalias 'message-window-inside-pixel-edges 'ignore)))
  1783. ;;;
  1784. ;;; Utility functions.
  1785. ;;;
  1786. (defmacro message-y-or-n-p (question show &rest text)
  1787. "Ask QUESTION, displaying remaining args in a temporary buffer if SHOW."
  1788. `(message-talkative-question 'y-or-n-p ,question ,show ,@text))
  1789. (defmacro message-delete-line (&optional n)
  1790. "Delete the current line (and the next N lines)."
  1791. `(delete-region (progn (beginning-of-line) (point))
  1792. (progn (forward-line ,(or n 1)) (point))))
  1793. (defun message-mark-active-p ()
  1794. "Non-nil means the mark and region are currently active in this buffer."
  1795. mark-active)
  1796. (defun message-unquote-tokens (elems)
  1797. "Remove double quotes (\") from strings in list ELEMS."
  1798. (mapcar (lambda (item)
  1799. (while (string-match "^\\(.*\\)\"\\(.*\\)$" item)
  1800. (setq item (concat (match-string 1 item)
  1801. (match-string 2 item))))
  1802. item)
  1803. elems))
  1804. (defun message-tokenize-header (header &optional separator)
  1805. "Split HEADER into a list of header elements.
  1806. SEPARATOR is a string of characters to be used as separators. \",\"
  1807. is used by default."
  1808. (if (not header)
  1809. nil
  1810. (let ((regexp (format "[%s]+" (or separator ",")))
  1811. (first t)
  1812. beg quoted elems paren)
  1813. (with-temp-buffer
  1814. (mm-enable-multibyte)
  1815. (setq beg (point-min))
  1816. (insert header)
  1817. (goto-char (point-min))
  1818. (while (not (eobp))
  1819. (if first
  1820. (setq first nil)
  1821. (forward-char 1))
  1822. (cond ((and (> (point) beg)
  1823. (or (eobp)
  1824. (and (looking-at regexp)
  1825. (not quoted)
  1826. (not paren))))
  1827. (push (buffer-substring beg (point)) elems)
  1828. (setq beg (match-end 0)))
  1829. ((eq (char-after) ?\")
  1830. (setq quoted (not quoted)))
  1831. ((and (eq (char-after) ?\()
  1832. (not quoted))
  1833. (setq paren t))
  1834. ((and (eq (char-after) ?\))
  1835. (not quoted))
  1836. (setq paren nil))))
  1837. (nreverse elems)))))
  1838. (autoload 'nnheader-insert-file-contents "nnheader")
  1839. (defun message-mail-file-mbox-p (file)
  1840. "Say whether FILE looks like a Unix mbox file."
  1841. (when (and (file-exists-p file)
  1842. (file-readable-p file)
  1843. (file-regular-p file))
  1844. (with-temp-buffer
  1845. (nnheader-insert-file-contents file)
  1846. (goto-char (point-min))
  1847. (looking-at message-unix-mail-delimiter))))
  1848. (defun message-fetch-field (header &optional not-all)
  1849. "The same as `mail-fetch-field', only remove all newlines.
  1850. The buffer is expected to be narrowed to just the header of the message;
  1851. see `message-narrow-to-headers-or-head'."
  1852. (let* ((inhibit-point-motion-hooks t)
  1853. (value (mail-fetch-field header nil (not not-all))))
  1854. (when value
  1855. (while (string-match "\n[\t ]+" value)
  1856. (setq value (replace-match " " t t value)))
  1857. value)))
  1858. (defun message-field-value (header &optional not-all)
  1859. "The same as `message-fetch-field', only narrow to the headers first."
  1860. (save-excursion
  1861. (save-restriction
  1862. (message-narrow-to-headers-or-head)
  1863. (message-fetch-field header not-all))))
  1864. (defun message-narrow-to-field ()
  1865. "Narrow the buffer to the header on the current line."
  1866. (beginning-of-line)
  1867. (while (looking-at "[ \t]")
  1868. (forward-line -1))
  1869. (narrow-to-region
  1870. (point)
  1871. (progn
  1872. (forward-line 1)
  1873. (if (re-search-forward "^[^ \n\t]" nil t)
  1874. (point-at-bol)
  1875. (point-max))))
  1876. (goto-char (point-min)))
  1877. (defun message-add-header (&rest headers)
  1878. "Add the HEADERS to the message header, skipping those already present."
  1879. (while headers
  1880. (let (hclean)
  1881. (unless (string-match "^\\([^:]+\\):[ \t]*[^ \t]" (car headers))
  1882. (error "Invalid header `%s'" (car headers)))
  1883. (setq hclean (match-string 1 (car headers)))
  1884. (save-restriction
  1885. (message-narrow-to-headers)
  1886. (unless (re-search-forward (concat "^" (regexp-quote hclean) ":") nil t)
  1887. (goto-char (point-max))
  1888. (if (string-match "\n$" (car headers))
  1889. (insert (car headers))
  1890. (insert (car headers) ?\n)))))
  1891. (setq headers (cdr headers))))
  1892. (defmacro message-with-reply-buffer (&rest forms)
  1893. "Evaluate FORMS in the reply buffer, if it exists."
  1894. `(when (and (bufferp message-reply-buffer)
  1895. (buffer-name message-reply-buffer))
  1896. (with-current-buffer message-reply-buffer
  1897. ,@forms)))
  1898. (put 'message-with-reply-buffer 'lisp-indent-function 0)
  1899. (put 'message-with-reply-buffer 'edebug-form-spec '(body))
  1900. (defun message-fetch-reply-field (header)
  1901. "Fetch field HEADER from the message we're replying to."
  1902. (message-with-reply-buffer
  1903. (save-restriction
  1904. (mail-narrow-to-head)
  1905. (message-fetch-field header))))
  1906. (defun message-strip-list-identifiers (subject)
  1907. "Remove list identifiers in `gnus-list-identifiers' from string SUBJECT."
  1908. (require 'gnus-sum) ; for gnus-list-identifiers
  1909. (let ((regexp (if (stringp gnus-list-identifiers)
  1910. gnus-list-identifiers
  1911. (mapconcat 'identity gnus-list-identifiers " *\\|"))))
  1912. (if (string-match (concat "\\(\\(\\(Re: +\\)?\\(" regexp
  1913. " *\\)\\)+\\(Re: +\\)?\\)") subject)
  1914. (concat (substring subject 0 (match-beginning 1))
  1915. (or (match-string 3 subject)
  1916. (match-string 5 subject))
  1917. (substring subject
  1918. (match-end 1)))
  1919. subject)))
  1920. (defun message-strip-subject-re (subject)
  1921. "Remove \"Re:\" from subject lines in string SUBJECT."
  1922. (if (string-match message-subject-re-regexp subject)
  1923. (substring subject (match-end 0))
  1924. subject))
  1925. (defcustom message-replacement-char "."
  1926. "Replacement character used instead of unprintable or not decodable chars."
  1927. :group 'message-various
  1928. :version "22.1" ;; Gnus 5.10.9
  1929. :type '(choice string
  1930. (const ".")
  1931. (const "?")))
  1932. ;; FIXME: We also should call `message-strip-subject-encoded-words'
  1933. ;; when forwarding. Probably in `message-make-forward-subject' and
  1934. ;; `message-forward-make-body'.
  1935. (defun message-strip-subject-encoded-words (subject)
  1936. "Fix non-decodable words in SUBJECT."
  1937. ;; Cf. `gnus-simplify-subject-fully'.
  1938. (let* ((case-fold-search t)
  1939. (replacement-chars (format "[%s%s%s]"
  1940. message-replacement-char
  1941. message-replacement-char
  1942. message-replacement-char))
  1943. (enc-word-re "=\\?\\([^?]+\\)\\?\\([QB]\\)\\?\\([^?]+\\)\\(\\?=\\)")
  1944. cs-string
  1945. (have-marker
  1946. (with-temp-buffer
  1947. (insert subject)
  1948. (goto-char (point-min))
  1949. (when (re-search-forward enc-word-re nil t)
  1950. (setq cs-string (match-string 1)))))
  1951. cs-coding q-or-b word-beg word-end)
  1952. (if (or (not have-marker) ;; No encoded word found...
  1953. ;; ... or double encoding was correct:
  1954. (and (stringp cs-string)
  1955. (setq cs-string (downcase cs-string))
  1956. (mm-coding-system-p (intern cs-string))
  1957. (not (prog1
  1958. (y-or-n-p
  1959. (format "\
  1960. Decoded Subject \"%s\"
  1961. contains a valid encoded word. Decode again? "
  1962. subject))
  1963. (setq cs-coding (intern cs-string))))))
  1964. subject
  1965. (with-temp-buffer
  1966. (insert subject)
  1967. (goto-char (point-min))
  1968. (while (re-search-forward enc-word-re nil t)
  1969. (setq cs-string (downcase (match-string 1))
  1970. q-or-b (match-string 2)
  1971. word-beg (match-beginning 0)
  1972. word-end (match-end 0))
  1973. (setq cs-coding
  1974. (if (mm-coding-system-p (intern cs-string))
  1975. (setq cs-coding (intern cs-string))
  1976. nil))
  1977. ;; No double encoded subject? => bogus charset.
  1978. (unless cs-coding
  1979. (setq cs-coding
  1980. (mm-read-coding-system
  1981. (format "\
  1982. Decoded Subject \"%s\"
  1983. contains an encoded word. The charset `%s' is unknown or invalid.
  1984. Hit RET to replace non-decodable characters with \"%s\" or enter replacement
  1985. charset: "
  1986. subject cs-string message-replacement-char)))
  1987. (if cs-coding
  1988. (replace-match (concat "=?" (symbol-name cs-coding)
  1989. "?\\2?\\3\\4\\5"))
  1990. (save-excursion
  1991. (goto-char word-beg)
  1992. (re-search-forward "=\\?\\([^?]+\\)\\?\\([QB]\\)\\?" word-end t)
  1993. (replace-match "")
  1994. ;; QP or base64
  1995. (if (string-match "\\`Q\\'" q-or-b)
  1996. ;; QP
  1997. (progn
  1998. (message "Replacing non-decodable characters with \"%s\"."
  1999. message-replacement-char)
  2000. (while (re-search-forward "\\(=[A-F0-9][A-F0-9]\\)+"
  2001. word-end t)
  2002. (replace-match message-replacement-char)))
  2003. ;; base64
  2004. (message "Replacing non-decodable characters with \"%s\"."
  2005. replacement-chars)
  2006. (re-search-forward "[^?]+" word-end t)
  2007. (replace-match replacement-chars))
  2008. (re-search-forward "\\?=")
  2009. (replace-match "")))))
  2010. (rfc2047-decode-region (point-min) (point-max))
  2011. (buffer-string)))))
  2012. ;;; Start of functions adopted from `message-utils.el'.
  2013. (defun message-strip-subject-trailing-was (subject)
  2014. "Remove trailing \"(was: <old subject>)\" from SUBJECT lines.
  2015. Leading \"Re: \" is not stripped by this function. Use the function
  2016. `message-strip-subject-re' for this."
  2017. (let* ((query message-subject-trailing-was-query)
  2018. (new) (found))
  2019. (setq found
  2020. (string-match
  2021. (if (eq query 'ask)
  2022. message-subject-trailing-was-ask-regexp
  2023. message-subject-trailing-was-regexp)
  2024. subject))
  2025. (if found
  2026. (setq new (substring subject 0 (match-beginning 0))))
  2027. (if (or (not found) (eq query nil))
  2028. subject
  2029. (if (eq query 'ask)
  2030. (if (message-y-or-n-p
  2031. "Strip `(was: <old subject>)' in subject? " t
  2032. (concat
  2033. "Strip `(was: <old subject>)' in subject "
  2034. "and use the new one instead?\n\n"
  2035. "Current subject is: \""
  2036. subject "\"\n\n"
  2037. "New subject would be: \""
  2038. new "\"\n\n"
  2039. "See the variable `message-subject-trailing-was-query' "
  2040. "to get rid of this query."
  2041. ))
  2042. new subject)
  2043. new))))
  2044. ;;; Suggested by Jonas Steverud @ www.dtek.chalmers.se/~d4jonas/
  2045. (defun message-change-subject (new-subject)
  2046. "Ask for NEW-SUBJECT header, append (was: <Old Subject>)."
  2047. (interactive
  2048. (list
  2049. (read-from-minibuffer "New subject: ")))
  2050. (cond ((and (not (or (null new-subject) ; new subject not empty
  2051. (zerop (string-width new-subject))
  2052. (string-match "^[ \t]*$" new-subject))))
  2053. (save-excursion
  2054. (let ((old-subject
  2055. (save-restriction
  2056. (message-narrow-to-headers)
  2057. (message-fetch-field "Subject"))))
  2058. (cond ((not old-subject)
  2059. (error "No current subject"))
  2060. ((not (string-match
  2061. (concat "^[ \t]*"
  2062. (regexp-quote new-subject)
  2063. "[ \t]*$")
  2064. old-subject)) ; yes, it really is a new subject
  2065. ;; delete eventual Re: prefix
  2066. (setq old-subject
  2067. (message-strip-subject-re old-subject))
  2068. (message-goto-subject)
  2069. (message-delete-line)
  2070. (insert (concat "Subject: "
  2071. new-subject
  2072. " (was: "
  2073. old-subject ")\n")))))))))
  2074. (defun message-mark-inserted-region (beg end &optional verbatim)
  2075. "Mark some region in the current article with enclosing tags.
  2076. See `message-mark-insert-begin' and `message-mark-insert-end'.
  2077. If VERBATIM, use slrn style verbatim marks (\"#v+\" and \"#v-\")."
  2078. (interactive "r\nP")
  2079. (save-excursion
  2080. ;; add to the end of the region first, otherwise end would be invalid
  2081. (goto-char end)
  2082. (insert (if verbatim "#v-\n" message-mark-insert-end))
  2083. (goto-char beg)
  2084. (insert (if verbatim "#v+\n" message-mark-insert-begin))))
  2085. (defun message-mark-insert-file (file &optional verbatim)
  2086. "Insert FILE at point, marking it with enclosing tags.
  2087. See `message-mark-insert-begin' and `message-mark-insert-end'.
  2088. If VERBATIM, use slrn style verbatim marks (\"#v+\" and \"#v-\")."
  2089. (interactive "fFile to insert: \nP")
  2090. ;; reverse insertion to get correct result.
  2091. (let ((p (point)))
  2092. (insert (if verbatim "#v-\n" message-mark-insert-end))
  2093. (goto-char p)
  2094. (insert-file-contents file)
  2095. (goto-char p)
  2096. (insert (if verbatim "#v+\n" message-mark-insert-begin))))
  2097. (defun message-add-archive-header ()
  2098. "Insert \"X-No-Archive: Yes\" in the header and a note in the body.
  2099. The note can be customized using `message-archive-note'. When called with a
  2100. prefix argument, ask for a text to insert. If you don't want the note in the
  2101. body, set `message-archive-note' to nil."
  2102. (interactive)
  2103. (if current-prefix-arg
  2104. (setq message-archive-note
  2105. (read-from-minibuffer "Reason for No-Archive: "
  2106. (cons message-archive-note 0))))
  2107. (save-excursion
  2108. (if (message-goto-signature)
  2109. (re-search-backward message-signature-separator))
  2110. (when message-archive-note
  2111. (insert message-archive-note)
  2112. (newline))
  2113. (message-add-header message-archive-header)
  2114. (message-sort-headers)))
  2115. (defun message-cross-post-followup-to-header (target-group)
  2116. "Mangles FollowUp-To and Newsgroups header to point to TARGET-GROUP.
  2117. With prefix-argument just set Follow-Up, don't cross-post."
  2118. (interactive
  2119. (list ; Completion based on Gnus
  2120. (completing-read "Followup To: "
  2121. (if (boundp 'gnus-newsrc-alist)
  2122. gnus-newsrc-alist)
  2123. nil nil '("poster" . 0)
  2124. (if (boundp 'gnus-group-history)
  2125. 'gnus-group-history))))
  2126. (message-remove-header "Follow[Uu]p-[Tt]o" t)
  2127. (message-goto-newsgroups)
  2128. (beginning-of-line)
  2129. ;; if we already did a crosspost before, kill old target
  2130. (if (and message-cross-post-old-target
  2131. (re-search-forward
  2132. (regexp-quote (concat "," message-cross-post-old-target))
  2133. nil t))
  2134. (replace-match ""))
  2135. ;; unless (followup is to poster or user explicitly asked not
  2136. ;; to cross-post, or target-group is already in Newsgroups)
  2137. ;; add target-group to Newsgroups line.
  2138. (cond ((and (or
  2139. ;; def: cross-post, req:no
  2140. (and message-cross-post-default (not current-prefix-arg))
  2141. ;; def: no-cross-post, req:yes
  2142. (and (not message-cross-post-default) current-prefix-arg))
  2143. (not (string-match "poster" target-group))
  2144. (not (string-match (regexp-quote target-group)
  2145. (message-fetch-field "Newsgroups"))))
  2146. (end-of-line)
  2147. (insert (concat "," target-group))))
  2148. (end-of-line) ; ensure Followup: comes after Newsgroups:
  2149. ;; unless new followup would be identical to Newsgroups line
  2150. ;; make a new Followup-To line
  2151. (if (not (string-match (concat "^[ \t]*"
  2152. target-group
  2153. "[ \t]*$")
  2154. (message-fetch-field "Newsgroups")))
  2155. (insert (concat "\nFollowup-To: " target-group)))
  2156. (setq message-cross-post-old-target target-group))
  2157. (defun message-cross-post-insert-note (target-group cross-post in-old
  2158. old-groups)
  2159. "Insert a in message body note about a set Followup or Crosspost.
  2160. If there have been previous notes, delete them. TARGET-GROUP specifies the
  2161. group to Followup-To. When CROSS-POST is t, insert note about
  2162. crossposting. IN-OLD specifies whether TARGET-GROUP is a member of
  2163. OLD-GROUPS. OLD-GROUPS lists the old-groups the posting would have
  2164. been made to before the user asked for a Crosspost."
  2165. ;; start scanning body for previous uses
  2166. (message-goto-signature)
  2167. (let ((head (re-search-backward
  2168. (concat "^" mail-header-separator)
  2169. nil t))) ; just search in body
  2170. (message-goto-signature)
  2171. (while (re-search-backward
  2172. (concat "^" (regexp-quote message-cross-post-note) ".*")
  2173. head t)
  2174. (message-delete-line))
  2175. (message-goto-signature)
  2176. (while (re-search-backward
  2177. (concat "^" (regexp-quote message-followup-to-note) ".*")
  2178. head t)
  2179. (message-delete-line))
  2180. ;; insert new note
  2181. (if (message-goto-signature)
  2182. (re-search-backward message-signature-separator))
  2183. (if (or in-old
  2184. (not cross-post)
  2185. (string-match "^[ \t]*poster[ \t]*$" target-group))
  2186. (insert (concat message-followup-to-note target-group "\n"))
  2187. (insert (concat message-cross-post-note target-group "\n")))))
  2188. (defun message-cross-post-followup-to (target-group)
  2189. "Crossposts message and set Followup-To to TARGET-GROUP.
  2190. With prefix-argument just set Follow-Up, don't cross-post."
  2191. (interactive
  2192. (list ; Completion based on Gnus
  2193. (completing-read "Followup To: "
  2194. (if (boundp 'gnus-newsrc-alist)
  2195. gnus-newsrc-alist)
  2196. nil nil '("poster" . 0)
  2197. (if (boundp 'gnus-group-history)
  2198. 'gnus-group-history))))
  2199. (cond ((not (or (null target-group) ; new subject not empty
  2200. (zerop (string-width target-group))
  2201. (string-match "^[ \t]*$" target-group)))
  2202. (save-excursion
  2203. (let* ((old-groups (message-fetch-field "Newsgroups"))
  2204. (in-old (string-match
  2205. (regexp-quote target-group)
  2206. (or old-groups ""))))
  2207. ;; check whether target exactly matches old Newsgroups
  2208. (cond ((not old-groups)
  2209. (error "No current newsgroup"))
  2210. ((or (not in-old)
  2211. (not (string-match
  2212. (concat "^[ \t]*"
  2213. (regexp-quote target-group)
  2214. "[ \t]*$")
  2215. old-groups)))
  2216. ;; yes, Newsgroups line must change
  2217. (message-cross-post-followup-to-header target-group)
  2218. ;; insert note whether we do cross-post or followup-to
  2219. (funcall message-cross-post-note-function
  2220. target-group
  2221. (if (or (and message-cross-post-default
  2222. (not current-prefix-arg))
  2223. (and (not message-cross-post-default)
  2224. current-prefix-arg)) t)
  2225. in-old old-groups))))))))
  2226. ;;; Reduce To: to Cc: or Bcc: header
  2227. (defun message-reduce-to-to-cc ()
  2228. "Replace contents of To: header with contents of Cc: or Bcc: header."
  2229. (interactive)
  2230. (let ((cc-content
  2231. (save-restriction (message-narrow-to-headers)
  2232. (message-fetch-field "cc")))
  2233. (bcc nil))
  2234. (if (and (not cc-content)
  2235. (setq cc-content
  2236. (save-restriction
  2237. (message-narrow-to-headers)
  2238. (message-fetch-field "bcc"))))
  2239. (setq bcc t))
  2240. (cond (cc-content
  2241. (save-excursion
  2242. (message-goto-to)
  2243. (message-delete-line)
  2244. (insert (concat "To: " cc-content "\n"))
  2245. (save-restriction
  2246. (message-narrow-to-headers)
  2247. (message-remove-header (if bcc
  2248. "bcc"
  2249. "cc"))))))))
  2250. ;;; End of functions adopted from `message-utils.el'.
  2251. (defun message-remove-header (header &optional is-regexp first reverse)
  2252. "Remove HEADER in the narrowed buffer.
  2253. If IS-REGEXP, HEADER is a regular expression.
  2254. If FIRST, only remove the first instance of the header.
  2255. If REVERSE, remove headers that doesn't match HEADER.
  2256. Return the number of headers removed."
  2257. (goto-char (point-min))
  2258. (let ((regexp (if is-regexp header (concat "^" (regexp-quote header) ":")))
  2259. (number 0)
  2260. (case-fold-search t)
  2261. last)
  2262. (while (and (not (eobp))
  2263. (not last))
  2264. (if (if reverse
  2265. (not (looking-at regexp))
  2266. (looking-at regexp))
  2267. (progn
  2268. (incf number)
  2269. (when first
  2270. (setq last t))
  2271. (delete-region
  2272. (point)
  2273. ;; There might be a continuation header, so we have to search
  2274. ;; until we find a new non-continuation line.
  2275. (progn
  2276. (forward-line 1)
  2277. (if (re-search-forward "^[^ \t]" nil t)
  2278. (goto-char (match-beginning 0))
  2279. (point-max)))))
  2280. (forward-line 1)
  2281. (if (re-search-forward "^[^ \t]" nil t)
  2282. (goto-char (match-beginning 0))
  2283. (goto-char (point-max)))))
  2284. number))
  2285. (defun message-remove-first-header (header)
  2286. "Remove the first instance of HEADER if there is more than one."
  2287. (let ((count 0)
  2288. (regexp (concat "^" (regexp-quote header) ":")))
  2289. (save-excursion
  2290. (goto-char (point-min))
  2291. (while (re-search-forward regexp nil t)
  2292. (incf count)))
  2293. (while (> count 1)
  2294. (message-remove-header header nil t)
  2295. (decf count))))
  2296. (defun message-narrow-to-headers ()
  2297. "Narrow the buffer to the head of the message."
  2298. (widen)
  2299. (narrow-to-region
  2300. (goto-char (point-min))
  2301. (if (re-search-forward
  2302. (concat "^" (regexp-quote mail-header-separator) "\n") nil t)
  2303. (match-beginning 0)
  2304. (point-max)))
  2305. (goto-char (point-min)))
  2306. (defun message-narrow-to-head-1 ()
  2307. "Like `message-narrow-to-head'. Don't widen."
  2308. (narrow-to-region
  2309. (goto-char (point-min))
  2310. (if (search-forward "\n\n" nil 1)
  2311. (1- (point))
  2312. (point-max)))
  2313. (goto-char (point-min)))
  2314. ;; FIXME: clarify difference: message-narrow-to-head,
  2315. ;; message-narrow-to-headers-or-head, message-narrow-to-headers
  2316. (defun message-narrow-to-head ()
  2317. "Narrow the buffer to the head of the message.
  2318. Point is left at the beginning of the narrowed-to region."
  2319. (widen)
  2320. (message-narrow-to-head-1))
  2321. (defun message-narrow-to-headers-or-head ()
  2322. "Narrow the buffer to the head of the message."
  2323. (widen)
  2324. (narrow-to-region
  2325. (goto-char (point-min))
  2326. (if (re-search-forward (concat "\\(\n\\)\n\\|^\\("
  2327. (regexp-quote mail-header-separator)
  2328. "\n\\)")
  2329. nil t)
  2330. (or (match-end 1) (match-beginning 2))
  2331. (point-max)))
  2332. (goto-char (point-min)))
  2333. (defun message-news-p ()
  2334. "Say whether the current buffer contains a news message."
  2335. (and (not message-this-is-mail)
  2336. (or message-this-is-news
  2337. (save-excursion
  2338. (save-restriction
  2339. (message-narrow-to-headers)
  2340. (and (message-fetch-field "newsgroups")
  2341. (not (message-fetch-field "posted-to"))))))))
  2342. (defun message-mail-p ()
  2343. "Say whether the current buffer contains a mail message."
  2344. (and (not message-this-is-news)
  2345. (or message-this-is-mail
  2346. (save-excursion
  2347. (save-restriction
  2348. (message-narrow-to-headers)
  2349. (or (message-fetch-field "to")
  2350. (message-fetch-field "cc")
  2351. (message-fetch-field "bcc")))))))
  2352. (defun message-subscribed-p ()
  2353. "Say whether we need to insert a MFT header."
  2354. (or message-subscribed-regexps
  2355. message-subscribed-addresses
  2356. message-subscribed-address-file
  2357. message-subscribed-address-functions))
  2358. (defun message-next-header ()
  2359. "Go to the beginning of the next header."
  2360. (beginning-of-line)
  2361. (or (eobp) (forward-char 1))
  2362. (not (if (re-search-forward "^[^ \t]" nil t)
  2363. (beginning-of-line)
  2364. (goto-char (point-max)))))
  2365. (defun message-sort-headers-1 ()
  2366. "Sort the buffer as headers using `message-rank' text props."
  2367. (goto-char (point-min))
  2368. (require 'sort)
  2369. (sort-subr
  2370. nil 'message-next-header
  2371. (lambda ()
  2372. (message-next-header)
  2373. (unless (bobp)
  2374. (forward-char -1)))
  2375. (lambda ()
  2376. (or (get-text-property (point) 'message-rank)
  2377. 10000))))
  2378. (defun message-sort-headers ()
  2379. "Sort the headers of the current message according to `message-header-format-alist'."
  2380. (interactive)
  2381. (save-excursion
  2382. (save-restriction
  2383. (let ((max (1+ (length message-header-format-alist)))
  2384. rank)
  2385. (message-narrow-to-headers)
  2386. (while (re-search-forward "^[^ \n]+:" nil t)
  2387. (put-text-property
  2388. (match-beginning 0) (1+ (match-beginning 0))
  2389. 'message-rank
  2390. (if (setq rank (length (memq (assq (intern (buffer-substring
  2391. (match-beginning 0)
  2392. (1- (match-end 0))))
  2393. message-header-format-alist)
  2394. message-header-format-alist)))
  2395. (- max rank)
  2396. (1+ max)))))
  2397. (message-sort-headers-1))))
  2398. (defun message-kill-address ()
  2399. "Kill the address under point."
  2400. (interactive)
  2401. (let ((start (point)))
  2402. (message-skip-to-next-address)
  2403. (kill-region start (if (bolp) (1- (point)) (point)))))
  2404. (autoload 'Info-goto-node "info")
  2405. (defvar mml2015-use)
  2406. (defun message-info (&optional arg)
  2407. "Display the Message manual.
  2408. Prefixed with one \\[universal-argument], display the Emacs MIME
  2409. manual. With two \\[universal-argument]'s, display the EasyPG or
  2410. PGG manual, depending on the value of `mml2015-use'."
  2411. (interactive "p")
  2412. ;; Don't use `info' because support for `(filename)nodename' is not
  2413. ;; available in XEmacs < 21.5.12.
  2414. (Info-goto-node (format "(%s)Top"
  2415. (cond ((eq arg 16)
  2416. (require 'mml2015)
  2417. mml2015-use)
  2418. ((eq arg 4) 'emacs-mime)
  2419. ;; `booleanp' only available in Emacs 22+
  2420. ((and (not (memq arg '(nil t)))
  2421. (symbolp arg))
  2422. arg)
  2423. (t
  2424. 'message)))))
  2425. ;;;
  2426. ;;; Message mode
  2427. ;;;
  2428. ;;; Set up keymap.
  2429. (defvar message-mode-map nil)
  2430. (unless message-mode-map
  2431. (setq message-mode-map (make-keymap))
  2432. (set-keymap-parent message-mode-map text-mode-map)
  2433. (define-key message-mode-map "\C-c?" 'describe-mode)
  2434. (define-key message-mode-map "\C-c\C-f\C-t" 'message-goto-to)
  2435. (define-key message-mode-map "\C-c\C-f\C-o" 'message-goto-from)
  2436. (define-key message-mode-map "\C-c\C-f\C-b" 'message-goto-bcc)
  2437. (define-key message-mode-map "\C-c\C-f\C-w" 'message-goto-fcc)
  2438. (define-key message-mode-map "\C-c\C-f\C-c" 'message-goto-cc)
  2439. (define-key message-mode-map "\C-c\C-f\C-s" 'message-goto-subject)
  2440. (define-key message-mode-map "\C-c\C-f\C-r" 'message-goto-reply-to)
  2441. (define-key message-mode-map "\C-c\C-f\C-n" 'message-goto-newsgroups)
  2442. (define-key message-mode-map "\C-c\C-f\C-d" 'message-goto-distribution)
  2443. (define-key message-mode-map "\C-c\C-f\C-f" 'message-goto-followup-to)
  2444. (define-key message-mode-map "\C-c\C-f\C-m" 'message-goto-mail-followup-to)
  2445. (define-key message-mode-map "\C-c\C-f\C-k" 'message-goto-keywords)
  2446. (define-key message-mode-map "\C-c\C-f\C-u" 'message-goto-summary)
  2447. (define-key message-mode-map "\C-c\C-f\C-i"
  2448. 'message-insert-or-toggle-importance)
  2449. (define-key message-mode-map "\C-c\C-f\C-a"
  2450. 'message-generate-unsubscribed-mail-followup-to)
  2451. ;; modify headers (and insert notes in body)
  2452. (define-key message-mode-map "\C-c\C-fs" 'message-change-subject)
  2453. ;;
  2454. (define-key message-mode-map "\C-c\C-fx" 'message-cross-post-followup-to)
  2455. ;; prefix+message-cross-post-followup-to = same w/o cross-post
  2456. (define-key message-mode-map "\C-c\C-ft" 'message-reduce-to-to-cc)
  2457. (define-key message-mode-map "\C-c\C-fa" 'message-add-archive-header)
  2458. ;; mark inserted text
  2459. (define-key message-mode-map "\C-c\M-m" 'message-mark-inserted-region)
  2460. (define-key message-mode-map "\C-c\M-f" 'message-mark-insert-file)
  2461. (define-key message-mode-map "\C-c\C-b" 'message-goto-body)
  2462. (define-key message-mode-map "\C-c\C-i" 'message-goto-signature)
  2463. (define-key message-mode-map "\C-c\C-t" 'message-insert-to)
  2464. (define-key message-mode-map "\C-c\C-fw" 'message-insert-wide-reply)
  2465. (define-key message-mode-map "\C-c\C-n" 'message-insert-newsgroups)
  2466. (define-key message-mode-map "\C-c\C-l" 'message-to-list-only)
  2467. (define-key message-mode-map "\C-c\C-f\C-e" 'message-insert-expires)
  2468. (define-key message-mode-map "\C-c\C-u" 'message-insert-or-toggle-importance)
  2469. (define-key message-mode-map "\C-c\M-n"
  2470. 'message-insert-disposition-notification-to)
  2471. (define-key message-mode-map "\C-c\C-y" 'message-yank-original)
  2472. (define-key message-mode-map "\C-c\M-\C-y" 'message-yank-buffer)
  2473. (define-key message-mode-map "\C-c\C-q" 'message-fill-yanked-message)
  2474. (define-key message-mode-map "\C-c\C-w" 'message-insert-signature)
  2475. (define-key message-mode-map "\C-c\M-h" 'message-insert-headers)
  2476. (define-key message-mode-map "\C-c\C-r" 'message-caesar-buffer-body)
  2477. (define-key message-mode-map "\C-c\C-o" 'message-sort-headers)
  2478. (define-key message-mode-map "\C-c\M-r" 'message-rename-buffer)
  2479. (define-key message-mode-map "\C-c\C-c" 'message-send-and-exit)
  2480. (define-key message-mode-map "\C-c\C-s" 'message-send)
  2481. (define-key message-mode-map "\C-c\C-k" 'message-kill-buffer)
  2482. (define-key message-mode-map "\C-c\C-d" 'message-dont-send)
  2483. (define-key message-mode-map "\C-c\n" 'gnus-delay-article)
  2484. (define-key message-mode-map "\C-c\M-k" 'message-kill-address)
  2485. (define-key message-mode-map "\C-c\C-e" 'message-elide-region)
  2486. (define-key message-mode-map "\C-c\C-v" 'message-delete-not-region)
  2487. (define-key message-mode-map "\C-c\C-z" 'message-kill-to-signature)
  2488. (define-key message-mode-map "\M-\r" 'message-newline-and-reformat)
  2489. (define-key message-mode-map [remap split-line] 'message-split-line)
  2490. (define-key message-mode-map "\C-c\C-a" 'mml-attach-file)
  2491. (define-key message-mode-map "\C-a" 'message-beginning-of-line)
  2492. (define-key message-mode-map "\t" 'message-tab)
  2493. (define-key message-mode-map "\M-n" 'message-display-abbrev))
  2494. (easy-menu-define
  2495. message-mode-menu message-mode-map "Message Menu."
  2496. `("Message"
  2497. ["Yank Original" message-yank-original message-reply-buffer]
  2498. ["Fill Yanked Message" message-fill-yanked-message t]
  2499. ["Insert Signature" message-insert-signature t]
  2500. ["Caesar (rot13) Message" message-caesar-buffer-body t]
  2501. ["Caesar (rot13) Region" message-caesar-region (message-mark-active-p)]
  2502. ["Elide Region" message-elide-region
  2503. :active (message-mark-active-p)
  2504. ,@(if (featurep 'xemacs) nil
  2505. '(:help "Replace text in region with an ellipsis"))]
  2506. ["Delete Outside Region" message-delete-not-region
  2507. :active (message-mark-active-p)
  2508. ,@(if (featurep 'xemacs) nil
  2509. '(:help "Delete all quoted text outside region"))]
  2510. ["Kill To Signature" message-kill-to-signature t]
  2511. ["Newline and Reformat" message-newline-and-reformat t]
  2512. ["Rename buffer" message-rename-buffer t]
  2513. ["Spellcheck" ispell-message
  2514. ,@(if (featurep 'xemacs) '(t)
  2515. '(:help "Spellcheck this message"))]
  2516. "----"
  2517. ["Insert Region Marked" message-mark-inserted-region
  2518. :active (message-mark-active-p)
  2519. ,@(if (featurep 'xemacs) nil
  2520. '(:help "Mark region with enclosing tags"))]
  2521. ["Insert File Marked..." message-mark-insert-file
  2522. ,@(if (featurep 'xemacs) '(t)
  2523. '(:help "Insert file at point marked with enclosing tags"))]
  2524. "----"
  2525. ["Send Message" message-send-and-exit
  2526. ,@(if (featurep 'xemacs) '(t)
  2527. '(:help "Send this message"))]
  2528. ["Postpone Message" message-dont-send
  2529. ,@(if (featurep 'xemacs) '(t)
  2530. '(:help "File this draft message and exit"))]
  2531. ["Send at Specific Time..." gnus-delay-article
  2532. ,@(if (featurep 'xemacs) '(t)
  2533. '(:help "Ask, then arrange to send message at that time"))]
  2534. ["Kill Message" message-kill-buffer
  2535. ,@(if (featurep 'xemacs) '(t)
  2536. '(:help "Delete this message without sending"))]
  2537. "----"
  2538. ["Message manual" message-info
  2539. ,@(if (featurep 'xemacs) '(t)
  2540. '(:help "Display the Message manual"))]))
  2541. (easy-menu-define
  2542. message-mode-field-menu message-mode-map ""
  2543. `("Field"
  2544. ["To" message-goto-to t]
  2545. ["From" message-goto-from t]
  2546. ["Subject" message-goto-subject t]
  2547. ["Change subject..." message-change-subject t]
  2548. ["Cc" message-goto-cc t]
  2549. ["Bcc" message-goto-bcc t]
  2550. ["Fcc" message-goto-fcc t]
  2551. ["Reply-To" message-goto-reply-to t]
  2552. ["Flag As Important" message-insert-importance-high
  2553. ,@(if (featurep 'xemacs) '(t)
  2554. '(:help "Mark this message as important"))]
  2555. ["Flag As Unimportant" message-insert-importance-low
  2556. ,@(if (featurep 'xemacs) '(t)
  2557. '(:help "Mark this message as unimportant"))]
  2558. ["Request Receipt"
  2559. message-insert-disposition-notification-to
  2560. ,@(if (featurep 'xemacs) '(t)
  2561. '(:help "Request a receipt notification"))]
  2562. "----"
  2563. ;; (typical) news stuff
  2564. ["Summary" message-goto-summary t]
  2565. ["Keywords" message-goto-keywords t]
  2566. ["Newsgroups" message-goto-newsgroups t]
  2567. ["Fetch Newsgroups" message-insert-newsgroups t]
  2568. ["Followup-To" message-goto-followup-to t]
  2569. ;; ["Followup-To (with note in body)" message-cross-post-followup-to t]
  2570. ["Crosspost / Followup-To..." message-cross-post-followup-to t]
  2571. ["Distribution" message-goto-distribution t]
  2572. ["Expires" message-insert-expires t ]
  2573. ["X-No-Archive" message-add-archive-header t ]
  2574. "----"
  2575. ;; (typical) mailing-lists stuff
  2576. ["Fetch To" message-insert-to
  2577. ,@(if (featurep 'xemacs) '(t)
  2578. '(:help "Insert a To header that points to the author."))]
  2579. ["Fetch To and Cc" message-insert-wide-reply
  2580. ,@(if (featurep 'xemacs) '(t)
  2581. '(:help
  2582. "Insert To and Cc headers as if you were doing a wide reply."))]
  2583. "----"
  2584. ["Send to list only" message-to-list-only t]
  2585. ["Mail-Followup-To" message-goto-mail-followup-to t]
  2586. ["Unsubscribed list post" message-generate-unsubscribed-mail-followup-to
  2587. ,@(if (featurep 'xemacs) '(t)
  2588. '(:help "Insert a reasonable `Mail-Followup-To:' header."))]
  2589. ["Reduce To: to Cc:" message-reduce-to-to-cc t]
  2590. "----"
  2591. ["Sort Headers" message-sort-headers t]
  2592. ["Encode non-ASCII domain names" message-idna-to-ascii-rhs t]
  2593. ;; We hide `message-hidden-headers' by narrowing the buffer.
  2594. ["Show Hidden Headers" widen t]
  2595. ["Goto Body" message-goto-body t]
  2596. ["Goto Signature" message-goto-signature t]))
  2597. (defvar message-tool-bar-map nil)
  2598. (defvar facemenu-add-face-function)
  2599. (defvar facemenu-remove-face-function)
  2600. ;;; Forbidden properties
  2601. ;;
  2602. ;; We use `after-change-functions' to keep special text properties
  2603. ;; that interfere with the normal function of message mode out of the
  2604. ;; buffer.
  2605. (defcustom message-strip-special-text-properties t
  2606. "Strip special properties from the message buffer.
  2607. Emacs has a number of special text properties which can break message
  2608. composing in various ways. If this option is set, message will strip
  2609. these properties from the message composition buffer. However, some
  2610. packages requires these properties to be present in order to work.
  2611. If you use one of these packages, turn this option off, and hope the
  2612. message composition doesn't break too bad."
  2613. :version "22.1"
  2614. :group 'message-various
  2615. :link '(custom-manual "(message)Various Message Variables")
  2616. :type 'boolean)
  2617. (defvar message-forbidden-properties
  2618. ;; No reason this should be clutter up customize. We make it a
  2619. ;; property list (rather than a list of property symbols), to be
  2620. ;; directly useful for `remove-text-properties'.
  2621. '(field nil read-only nil invisible nil intangible nil
  2622. mouse-face nil modification-hooks nil insert-in-front-hooks nil
  2623. insert-behind-hooks nil point-entered nil point-left nil)
  2624. ;; Other special properties:
  2625. ;; category, face, display: probably doesn't do any harm.
  2626. ;; fontified: is used by font-lock.
  2627. ;; syntax-table, local-map: I dunno.
  2628. ;; We need to add XEmacs names to the list.
  2629. "Property list of with properties forbidden in message buffers.
  2630. The values of the properties are ignored, only the property names are used.")
  2631. (defun message-tamago-not-in-use-p (pos)
  2632. "Return t when tamago version 4 is not in use at the cursor position.
  2633. Tamago version 4 is a popular input method for writing Japanese text.
  2634. It uses the properties `intangible', `invisible', `modification-hooks'
  2635. and `read-only' when translating ascii or kana text to kanji text.
  2636. These properties are essential to work, so we should never strip them."
  2637. (not (and (boundp 'egg-modefull-mode)
  2638. (symbol-value 'egg-modefull-mode)
  2639. (or (memq (get-text-property pos 'intangible)
  2640. '(its-part-1 its-part-2))
  2641. (get-text-property pos 'egg-end)
  2642. (get-text-property pos 'egg-lang)
  2643. (get-text-property pos 'egg-start)))))
  2644. (defsubst message-mail-alias-type-p (type)
  2645. (if (atom message-mail-alias-type)
  2646. (eq message-mail-alias-type type)
  2647. (memq type message-mail-alias-type)))
  2648. (defun message-strip-forbidden-properties (begin end &optional old-length)
  2649. "Strip forbidden properties between BEGIN and END, ignoring the third arg.
  2650. This function is intended to be called from `after-change-functions'.
  2651. See also `message-forbidden-properties'."
  2652. (when (and (message-mail-alias-type-p 'ecomplete)
  2653. (memq this-command message-self-insert-commands))
  2654. (message-display-abbrev))
  2655. (when (and message-strip-special-text-properties
  2656. (message-tamago-not-in-use-p begin))
  2657. (let ((buffer-read-only nil)
  2658. (inhibit-read-only t))
  2659. (remove-text-properties begin end message-forbidden-properties))))
  2660. (autoload 'ecomplete-setup "ecomplete") ;; for Emacs <23.
  2661. (defvar message-smileys '(":-)" ":)"
  2662. ":-(" ":("
  2663. ";-)" ";)")
  2664. "A list of recognized smiley faces in `message-mode'.")
  2665. (defun message--syntax-propertize (beg end)
  2666. "Syntax-propertize certain message text specially."
  2667. (let ((citation-regexp (concat "^" message-cite-prefix-regexp ".*$"))
  2668. (smiley-regexp (regexp-opt message-smileys)))
  2669. (goto-char beg)
  2670. (while (search-forward-regexp citation-regexp
  2671. end 'noerror)
  2672. (let ((start (match-beginning 0))
  2673. (end (match-end 0)))
  2674. (add-text-properties start (1+ start)
  2675. `(syntax-table ,(string-to-syntax "<")))
  2676. (add-text-properties end (min (1+ end) (point-max))
  2677. `(syntax-table ,(string-to-syntax ">")))))
  2678. (goto-char beg)
  2679. (while (search-forward-regexp smiley-regexp
  2680. end 'noerror)
  2681. (add-text-properties (match-beginning 0) (match-end 0)
  2682. `(syntax-table ,(string-to-syntax "."))))))
  2683. ;;;###autoload
  2684. (define-derived-mode message-mode text-mode "Message"
  2685. "Major mode for editing mail and news to be sent.
  2686. Like Text Mode but with these additional commands:\\<message-mode-map>
  2687. C-c C-s `message-send' (send the message) C-c C-c `message-send-and-exit'
  2688. C-c C-d Postpone sending the message C-c C-k Kill the message
  2689. C-c C-f move to a header field (and create it if there isn't):
  2690. C-c C-f C-t move to To C-c C-f C-s move to Subject
  2691. C-c C-f C-c move to Cc C-c C-f C-b move to Bcc
  2692. C-c C-f C-w move to Fcc C-c C-f C-r move to Reply-To
  2693. C-c C-f C-u move to Summary C-c C-f C-n move to Newsgroups
  2694. C-c C-f C-k move to Keywords C-c C-f C-d move to Distribution
  2695. C-c C-f C-o move to From (\"Originator\")
  2696. C-c C-f C-f move to Followup-To
  2697. C-c C-f C-m move to Mail-Followup-To
  2698. C-c C-f C-e move to Expires
  2699. C-c C-f C-i cycle through Importance values
  2700. C-c C-f s change subject and append \"(was: <Old Subject>)\"
  2701. C-c C-f x crossposting with FollowUp-To header and note in body
  2702. C-c C-f t replace To: header with contents of Cc: or Bcc:
  2703. C-c C-f a Insert X-No-Archive: header and a note in the body
  2704. C-c C-t `message-insert-to' (add a To header to a news followup)
  2705. C-c C-l `message-to-list-only' (removes all but list address in to/cc)
  2706. C-c C-n `message-insert-newsgroups' (add a Newsgroup header to a news reply)
  2707. C-c C-b `message-goto-body' (move to beginning of message text).
  2708. C-c C-i `message-goto-signature' (move to the beginning of the signature).
  2709. C-c C-w `message-insert-signature' (insert `message-signature-file' file).
  2710. C-c C-y `message-yank-original' (insert current message, if any).
  2711. C-c C-q `message-fill-yanked-message' (fill what was yanked).
  2712. C-c C-e `message-elide-region' (elide the text between point and mark).
  2713. C-c C-v `message-delete-not-region' (remove the text outside the region).
  2714. C-c C-z `message-kill-to-signature' (kill the text up to the signature).
  2715. C-c C-r `message-caesar-buffer-body' (rot13 the message body).
  2716. C-c C-a `mml-attach-file' (attach a file as MIME).
  2717. C-c C-u `message-insert-or-toggle-importance' (insert or cycle importance).
  2718. C-c M-n `message-insert-disposition-notification-to' (request receipt).
  2719. C-c M-m `message-mark-inserted-region' (mark region with enclosing tags).
  2720. C-c M-f `message-mark-insert-file' (insert file marked with enclosing tags).
  2721. M-RET `message-newline-and-reformat' (break the line and reformat)."
  2722. (set (make-local-variable 'message-reply-buffer) nil)
  2723. (set (make-local-variable 'message-inserted-headers) nil)
  2724. (set (make-local-variable 'message-send-actions) nil)
  2725. (set (make-local-variable 'message-return-action) nil)
  2726. (set (make-local-variable 'message-exit-actions) nil)
  2727. (set (make-local-variable 'message-kill-actions) nil)
  2728. (set (make-local-variable 'message-postpone-actions) nil)
  2729. (set (make-local-variable 'message-draft-article) nil)
  2730. (setq buffer-offer-save t)
  2731. (set (make-local-variable 'facemenu-add-face-function)
  2732. (lambda (face end)
  2733. (let ((face-fun (cdr (assq face message-face-alist))))
  2734. (if face-fun
  2735. (funcall face-fun (point) end)
  2736. (error "Face %s not configured for %s mode" face mode-name)))
  2737. ""))
  2738. (set (make-local-variable 'facemenu-remove-face-function) t)
  2739. (set (make-local-variable 'message-reply-headers) nil)
  2740. (make-local-variable 'message-newsreader)
  2741. (make-local-variable 'message-mailer)
  2742. (make-local-variable 'message-post-method)
  2743. (set (make-local-variable 'message-sent-message-via) nil)
  2744. (set (make-local-variable 'message-checksum) nil)
  2745. (set (make-local-variable 'message-mime-part) 0)
  2746. (message-setup-fill-variables)
  2747. (when message-fill-column
  2748. (setq fill-column message-fill-column)
  2749. (turn-on-auto-fill))
  2750. ;; Allow using comment commands to add/remove quoting.
  2751. ;; (set (make-local-variable 'comment-start) message-yank-prefix)
  2752. (when message-yank-prefix
  2753. (set (make-local-variable 'comment-start) message-yank-prefix)
  2754. (set (make-local-variable 'comment-start-skip)
  2755. (concat "^" (regexp-quote message-yank-prefix) "[ \t]*")))
  2756. (if (featurep 'xemacs)
  2757. (message-setup-toolbar)
  2758. (set (make-local-variable 'font-lock-defaults)
  2759. '(message-font-lock-keywords t))
  2760. (if (boundp 'tool-bar-map)
  2761. (set (make-local-variable 'tool-bar-map) (message-make-tool-bar))))
  2762. (easy-menu-add message-mode-menu message-mode-map)
  2763. (easy-menu-add message-mode-field-menu message-mode-map)
  2764. (gnus-make-local-hook 'after-change-functions)
  2765. ;; Mmmm... Forbidden properties...
  2766. (add-hook 'after-change-functions 'message-strip-forbidden-properties
  2767. nil 'local)
  2768. ;; Allow mail alias things.
  2769. (cond
  2770. ((message-mail-alias-type-p 'abbrev)
  2771. (if (fboundp 'mail-abbrevs-setup)
  2772. (mail-abbrevs-setup)
  2773. (if (fboundp 'mail-aliases-setup) ; warning avoidance
  2774. (mail-aliases-setup))))
  2775. ((message-mail-alias-type-p 'ecomplete)
  2776. (ecomplete-setup)))
  2777. (add-hook 'completion-at-point-functions 'message-completion-function nil t)
  2778. (unless buffer-file-name
  2779. (message-set-auto-save-file-name))
  2780. (unless (buffer-base-buffer)
  2781. ;; Don't enable multibyte on an indirect buffer. Maybe enabling
  2782. ;; multibyte is not necessary at all. -- zsh
  2783. (mm-enable-multibyte))
  2784. (set (make-local-variable 'indent-tabs-mode) nil) ;No tabs for indentation.
  2785. (mml-mode)
  2786. ;; Syntactic fontification. Helps `show-paren-mode',
  2787. ;; `electric-pair-mode', and C-M-* navigation by syntactically
  2788. ;; excluding citations and other artifacts.
  2789. ;;
  2790. (set (make-local-variable 'syntax-propertize-function) 'message--syntax-propertize)
  2791. (set (make-local-variable 'parse-sexp-ignore-comments) t))
  2792. (defun message-setup-fill-variables ()
  2793. "Setup message fill variables."
  2794. (set (make-local-variable 'fill-paragraph-function)
  2795. 'message-fill-paragraph)
  2796. (make-local-variable 'paragraph-separate)
  2797. (make-local-variable 'paragraph-start)
  2798. (make-local-variable 'adaptive-fill-regexp)
  2799. (unless (boundp 'adaptive-fill-first-line-regexp)
  2800. (setq adaptive-fill-first-line-regexp nil))
  2801. (make-local-variable 'adaptive-fill-first-line-regexp)
  2802. (let ((quote-prefix-regexp
  2803. ;; User should change message-cite-prefix-regexp if
  2804. ;; message-yank-prefix is set to an abnormal value.
  2805. (concat "\\(" message-cite-prefix-regexp "\\)[ \t]*")))
  2806. (setq paragraph-start
  2807. (concat
  2808. (regexp-quote mail-header-separator) "$\\|"
  2809. "[ \t]*$\\|" ; blank lines
  2810. "-- $\\|" ; signature delimiter
  2811. "---+$\\|" ; delimiters for forwarded messages
  2812. page-delimiter "$\\|" ; spoiler warnings
  2813. ".*wrote:$\\|" ; attribution lines
  2814. quote-prefix-regexp "$\\|" ; empty lines in quoted text
  2815. ; mml tags
  2816. "<#!*/?\\(multipart\\|part\\|external\\|mml\\|secure\\)"))
  2817. (setq paragraph-separate paragraph-start)
  2818. (setq adaptive-fill-regexp
  2819. (concat quote-prefix-regexp "\\|" adaptive-fill-regexp))
  2820. (setq adaptive-fill-first-line-regexp
  2821. (concat quote-prefix-regexp "\\|"
  2822. adaptive-fill-first-line-regexp)))
  2823. (make-local-variable 'auto-fill-inhibit-regexp)
  2824. ;;(setq auto-fill-inhibit-regexp "^[A-Z][^: \n\t]+:")
  2825. (setq auto-fill-inhibit-regexp nil)
  2826. (make-local-variable 'normal-auto-fill-function)
  2827. (setq normal-auto-fill-function 'message-do-auto-fill)
  2828. ;; KLUDGE: auto fill might already be turned on in `text-mode-hook'.
  2829. ;; In that case, ensure that it uses the right function. The real
  2830. ;; solution would be not to use `define-derived-mode', and run
  2831. ;; `text-mode-hook' ourself at the end of the mode.
  2832. ;; -- Per Abrahamsen <abraham@dina.kvl.dk> Date: 2001-10-19.
  2833. ;; This kludge is unneeded in Emacs>=21 since define-derived-mode is
  2834. ;; now careful to run parent hooks after the body. --Stef
  2835. (when auto-fill-function
  2836. (setq auto-fill-function normal-auto-fill-function)))
  2837. ;;;
  2838. ;;; Message mode commands
  2839. ;;;
  2840. ;;; Movement commands
  2841. (defun message-goto-to ()
  2842. "Move point to the To header."
  2843. (interactive)
  2844. (push-mark)
  2845. (message-position-on-field "To"))
  2846. (defun message-goto-from ()
  2847. "Move point to the From header."
  2848. (interactive)
  2849. (push-mark)
  2850. (message-position-on-field "From"))
  2851. (defun message-goto-subject ()
  2852. "Move point to the Subject header."
  2853. (interactive)
  2854. (push-mark)
  2855. (message-position-on-field "Subject"))
  2856. (defun message-goto-cc ()
  2857. "Move point to the Cc header."
  2858. (interactive)
  2859. (push-mark)
  2860. (message-position-on-field "Cc" "To"))
  2861. (defun message-goto-bcc ()
  2862. "Move point to the Bcc header."
  2863. (interactive)
  2864. (push-mark)
  2865. (message-position-on-field "Bcc" "Cc" "To"))
  2866. (defun message-goto-fcc ()
  2867. "Move point to the Fcc header."
  2868. (interactive)
  2869. (push-mark)
  2870. (message-position-on-field "Fcc" "To" "Newsgroups"))
  2871. (defun message-goto-reply-to ()
  2872. "Move point to the Reply-To header."
  2873. (interactive)
  2874. (push-mark)
  2875. (message-position-on-field "Reply-To" "Subject"))
  2876. (defun message-goto-newsgroups ()
  2877. "Move point to the Newsgroups header."
  2878. (interactive)
  2879. (push-mark)
  2880. (message-position-on-field "Newsgroups"))
  2881. (defun message-goto-distribution ()
  2882. "Move point to the Distribution header."
  2883. (interactive)
  2884. (push-mark)
  2885. (message-position-on-field "Distribution"))
  2886. (defun message-goto-followup-to ()
  2887. "Move point to the Followup-To header."
  2888. (interactive)
  2889. (push-mark)
  2890. (message-position-on-field "Followup-To" "Newsgroups"))
  2891. (defun message-goto-mail-followup-to ()
  2892. "Move point to the Mail-Followup-To header."
  2893. (interactive)
  2894. (push-mark)
  2895. (message-position-on-field "Mail-Followup-To" "To"))
  2896. (defun message-goto-keywords ()
  2897. "Move point to the Keywords header."
  2898. (interactive)
  2899. (push-mark)
  2900. (message-position-on-field "Keywords" "Subject"))
  2901. (defun message-goto-summary ()
  2902. "Move point to the Summary header."
  2903. (interactive)
  2904. (push-mark)
  2905. (message-position-on-field "Summary" "Subject"))
  2906. (defun message-goto-body ()
  2907. "Move point to the beginning of the message body."
  2908. (interactive)
  2909. (when (and (gmm-called-interactively-p 'any)
  2910. (looking-at "[ \t]*\n"))
  2911. (expand-abbrev))
  2912. (push-mark)
  2913. (goto-char (point-min))
  2914. (or (search-forward (concat "\n" mail-header-separator "\n") nil t)
  2915. (search-forward-regexp "[^:]+:\\([^\n]\\|\n[ \t]\\)+\n\n" nil t)))
  2916. (defun message-in-body-p ()
  2917. "Return t if point is in the message body."
  2918. (>= (point)
  2919. (save-excursion
  2920. (goto-char (point-min))
  2921. (or (search-forward (concat "\n" mail-header-separator "\n") nil t)
  2922. (search-forward-regexp "[^:]+:\\([^\n]\\|\n[ \t]\\)+\n\n" nil t))
  2923. (point))))
  2924. (defun message-goto-eoh ()
  2925. "Move point to the end of the headers."
  2926. (interactive)
  2927. (message-goto-body)
  2928. (forward-line -1))
  2929. (defun message-goto-signature ()
  2930. "Move point to the beginning of the message signature.
  2931. If there is no signature in the article, go to the end and
  2932. return nil."
  2933. (interactive)
  2934. (push-mark)
  2935. (goto-char (point-min))
  2936. (if (re-search-forward message-signature-separator nil t)
  2937. (forward-line 1)
  2938. (goto-char (point-max))
  2939. nil))
  2940. (defun message-generate-unsubscribed-mail-followup-to (&optional include-cc)
  2941. "Insert a reasonable MFT header in a post to an unsubscribed list.
  2942. When making original posts to a mailing list you are not subscribed to,
  2943. you have to type in a MFT header by hand. The contents, usually, are
  2944. the addresses of the list and your own address. This function inserts
  2945. such a header automatically. It fetches the contents of the To: header
  2946. in the current mail buffer, and appends the current `user-mail-address'.
  2947. If the optional argument INCLUDE-CC is non-nil, the addresses in the
  2948. Cc: header are also put into the MFT."
  2949. (interactive "P")
  2950. (let* (cc tos)
  2951. (save-restriction
  2952. (message-narrow-to-headers)
  2953. (message-remove-header "Mail-Followup-To")
  2954. (setq cc (and include-cc (message-fetch-field "Cc")))
  2955. (setq tos (if cc
  2956. (concat (message-fetch-field "To") "," cc)
  2957. (message-fetch-field "To"))))
  2958. (message-goto-mail-followup-to)
  2959. (insert (concat tos ", " user-mail-address))))
  2960. (defun message-insert-to (&optional force)
  2961. "Insert a To header that points to the author of the article being replied to.
  2962. If the original author requested not to be sent mail, don't insert unless the
  2963. prefix FORCE is given."
  2964. (interactive "P")
  2965. (let* ((mct (message-fetch-reply-field "mail-copies-to"))
  2966. (dont (and mct (or (equal (downcase mct) "never")
  2967. (equal (downcase mct) "nobody"))))
  2968. (to (or (message-fetch-reply-field "mail-reply-to")
  2969. (message-fetch-reply-field "reply-to")
  2970. (message-fetch-reply-field "from"))))
  2971. (when (and dont to)
  2972. (message
  2973. (if force
  2974. "Ignoring the user request not to have copies sent via mail"
  2975. "Complying with the user request not to have copies sent via mail")))
  2976. (when (and force (not to))
  2977. (error "No mail address in the article"))
  2978. (when (and to (or force (not dont)))
  2979. (message-carefully-insert-headers (list (cons 'To to))))))
  2980. (defun message-insert-wide-reply ()
  2981. "Insert To and Cc headers as if you were doing a wide reply."
  2982. (interactive)
  2983. (let ((headers (message-with-reply-buffer
  2984. (message-get-reply-headers t))))
  2985. (message-carefully-insert-headers headers)))
  2986. (defcustom message-header-synonyms
  2987. '((To Cc Bcc)
  2988. (Original-To))
  2989. "List of lists of header synonyms.
  2990. E.g., if this list contains a member list with elements `Cc' and `To',
  2991. then `message-carefully-insert-headers' will not insert a `To' header
  2992. when the message is already `Cc'ed to the recipient."
  2993. :version "22.1"
  2994. :group 'message-headers
  2995. :link '(custom-manual "(message)Message Headers")
  2996. :type '(repeat sexp))
  2997. (defun message-carefully-insert-headers (headers)
  2998. "Insert the HEADERS, an alist, into the message buffer.
  2999. Does not insert the headers when they are already present there
  3000. or in the synonym headers, defined by `message-header-synonyms'."
  3001. ;; FIXME: Should compare only the address and not the full name. Comparison
  3002. ;; should be done case-folded (and with `string=' rather than
  3003. ;; `string-match').
  3004. ;; (mail-strip-quoted-names "Foo Bar <foo@bar>, bla@fasel (Bla Fasel)")
  3005. (dolist (header headers)
  3006. (let* ((header-name (symbol-name (car header)))
  3007. (new-header (cdr header))
  3008. (synonyms (loop for synonym in message-header-synonyms
  3009. when (memq (car header) synonym) return synonym))
  3010. (old-header
  3011. (loop for synonym in synonyms
  3012. for old-header = (mail-fetch-field (symbol-name synonym))
  3013. when (and old-header (string-match new-header old-header))
  3014. return synonym)))
  3015. (if old-header
  3016. (message "already have `%s' in `%s'" new-header old-header)
  3017. (when (and (message-position-on-field header-name)
  3018. (setq old-header (mail-fetch-field header-name))
  3019. (not (string-match "\\` *\\'" old-header)))
  3020. (insert ", "))
  3021. (insert new-header)))))
  3022. (defun message-widen-reply ()
  3023. "Widen the reply to include maximum recipients."
  3024. (interactive)
  3025. (let ((follow-to
  3026. (and (bufferp message-reply-buffer)
  3027. (buffer-name message-reply-buffer)
  3028. (with-current-buffer message-reply-buffer
  3029. (message-get-reply-headers t)))))
  3030. (save-excursion
  3031. (save-restriction
  3032. (message-narrow-to-headers)
  3033. (dolist (elem follow-to)
  3034. (message-remove-header (symbol-name (car elem)))
  3035. (goto-char (point-min))
  3036. (insert (symbol-name (car elem)) ": "
  3037. (cdr elem) "\n"))))))
  3038. (defun message-insert-newsgroups ()
  3039. "Insert the Newsgroups header from the article being replied to."
  3040. (interactive)
  3041. (let ((old-newsgroups (mail-fetch-field "newsgroups"))
  3042. (new-newsgroups (message-fetch-reply-field "newsgroups"))
  3043. (first t)
  3044. insert-newsgroups)
  3045. (message-position-on-field "Newsgroups")
  3046. (cond
  3047. ((not new-newsgroups)
  3048. (error "No Newsgroups to insert"))
  3049. ((not old-newsgroups)
  3050. (insert new-newsgroups))
  3051. (t
  3052. (setq new-newsgroups (split-string new-newsgroups "[, ]+")
  3053. old-newsgroups (split-string old-newsgroups "[, ]+"))
  3054. (dolist (group new-newsgroups)
  3055. (unless (member group old-newsgroups)
  3056. (push group insert-newsgroups)))
  3057. (if (null insert-newsgroups)
  3058. (error "Newgroup%s already in the header"
  3059. (if (> (length new-newsgroups) 1)
  3060. "s" ""))
  3061. (when old-newsgroups
  3062. (setq first nil))
  3063. (dolist (group insert-newsgroups)
  3064. (unless first
  3065. (insert ","))
  3066. (setq first nil)
  3067. (insert group)))))))
  3068. ;;; Various commands
  3069. (defun message-delete-not-region (beg end)
  3070. "Delete everything in the body of the current message outside of the region."
  3071. (interactive "r")
  3072. (let (citeprefix)
  3073. (save-excursion
  3074. (goto-char beg)
  3075. ;; snarf citation prefix, if appropriate
  3076. (unless (eq (point) (progn (beginning-of-line) (point)))
  3077. (when (looking-at message-cite-prefix-regexp)
  3078. (setq citeprefix (match-string 0))))
  3079. (goto-char end)
  3080. (delete-region (point) (if (not (message-goto-signature))
  3081. (point)
  3082. (forward-line -2)
  3083. (point)))
  3084. (insert "\n")
  3085. (goto-char beg)
  3086. (delete-region beg (progn (message-goto-body)
  3087. (forward-line 2)
  3088. (point)))
  3089. (when citeprefix
  3090. (insert citeprefix))))
  3091. (when (message-goto-signature)
  3092. (forward-line -2)))
  3093. (defun message-kill-to-signature (&optional arg)
  3094. "Kill all text up to the signature.
  3095. If a numeric argument or prefix arg is given, leave that number
  3096. of lines before the signature intact."
  3097. (interactive "P")
  3098. (save-excursion
  3099. (save-restriction
  3100. (let ((point (point)))
  3101. (narrow-to-region point (point-max))
  3102. (message-goto-signature)
  3103. (unless (eobp)
  3104. (if (and arg (numberp arg))
  3105. (forward-line (- -1 arg))
  3106. (end-of-line -1)))
  3107. (unless (= point (point))
  3108. (kill-region point (point))
  3109. (unless (bolp)
  3110. (insert "\n")))))))
  3111. (defun message-newline-and-reformat (&optional arg not-break)
  3112. "Insert four newlines, and then reformat if inside quoted text.
  3113. Prefix arg means justify as well."
  3114. (interactive (list (if current-prefix-arg 'full)))
  3115. (let (quoted point beg end leading-space bolp fill-paragraph-function)
  3116. (setq point (point))
  3117. (beginning-of-line)
  3118. (setq beg (point))
  3119. (setq bolp (= beg point))
  3120. ;; Find first line of the paragraph.
  3121. (if not-break
  3122. (while (and (not (eobp))
  3123. (not (looking-at message-cite-prefix-regexp))
  3124. (looking-at paragraph-start))
  3125. (forward-line 1)))
  3126. ;; Find the prefix
  3127. (when (looking-at message-cite-prefix-regexp)
  3128. (setq quoted (match-string 0))
  3129. (goto-char (match-end 0))
  3130. (looking-at "[ \t]*")
  3131. (setq leading-space (match-string 0)))
  3132. (if (and quoted
  3133. (not not-break)
  3134. (not bolp)
  3135. (< (- point beg) (length quoted)))
  3136. ;; break inside the cite prefix.
  3137. (setq quoted nil
  3138. end nil))
  3139. (if quoted
  3140. (progn
  3141. (forward-line 1)
  3142. (while (and (not (eobp))
  3143. (not (looking-at paragraph-separate))
  3144. (looking-at message-cite-prefix-regexp)
  3145. (equal quoted (match-string 0)))
  3146. (goto-char (match-end 0))
  3147. (looking-at "[ \t]*")
  3148. (if (> (length leading-space) (length (match-string 0)))
  3149. (setq leading-space (match-string 0)))
  3150. (forward-line 1))
  3151. (setq end (point))
  3152. (goto-char beg)
  3153. (while (and (if (bobp) nil (forward-line -1) t)
  3154. (not (looking-at paragraph-start))
  3155. (looking-at message-cite-prefix-regexp)
  3156. (equal quoted (match-string 0)))
  3157. (setq beg (point))
  3158. (goto-char (match-end 0))
  3159. (looking-at "[ \t]*")
  3160. (if (> (length leading-space) (length (match-string 0)))
  3161. (setq leading-space (match-string 0)))))
  3162. (while (and (not (eobp))
  3163. (not (looking-at paragraph-separate))
  3164. (not (looking-at message-cite-prefix-regexp)))
  3165. (forward-line 1))
  3166. (setq end (point))
  3167. (goto-char beg)
  3168. (while (and (if (bobp) nil (forward-line -1) t)
  3169. (not (looking-at paragraph-start))
  3170. (not (looking-at message-cite-prefix-regexp)))
  3171. (setq beg (point))))
  3172. (goto-char point)
  3173. (save-restriction
  3174. (narrow-to-region beg end)
  3175. (if not-break
  3176. (setq point nil)
  3177. (if bolp
  3178. (newline)
  3179. (newline)
  3180. (newline))
  3181. (setq point (point))
  3182. ;; (newline 2) doesn't mark both newline's as hard, so call
  3183. ;; newline twice. -jas
  3184. (newline)
  3185. (newline)
  3186. (delete-region (point) (re-search-forward "[ \t]*"))
  3187. (when (and quoted (not bolp))
  3188. (insert quoted leading-space)))
  3189. (undo-boundary)
  3190. (if quoted
  3191. (let* ((adaptive-fill-regexp
  3192. (regexp-quote (concat quoted leading-space)))
  3193. (adaptive-fill-first-line-regexp
  3194. adaptive-fill-regexp ))
  3195. (fill-paragraph arg))
  3196. (fill-paragraph arg))
  3197. (if point (goto-char point)))))
  3198. (defun message-fill-paragraph (&optional arg)
  3199. "Message specific function to fill a paragraph.
  3200. This function is used as the value of `fill-paragraph-function' in
  3201. Message buffers and is not meant to be called directly."
  3202. (interactive (list (if current-prefix-arg 'full)))
  3203. (if (if (boundp 'filladapt-mode) filladapt-mode)
  3204. nil
  3205. (if (message-point-in-header-p)
  3206. (message-fill-field)
  3207. (message-newline-and-reformat arg t))
  3208. t))
  3209. (defun message-point-in-header-p ()
  3210. "Return t if point is in the header."
  3211. (save-excursion
  3212. (and
  3213. (not
  3214. (re-search-backward
  3215. (concat "^" (regexp-quote mail-header-separator) "\n") nil t))
  3216. (re-search-forward
  3217. (concat "^" (regexp-quote mail-header-separator) "\n") nil t))))
  3218. (defun message-do-auto-fill ()
  3219. "Like `do-auto-fill', but don't fill in message header."
  3220. (unless (message-point-in-header-p)
  3221. (do-auto-fill)))
  3222. (defun message-insert-signature (&optional force)
  3223. "Insert a signature. See documentation for variable `message-signature'."
  3224. (interactive (list 0))
  3225. (let* ((signature
  3226. (cond
  3227. ((and (null message-signature)
  3228. (eq force 0))
  3229. (save-excursion
  3230. (goto-char (point-max))
  3231. (not (re-search-backward message-signature-separator nil t))))
  3232. ((and (null message-signature)
  3233. force)
  3234. t)
  3235. ((functionp message-signature)
  3236. (funcall message-signature))
  3237. ((listp message-signature)
  3238. (eval message-signature))
  3239. (t message-signature)))
  3240. signature-file)
  3241. (setq signature
  3242. (cond ((stringp signature)
  3243. signature)
  3244. ((and (eq t signature) message-signature-file)
  3245. (setq signature-file
  3246. (if (and message-signature-directory
  3247. ;; don't actually use the signature directory
  3248. ;; if message-signature-file contains a path.
  3249. (not (file-name-directory
  3250. message-signature-file)))
  3251. (expand-file-name message-signature-file
  3252. message-signature-directory)
  3253. message-signature-file))
  3254. (file-exists-p signature-file))))
  3255. (when signature
  3256. (goto-char (point-max))
  3257. ;; Insert the signature.
  3258. (unless (bolp)
  3259. (newline))
  3260. (when message-signature-insert-empty-line
  3261. (newline))
  3262. (insert "-- ")
  3263. (newline)
  3264. (if (eq signature t)
  3265. (insert-file-contents signature-file)
  3266. (insert signature))
  3267. (goto-char (point-max))
  3268. (or (bolp) (newline)))))
  3269. (defun message-insert-importance-high ()
  3270. "Insert header to mark message as important."
  3271. (interactive)
  3272. (save-excursion
  3273. (save-restriction
  3274. (message-narrow-to-headers)
  3275. (message-remove-header "Importance"))
  3276. (message-goto-eoh)
  3277. (insert "Importance: high\n")))
  3278. (defun message-insert-importance-low ()
  3279. "Insert header to mark message as unimportant."
  3280. (interactive)
  3281. (save-excursion
  3282. (save-restriction
  3283. (message-narrow-to-headers)
  3284. (message-remove-header "Importance"))
  3285. (message-goto-eoh)
  3286. (insert "Importance: low\n")))
  3287. (defun message-insert-or-toggle-importance ()
  3288. "Insert a \"Importance: high\" header, or cycle through the header values.
  3289. The three allowed values according to RFC 1327 are `high', `normal'
  3290. and `low'."
  3291. (interactive)
  3292. (save-excursion
  3293. (let ((new "high")
  3294. cur)
  3295. (save-restriction
  3296. (message-narrow-to-headers)
  3297. (when (setq cur (message-fetch-field "Importance"))
  3298. (message-remove-header "Importance")
  3299. (setq new (cond ((string= cur "high")
  3300. "low")
  3301. ((string= cur "low")
  3302. "normal")
  3303. (t
  3304. "high")))))
  3305. (message-goto-eoh)
  3306. (insert (format "Importance: %s\n" new)))))
  3307. (defun message-insert-disposition-notification-to ()
  3308. "Request a disposition notification (return receipt) to this message.
  3309. Note that this should not be used in newsgroups."
  3310. (interactive)
  3311. (save-excursion
  3312. (save-restriction
  3313. (message-narrow-to-headers)
  3314. (message-remove-header "Disposition-Notification-To"))
  3315. (message-goto-eoh)
  3316. (insert (format "Disposition-Notification-To: %s\n"
  3317. (or (message-field-value "Reply-to")
  3318. (message-field-value "From")
  3319. (message-make-from))))))
  3320. (defun message-elide-region (b e)
  3321. "Elide the text in the region.
  3322. An ellipsis (from `message-elide-ellipsis') will be inserted where the
  3323. text was killed."
  3324. (interactive "r")
  3325. (let ((lines (count-lines b e))
  3326. (chars (- e b)))
  3327. (kill-region b e)
  3328. (insert (format-spec message-elide-ellipsis
  3329. `((?l . ,lines)
  3330. (?c . ,chars))))))
  3331. (defvar message-caesar-translation-table nil)
  3332. (defun message-caesar-region (b e &optional n)
  3333. "Caesar rotate region B to E by N, default 13, for decrypting netnews."
  3334. (interactive
  3335. (list
  3336. (min (point) (or (mark t) (point)))
  3337. (max (point) (or (mark t) (point)))
  3338. (when current-prefix-arg
  3339. (prefix-numeric-value current-prefix-arg))))
  3340. (setq n (if (numberp n) (mod n 26) 13)) ;canonize N
  3341. (unless (or (zerop n) ; no action needed for a rot of 0
  3342. (= b e)) ; no region to rotate
  3343. ;; We build the table, if necessary.
  3344. (when (or (not message-caesar-translation-table)
  3345. (/= (aref message-caesar-translation-table ?a) (+ ?a n)))
  3346. (setq message-caesar-translation-table
  3347. (message-make-caesar-translation-table n)))
  3348. (translate-region b e message-caesar-translation-table)))
  3349. (defun message-make-caesar-translation-table (n)
  3350. "Create a rot table with offset N."
  3351. (let ((i -1)
  3352. (table (make-string 256 0)))
  3353. (while (< (incf i) 256)
  3354. (aset table i i))
  3355. (concat
  3356. (substring table 0 ?A)
  3357. (substring table (+ ?A n) (+ ?A n (- 26 n)))
  3358. (substring table ?A (+ ?A n))
  3359. (substring table (+ ?A 26) ?a)
  3360. (substring table (+ ?a n) (+ ?a n (- 26 n)))
  3361. (substring table ?a (+ ?a n))
  3362. (substring table (+ ?a 26) 255))))
  3363. (defun message-caesar-buffer-body (&optional rotnum wide)
  3364. "Caesar rotate all letters in the current buffer by 13 places.
  3365. Used to encode/decode possibly offensive messages (commonly in rec.humor).
  3366. With prefix arg, specifies the number of places to rotate each letter forward.
  3367. Mail and USENET news headers are not rotated unless WIDE is non-nil."
  3368. (interactive (if current-prefix-arg
  3369. (list (prefix-numeric-value current-prefix-arg))
  3370. (list nil)))
  3371. (save-excursion
  3372. (save-restriction
  3373. (when (and (not wide) (message-goto-body))
  3374. (narrow-to-region (point) (point-max)))
  3375. (message-caesar-region (point-min) (point-max) rotnum))))
  3376. (defun message-pipe-buffer-body (program)
  3377. "Pipe the message body in the current buffer through PROGRAM."
  3378. (save-excursion
  3379. (save-restriction
  3380. (when (message-goto-body)
  3381. (narrow-to-region (point) (point-max)))
  3382. (shell-command-on-region
  3383. (point-min) (point-max) program nil t))))
  3384. (defun message-rename-buffer (&optional enter-string)
  3385. "Rename the *message* buffer to \"*message* RECIPIENT\".
  3386. If the function is run with a prefix, it will ask for a new buffer
  3387. name, rather than giving an automatic name."
  3388. (interactive "Pbuffer name: ")
  3389. (save-excursion
  3390. (save-restriction
  3391. (goto-char (point-min))
  3392. (narrow-to-region (point)
  3393. (search-forward mail-header-separator nil 'end))
  3394. (let* ((mail-to (or
  3395. (if (message-news-p) (message-fetch-field "Newsgroups")
  3396. (message-fetch-field "To"))
  3397. ""))
  3398. (mail-trimmed-to
  3399. (if (string-match "," mail-to)
  3400. (concat (substring mail-to 0 (match-beginning 0)) ", ...")
  3401. mail-to))
  3402. (name-default (concat "*message* " mail-trimmed-to))
  3403. (name (if enter-string
  3404. (read-string "New buffer name: " name-default)
  3405. name-default)))
  3406. (rename-buffer name t)))))
  3407. (defun message-fill-yanked-message (&optional justifyp)
  3408. "Fill the paragraphs of a message yanked into this one.
  3409. Numeric argument means justify as well."
  3410. (interactive "P")
  3411. (save-excursion
  3412. (goto-char (point-min))
  3413. (search-forward (concat "\n" mail-header-separator "\n") nil t)
  3414. (let ((fill-prefix message-yank-prefix))
  3415. (fill-individual-paragraphs (point) (point-max) justifyp))))
  3416. (defun message-indent-citation (&optional start end yank-only)
  3417. "Modify text just inserted from a message to be cited.
  3418. The inserted text should be the region.
  3419. When this function returns, the region is again around the modified text.
  3420. Normally, indent each nonblank line `message-indentation-spaces' spaces.
  3421. However, if `message-yank-prefix' is non-nil, insert that prefix on each line."
  3422. (unless start (setq start (point)))
  3423. (unless yank-only
  3424. ;; Remove unwanted headers.
  3425. (when message-ignored-cited-headers
  3426. (let (all-removed)
  3427. (save-restriction
  3428. (narrow-to-region
  3429. (goto-char start)
  3430. (if (search-forward "\n\n" nil t)
  3431. (1- (point))
  3432. (point)))
  3433. (message-remove-header message-ignored-cited-headers t)
  3434. (when (= (point-min) (point-max))
  3435. (setq all-removed t))
  3436. (goto-char (point-max)))
  3437. (if all-removed
  3438. (goto-char start)
  3439. (forward-line 1))))
  3440. ;; Delete blank lines at the start of the buffer.
  3441. (while (and (point-min)
  3442. (eolp)
  3443. (not (eobp)))
  3444. (message-delete-line))
  3445. ;; Delete blank lines at the end of the buffer.
  3446. (goto-char (point-max))
  3447. (unless (eq (preceding-char) ?\n)
  3448. (insert "\n"))
  3449. (while (and (zerop (forward-line -1))
  3450. (looking-at "$"))
  3451. (message-delete-line)))
  3452. ;; Do the indentation.
  3453. (if (null message-yank-prefix)
  3454. (indent-rigidly start (or end (mark t)) message-indentation-spaces)
  3455. (save-excursion
  3456. (goto-char start)
  3457. (while (< (point) (or end (mark t)))
  3458. (cond ((looking-at ">")
  3459. (insert message-yank-cited-prefix))
  3460. ((looking-at "^$")
  3461. (insert message-yank-empty-prefix))
  3462. (t
  3463. (insert message-yank-prefix)))
  3464. (forward-line 1))))
  3465. (goto-char start))
  3466. (defun message-remove-blank-cited-lines (&optional remove)
  3467. "Remove cited lines containing only blanks.
  3468. If REMOVE is non-nil, remove newlines, too.
  3469. To use this automatically, you may add this function to
  3470. `gnus-message-setup-hook'."
  3471. (interactive "P")
  3472. (let ((citexp
  3473. (concat
  3474. "^\\("
  3475. (when (boundp 'message-yank-cited-prefix)
  3476. (concat message-yank-cited-prefix "\\|"))
  3477. message-yank-prefix
  3478. "\\)+ *\n"
  3479. )))
  3480. (gnus-message 8 "removing `%s'" citexp)
  3481. (save-excursion
  3482. (message-goto-body)
  3483. (while (re-search-forward citexp nil t)
  3484. (replace-match (if remove "" "\n"))))))
  3485. (defun message--yank-original-internal (arg)
  3486. (let ((modified (buffer-modified-p))
  3487. body-text)
  3488. (when (and message-reply-buffer
  3489. message-cite-function)
  3490. (when (equal message-cite-reply-position 'above)
  3491. (save-excursion
  3492. (setq body-text
  3493. (buffer-substring (message-goto-body)
  3494. (point-max)))
  3495. (delete-region (message-goto-body) (point-max))))
  3496. (if (bufferp message-reply-buffer)
  3497. (delete-windows-on message-reply-buffer t))
  3498. (push-mark (save-excursion
  3499. (cond
  3500. ((bufferp message-reply-buffer)
  3501. (insert-buffer-substring message-reply-buffer))
  3502. ((and (consp message-reply-buffer)
  3503. (functionp (car message-reply-buffer)))
  3504. (apply (car message-reply-buffer)
  3505. (cdr message-reply-buffer))))
  3506. (unless (bolp)
  3507. (insert ?\n))
  3508. (point)))
  3509. (unless arg
  3510. (funcall message-cite-function)
  3511. (unless (eq (char-before (mark t)) ?\n)
  3512. (let ((pt (point)))
  3513. (goto-char (mark t))
  3514. (insert-before-markers ?\n)
  3515. (goto-char pt))))
  3516. (case message-cite-reply-position
  3517. (above
  3518. (message-goto-body)
  3519. (insert body-text)
  3520. (insert (if (bolp) "\n" "\n\n"))
  3521. (message-goto-body))
  3522. (below
  3523. (message-goto-signature)))
  3524. ;; Add a `message-setup-very-last-hook' here?
  3525. ;; Add `gnus-article-highlight-citation' here?
  3526. (unless modified
  3527. (setq message-checksum (message-checksum))))))
  3528. (defun message-yank-original (&optional arg)
  3529. "Insert the message being replied to, if any.
  3530. Puts point before the text and mark after.
  3531. Normally indents each nonblank line ARG spaces (default 3). However,
  3532. if `message-yank-prefix' is non-nil, insert that prefix on each line.
  3533. This function uses `message-cite-function' to do the actual citing.
  3534. Just \\[universal-argument] as argument means don't indent, insert no
  3535. prefix, and don't delete any headers."
  3536. (interactive "P")
  3537. ;; eval the let forms contained in message-cite-style
  3538. (eval
  3539. `(let ,(if (symbolp message-cite-style)
  3540. (symbol-value message-cite-style)
  3541. message-cite-style)
  3542. (message--yank-original-internal ',arg))))
  3543. (defun message-yank-buffer (buffer)
  3544. "Insert BUFFER into the current buffer and quote it."
  3545. (interactive "bYank buffer: ")
  3546. (let ((message-reply-buffer (get-buffer buffer)))
  3547. (save-window-excursion
  3548. (message-yank-original))))
  3549. (defun message-buffers ()
  3550. "Return a list of active message buffers."
  3551. (let (buffers)
  3552. (save-current-buffer
  3553. (dolist (buffer (buffer-list t))
  3554. (set-buffer buffer)
  3555. (when (and (derived-mode-p 'message-mode)
  3556. (null message-sent-message-via))
  3557. (push (buffer-name buffer) buffers))))
  3558. (nreverse buffers)))
  3559. (defun message-cite-original-1 (strip-signature)
  3560. "Cite an original message.
  3561. If STRIP-SIGNATURE is non-nil, strips off the signature from the
  3562. original message.
  3563. This function uses `mail-citation-hook' if that is non-nil."
  3564. (if (and (boundp 'mail-citation-hook)
  3565. mail-citation-hook)
  3566. (run-hooks 'mail-citation-hook)
  3567. (let* ((start (point))
  3568. (end (mark t))
  3569. (x-no-archive nil)
  3570. (functions
  3571. (when message-indent-citation-function
  3572. (if (listp message-indent-citation-function)
  3573. message-indent-citation-function
  3574. (list message-indent-citation-function))))
  3575. ;; This function may be called by `gnus-summary-yank-message' and
  3576. ;; may insert a different article from the original. So, we will
  3577. ;; modify the value of `message-reply-headers' with that article.
  3578. (message-reply-headers
  3579. (save-restriction
  3580. (narrow-to-region start end)
  3581. (message-narrow-to-head-1)
  3582. (setq x-no-archive (message-fetch-field "x-no-archive"))
  3583. (vector 0
  3584. (or (message-fetch-field "subject") "none")
  3585. (or (message-fetch-field "from") "nobody")
  3586. (message-fetch-field "date")
  3587. (message-fetch-field "message-id" t)
  3588. (message-fetch-field "references")
  3589. 0 0 ""))))
  3590. (mml-quote-region start end)
  3591. (when strip-signature
  3592. ;; Allow undoing.
  3593. (undo-boundary)
  3594. (goto-char end)
  3595. (when (re-search-backward message-signature-separator start t)
  3596. ;; Also peel off any blank lines before the signature.
  3597. (forward-line -1)
  3598. (while (looking-at "^[ \t]*$")
  3599. (forward-line -1))
  3600. (forward-line 1)
  3601. (delete-region (point) end)
  3602. (unless (search-backward "\n\n" start t)
  3603. ;; Insert a blank line if it is peeled off.
  3604. (insert "\n"))))
  3605. (goto-char start)
  3606. (mapc 'funcall functions)
  3607. (when message-citation-line-function
  3608. (unless (bolp)
  3609. (insert "\n"))
  3610. (funcall message-citation-line-function))
  3611. (when (and x-no-archive
  3612. (not message-cite-articles-with-x-no-archive)
  3613. (string-match "yes" x-no-archive))
  3614. (undo-boundary)
  3615. (delete-region (point) (mark t))
  3616. (insert "> [Quoted text removed due to X-No-Archive]\n")
  3617. (push-mark)
  3618. (forward-line -1)))))
  3619. (defun message-cite-original ()
  3620. "Cite function in the standard Message manner."
  3621. (message-cite-original-1 nil))
  3622. (autoload 'format-spec "format-spec")
  3623. (autoload 'gnus-date-get-time "gnus-util")
  3624. (defun message-insert-formatted-citation-line (&optional from date tz)
  3625. "Function that inserts a formatted citation line.
  3626. The optional FROM, and DATE are strings containing the contents of
  3627. the From header and the Date header respectively. The optional TZ
  3628. is a number of seconds, overrides the time zone of DATE.
  3629. See `message-citation-line-format'."
  3630. ;; The optional args are for testing/debugging. They will disappear later.
  3631. ;; Example:
  3632. ;; (with-temp-buffer
  3633. ;; (message-insert-formatted-citation-line
  3634. ;; "John Doe <john.doe@example.invalid>"
  3635. ;; (message-make-date))
  3636. ;; (buffer-string))
  3637. (when (or message-reply-headers (and from date))
  3638. (unless from
  3639. (setq from (mail-header-from message-reply-headers)))
  3640. (let* ((data (condition-case ()
  3641. (funcall (if (boundp 'gnus-extract-address-components)
  3642. gnus-extract-address-components
  3643. 'mail-extract-address-components)
  3644. from)
  3645. (error nil)))
  3646. (name (car data))
  3647. (fname name)
  3648. (lname name)
  3649. (net (car (cdr data)))
  3650. (name-or-net (or (car data)
  3651. (car (cdr data)) from))
  3652. (time
  3653. (when (string-match "%[^fnNFL]" message-citation-line-format)
  3654. (cond ((numberp (car-safe date)) date) ;; backward compatibility
  3655. (date (gnus-date-get-time date))
  3656. (t
  3657. (gnus-date-get-time
  3658. (setq date (mail-header-date message-reply-headers)))))))
  3659. (tz (or tz
  3660. (when (stringp date)
  3661. (nth 8 (parse-time-string date)))))
  3662. (flist
  3663. (let ((i ?A) lst)
  3664. (when (stringp name)
  3665. ;; Guess first name and last name:
  3666. (let* ((names (delq
  3667. nil
  3668. (mapcar
  3669. (lambda (x)
  3670. (if (string-match "\\`\\(\\w\\|[-.]\\)+\\'"
  3671. x)
  3672. x
  3673. nil))
  3674. (split-string name "[ \t]+"))))
  3675. (count (length names)))
  3676. (cond ((= count 1)
  3677. (setq fname (car names)
  3678. lname ""))
  3679. ((or (= count 2) (= count 3))
  3680. (setq fname (car names)
  3681. lname (mapconcat 'identity (cdr names) " ")))
  3682. ((> count 3)
  3683. (setq fname (mapconcat 'identity
  3684. (butlast names (- count 2))
  3685. " ")
  3686. lname (mapconcat 'identity
  3687. (nthcdr 2 names)
  3688. " "))))
  3689. (when (string-match "\\(.*\\),\\'" fname)
  3690. (let ((newlname (match-string 1 fname)))
  3691. (setq fname lname lname newlname)))))
  3692. ;; The following letters are not used in `format-time-string':
  3693. (push ?E lst) (push "<E>" lst)
  3694. (push ?F lst) (push (or fname name-or-net) lst)
  3695. ;; We might want to use "" instead of "<X>" later.
  3696. (push ?J lst) (push "<J>" lst)
  3697. (push ?K lst) (push "<K>" lst)
  3698. (push ?L lst) (push lname lst)
  3699. (push ?N lst) (push name-or-net lst)
  3700. (push ?O lst) (push "<O>" lst)
  3701. (push ?P lst) (push "<P>" lst)
  3702. (push ?Q lst) (push "<Q>" lst)
  3703. (push ?f lst) (push from lst)
  3704. (push ?i lst) (push "<i>" lst)
  3705. (push ?n lst) (push net lst)
  3706. (push ?o lst) (push "<o>" lst)
  3707. (push ?q lst) (push "<q>" lst)
  3708. (push ?t lst) (push "<t>" lst)
  3709. (push ?v lst) (push "<v>" lst)
  3710. ;; Delegate the rest to `format-time-string':
  3711. (while (<= i ?z)
  3712. (when (and (not (memq i lst))
  3713. ;; Skip (Z,a)
  3714. (or (<= i ?Z)
  3715. (>= i ?a)))
  3716. (push i lst)
  3717. (push (condition-case nil
  3718. (gmm-format-time-string (format "%%%c" i) time tz)
  3719. (error (format ">%c<" i)))
  3720. lst))
  3721. (setq i (1+ i)))
  3722. (reverse lst)))
  3723. (spec (apply 'format-spec-make flist)))
  3724. (insert (format-spec message-citation-line-format spec)))
  3725. (newline)))
  3726. (defun message-cite-original-without-signature ()
  3727. "Cite function in the standard Message manner.
  3728. This function strips off the signature from the original message."
  3729. (message-cite-original-1 t))
  3730. (defun message-insert-citation-line ()
  3731. "Insert a simple citation line."
  3732. (when message-reply-headers
  3733. (insert (mail-header-from message-reply-headers) " writes:")
  3734. (newline)
  3735. (newline)))
  3736. (defun message-position-on-field (header &rest afters)
  3737. (let ((case-fold-search t))
  3738. (save-restriction
  3739. (narrow-to-region
  3740. (goto-char (point-min))
  3741. (progn
  3742. (re-search-forward
  3743. (concat "^" (regexp-quote mail-header-separator) "$"))
  3744. (match-beginning 0)))
  3745. (goto-char (point-min))
  3746. (if (re-search-forward (concat "^" (regexp-quote header) ":") nil t)
  3747. (progn
  3748. (re-search-forward "^[^ \t]" nil 'move)
  3749. (beginning-of-line)
  3750. (skip-chars-backward "\n")
  3751. t)
  3752. (while (and afters
  3753. (not (re-search-forward
  3754. (concat "^" (regexp-quote (car afters)) ":")
  3755. nil t)))
  3756. (pop afters))
  3757. (when afters
  3758. (re-search-forward "^[^ \t]" nil 'move)
  3759. (beginning-of-line))
  3760. (insert header ": \n")
  3761. (forward-char -1)
  3762. nil))))
  3763. ;;;
  3764. ;;; Sending messages
  3765. ;;;
  3766. (defun message-send-and-exit (&optional arg)
  3767. "Send message like `message-send', then, if no errors, exit from mail buffer.
  3768. The usage of ARG is defined by the instance that called Message.
  3769. It should typically alter the sending method in some way or other."
  3770. (interactive "P")
  3771. (let ((buf (current-buffer))
  3772. (actions message-exit-actions))
  3773. (when (and (message-send arg)
  3774. (buffer-name buf))
  3775. (message-bury buf)
  3776. (if message-kill-buffer-on-exit
  3777. (kill-buffer buf))
  3778. (message-do-actions actions)
  3779. t)))
  3780. (defun message-dont-send ()
  3781. "Don't send the message you have been editing.
  3782. Instead, just auto-save the buffer and then bury it."
  3783. (interactive)
  3784. (set-buffer-modified-p t)
  3785. (save-buffer)
  3786. (let ((actions message-postpone-actions))
  3787. (message-bury (current-buffer))
  3788. (message-do-actions actions)))
  3789. (defun message-kill-buffer ()
  3790. "Kill the current buffer."
  3791. (interactive)
  3792. (when (or (not (buffer-modified-p))
  3793. (not message-kill-buffer-query)
  3794. (yes-or-no-p "Message modified; kill anyway? "))
  3795. (let ((actions message-kill-actions)
  3796. (draft-article message-draft-article)
  3797. (auto-save-file-name buffer-auto-save-file-name)
  3798. (file-name buffer-file-name)
  3799. (modified (buffer-modified-p)))
  3800. (setq buffer-file-name nil)
  3801. (kill-buffer (current-buffer))
  3802. (when (and (or (and auto-save-file-name
  3803. (file-exists-p auto-save-file-name))
  3804. (and file-name
  3805. (file-exists-p file-name)))
  3806. (progn
  3807. ;; If the message buffer has lived in a dedicated window,
  3808. ;; `kill-buffer' has killed the frame. Thus the
  3809. ;; `yes-or-no-p' may show up in a lowered frame. Make sure
  3810. ;; that the user can see the question by raising the
  3811. ;; current frame:
  3812. (raise-frame)
  3813. (yes-or-no-p (format "Remove the backup file%s? "
  3814. (if modified " too" "")))))
  3815. (ignore-errors
  3816. (delete-file auto-save-file-name))
  3817. (let ((message-draft-article draft-article))
  3818. (message-disassociate-draft)))
  3819. (message-do-actions actions))))
  3820. (defun message-bury (buffer)
  3821. "Bury this mail BUFFER."
  3822. ;; Note that this is not quite the same as (bury-buffer buffer),
  3823. ;; since bury-buffer does extra stuff with a nil argument.
  3824. ;; Eg http://lists.gnu.org/archive/html/emacs-devel/2014-01/msg00539.html
  3825. (with-current-buffer buffer (bury-buffer))
  3826. (if message-return-action
  3827. (apply (car message-return-action) (cdr message-return-action))))
  3828. (defun message-send (&optional arg)
  3829. "Send the message in the current buffer.
  3830. If `message-interactive' is non-nil, wait for success indication or
  3831. error messages, and inform user.
  3832. Otherwise any failure is reported in a message back to the user from
  3833. the mailer.
  3834. The usage of ARG is defined by the instance that called Message.
  3835. It should typically alter the sending method in some way or other."
  3836. (interactive "P")
  3837. ;; Make it possible to undo the coming changes.
  3838. (undo-boundary)
  3839. (let ((inhibit-read-only t))
  3840. (put-text-property (point-min) (point-max) 'read-only nil))
  3841. (message-fix-before-sending)
  3842. (run-hooks 'message-send-hook)
  3843. (when message-confirm-send
  3844. (or (y-or-n-p "Send message? ")
  3845. (keyboard-quit)))
  3846. (message message-sending-message)
  3847. (let ((alist message-send-method-alist)
  3848. (success t)
  3849. elem sent dont-barf-on-no-method
  3850. (message-options message-options))
  3851. (message-options-set-recipient)
  3852. (while (and success
  3853. (setq elem (pop alist)))
  3854. (when (funcall (cadr elem))
  3855. (when (and (or (not (memq (car elem)
  3856. message-sent-message-via))
  3857. (message-fetch-field "supersedes")
  3858. (if (or (message-gnksa-enable-p 'multiple-copies)
  3859. (not (eq (car elem) 'news)))
  3860. (y-or-n-p
  3861. (format
  3862. "Already sent message via %s; resend? "
  3863. (car elem)))
  3864. (error "Denied posting -- multiple copies")))
  3865. (setq success (funcall (caddr elem) arg)))
  3866. (setq sent t))))
  3867. (unless (or sent
  3868. (not success)
  3869. (let ((fcc (message-fetch-field "Fcc"))
  3870. (gcc (message-fetch-field "Gcc")))
  3871. (when (or fcc gcc)
  3872. (or (eq message-allow-no-recipients 'always)
  3873. (and (not (eq message-allow-no-recipients 'never))
  3874. (setq dont-barf-on-no-method
  3875. (gnus-y-or-n-p
  3876. (format "No receiver, perform %s anyway? "
  3877. (cond ((and fcc gcc) "Fcc and Gcc")
  3878. (fcc "Fcc")
  3879. (t "Gcc"))))))))))
  3880. (error "No methods specified to send by"))
  3881. (when (or dont-barf-on-no-method
  3882. (and success sent))
  3883. (message-do-fcc)
  3884. (save-excursion
  3885. (run-hooks 'message-sent-hook))
  3886. (message "Sending...done")
  3887. ;; Do ecomplete address snarfing.
  3888. (when (and (message-mail-alias-type-p 'ecomplete)
  3889. (not message-inhibit-ecomplete))
  3890. (message-put-addresses-in-ecomplete))
  3891. ;; Mark the buffer as unmodified and delete auto-save.
  3892. (set-buffer-modified-p nil)
  3893. (delete-auto-save-file-if-necessary t)
  3894. (message-disassociate-draft)
  3895. ;; Delete other mail buffers and stuff.
  3896. (message-do-send-housekeeping)
  3897. (message-do-actions message-send-actions)
  3898. ;; Return success.
  3899. t)))
  3900. (defun message-send-via-mail (arg)
  3901. "Send the current message via mail."
  3902. (message-send-mail arg))
  3903. (defun message-send-via-news (arg)
  3904. "Send the current message via news."
  3905. (funcall message-send-news-function arg))
  3906. (defmacro message-check (type &rest forms)
  3907. "Eval FORMS if TYPE is to be checked."
  3908. `(or (message-check-element ,type)
  3909. (save-excursion
  3910. ,@forms)))
  3911. (put 'message-check 'lisp-indent-function 1)
  3912. (put 'message-check 'edebug-form-spec '(form body))
  3913. (defun message-text-with-property (prop &optional start end reverse)
  3914. "Return a list of start and end positions where the text has PROP.
  3915. START and END bound the search, they default to `point-min' and
  3916. `point-max' respectively. If REVERSE is non-nil, find text which does
  3917. not have PROP."
  3918. (unless start
  3919. (setq start (point-min)))
  3920. (unless end
  3921. (setq end (point-max)))
  3922. (let (next regions)
  3923. (if reverse
  3924. (while (and start
  3925. (setq start (text-property-any start end prop nil)))
  3926. (setq next (next-single-property-change start prop nil end))
  3927. (push (cons start (or next end)) regions)
  3928. (setq start next))
  3929. (while (and start
  3930. (or (get-text-property start prop)
  3931. (and (setq start (next-single-property-change
  3932. start prop nil end))
  3933. (get-text-property start prop))))
  3934. (setq next (text-property-any start end prop nil))
  3935. (push (cons start (or next end)) regions)
  3936. (setq start next)))
  3937. (nreverse regions)))
  3938. (defcustom message-bogus-addresses
  3939. '("noreply" "nospam" "invalid" "@@" "[^[:ascii:]].*@" "[ \t]")
  3940. "List of regexps of potentially bogus mail addresses.
  3941. See `message-check-recipients' how to setup checking.
  3942. This list should make it possible to catch typos or warn about
  3943. spam-trap addresses. It doesn't aim to verify strict RFC
  3944. conformance."
  3945. :version "23.1" ;; No Gnus
  3946. :group 'message-headers
  3947. :type '(choice
  3948. (const :tag "None" nil)
  3949. (list
  3950. (set :inline t
  3951. (const "noreply")
  3952. (const "nospam")
  3953. (const "invalid")
  3954. (const :tag "duplicate @" "@@")
  3955. (const :tag "non-ascii local part" "[^[:ascii:]].*@")
  3956. ;; Already caught by `message-valid-fqdn-regexp'
  3957. ;; (const :tag "`_' in domain part" "@.*_")
  3958. (const :tag "whitespace" "[ \t]"))
  3959. (repeat :inline t
  3960. :tag "Other"
  3961. (regexp)))))
  3962. (defun message-fix-before-sending ()
  3963. "Do various things to make the message nice before sending it."
  3964. ;; Make sure there's a newline at the end of the message.
  3965. (goto-char (point-max))
  3966. (unless (bolp)
  3967. (insert "\n"))
  3968. ;; Make the hidden headers visible.
  3969. (widen)
  3970. ;; Sort headers before sending the message.
  3971. (message-sort-headers)
  3972. ;; Make invisible text visible.
  3973. ;; It doesn't seem as if this is useful, since the invisible property
  3974. ;; is clobbered by an after-change hook anyhow.
  3975. (message-check 'invisible-text
  3976. (let ((regions (message-text-with-property 'invisible))
  3977. from to)
  3978. (when regions
  3979. (while regions
  3980. (setq from (caar regions)
  3981. to (cdar regions)
  3982. regions (cdr regions))
  3983. (put-text-property from to 'invisible nil)
  3984. (overlay-put (make-overlay from to) 'face 'highlight))
  3985. (unless (yes-or-no-p
  3986. "Invisible text found and made visible; continue sending? ")
  3987. (error "Invisible text found and made visible")))))
  3988. (message-check 'illegible-text
  3989. (let (char found choice nul-chars)
  3990. (message-goto-body)
  3991. (setq nul-chars (save-excursion
  3992. (search-forward "\000" nil t)))
  3993. (while (progn
  3994. (skip-chars-forward mm-7bit-chars)
  3995. (when (get-text-property (point) 'no-illegible-text)
  3996. ;; There is a signed or encrypted raw message part
  3997. ;; that is considered to be safe.
  3998. (goto-char (or (next-single-property-change
  3999. (point) 'no-illegible-text)
  4000. (point-max))))
  4001. (setq char (char-after)))
  4002. (when (or (< (mm-char-int char) 128)
  4003. (and (mm-multibyte-p)
  4004. (memq (char-charset char)
  4005. '(eight-bit-control eight-bit-graphic
  4006. ;; Emacs 23, Bug#1770:
  4007. eight-bit
  4008. control-1))
  4009. (not (get-text-property
  4010. (point) 'untranslated-utf-8))))
  4011. (overlay-put (make-overlay (point) (1+ (point))) 'face 'highlight)
  4012. (setq found t))
  4013. (forward-char))
  4014. (when found
  4015. (setq choice
  4016. (gnus-multiple-choice
  4017. (if nul-chars
  4018. "NUL characters found, which may cause problems. Continue sending?"
  4019. "Non-printable characters found. Continue sending?")
  4020. `((?d "Remove non-printable characters and send")
  4021. (?r ,(format
  4022. "Replace non-printable characters with \"%s\" and send"
  4023. message-replacement-char))
  4024. (?s "Send as is without removing anything")
  4025. (?e "Continue editing"))))
  4026. (if (eq choice ?e)
  4027. (error "Non-printable characters"))
  4028. (message-goto-body)
  4029. (skip-chars-forward mm-7bit-chars)
  4030. (while (not (eobp))
  4031. (when (let ((char (char-after)))
  4032. (or (< (mm-char-int char) 128)
  4033. (and (mm-multibyte-p)
  4034. ;; FIXME: Wrong for Emacs 23 (unicode) and for
  4035. ;; things like undecodable utf-8 (in Emacs 21?).
  4036. ;; Should at least use find-coding-systems-region.
  4037. ;; -- fx
  4038. (memq (char-charset char)
  4039. '(eight-bit-control eight-bit-graphic
  4040. ;; Emacs 23, Bug#1770:
  4041. eight-bit
  4042. control-1))
  4043. (not (get-text-property
  4044. (point) 'untranslated-utf-8)))))
  4045. (if (eq choice ?i)
  4046. (message-kill-all-overlays)
  4047. (delete-char 1)
  4048. (when (eq choice ?r)
  4049. (insert message-replacement-char))))
  4050. (forward-char)
  4051. (skip-chars-forward mm-7bit-chars)))))
  4052. (message-check 'bogus-recipient
  4053. ;; Warn before sending a mail to an invalid address.
  4054. (message-check-recipients)))
  4055. (defun message-bogus-recipient-p (recipients)
  4056. "Check if a mail address in RECIPIENTS looks bogus.
  4057. RECIPIENTS is a mail header. Return a list of potentially bogus
  4058. addresses. If none is found, return nil.
  4059. An address might be bogus if the domain part is not fully
  4060. qualified, see `message-valid-fqdn-regexp', or if there's a
  4061. matching entry in `message-bogus-addresses'."
  4062. ;; FIXME: How about "foo@subdomain", when the MTA adds ".domain.tld"?
  4063. (let (found)
  4064. (mapc (lambda (address)
  4065. (setq address (or (cadr address) ""))
  4066. (when
  4067. (or (string= "" address)
  4068. (not
  4069. (or
  4070. (not (string-match "@" address))
  4071. (string-match
  4072. (concat ".@.*\\("
  4073. message-valid-fqdn-regexp "\\)\\'") address)))
  4074. (and message-bogus-addresses
  4075. (let ((re
  4076. (if (listp message-bogus-addresses)
  4077. (mapconcat 'identity
  4078. message-bogus-addresses
  4079. "\\|")
  4080. message-bogus-addresses)))
  4081. (string-match re address))))
  4082. (push address found)))
  4083. ;;
  4084. (mail-extract-address-components recipients t))
  4085. found))
  4086. (defun message-check-recipients ()
  4087. "Warn before composing or sending a mail to an invalid address.
  4088. This function could be useful in `message-setup-hook'."
  4089. (interactive)
  4090. (save-restriction
  4091. (message-narrow-to-headers)
  4092. (dolist (hdr '("To" "Cc" "Bcc"))
  4093. (let ((addr (message-fetch-field hdr)))
  4094. (when (stringp addr)
  4095. (dolist (bog (message-bogus-recipient-p addr))
  4096. (and bog
  4097. (not (y-or-n-p
  4098. (format
  4099. "Address `%s'%s might be bogus. Continue? "
  4100. bog
  4101. ;; If the encoded version of the email address
  4102. ;; is different from the unencoded version,
  4103. ;; then we likely have invisible characters or
  4104. ;; the like. Display the encoded version,
  4105. ;; too.
  4106. (let ((encoded (rfc2047-encode-string bog)))
  4107. (if (string= encoded bog)
  4108. ""
  4109. (format " (%s)" encoded))))))
  4110. (error "Bogus address"))))))))
  4111. (custom-add-option 'message-setup-hook 'message-check-recipients)
  4112. (defun message-add-action (action &rest types)
  4113. "Add ACTION to be performed when doing an exit of type TYPES."
  4114. (while types
  4115. (add-to-list (intern (format "message-%s-actions" (pop types)))
  4116. action)))
  4117. (defun message-delete-action (action &rest types)
  4118. "Delete ACTION from lists of actions performed when doing an exit of type TYPES."
  4119. (let (var)
  4120. (while types
  4121. (set (setq var (intern (format "message-%s-actions" (pop types))))
  4122. (delq action (symbol-value var))))))
  4123. (defun message-do-actions (actions)
  4124. "Perform all actions in ACTIONS."
  4125. ;; Now perform actions on successful sending.
  4126. (dolist (action actions)
  4127. (ignore-errors
  4128. (cond
  4129. ;; A simple function.
  4130. ((functionp action)
  4131. (funcall action))
  4132. ;; Something to be evalled.
  4133. (t
  4134. (eval action))))))
  4135. (defun message-send-mail-partially ()
  4136. "Send mail as message/partial."
  4137. ;; replace the header delimiter with a blank line
  4138. (goto-char (point-min))
  4139. (re-search-forward
  4140. (concat "^" (regexp-quote mail-header-separator) "\n"))
  4141. (replace-match "\n")
  4142. (run-hooks 'message-send-mail-hook)
  4143. (let ((p (goto-char (point-min)))
  4144. (tembuf (message-generate-new-buffer-clone-locals " message temp"))
  4145. (curbuf (current-buffer))
  4146. (id (message-make-message-id)) (n 1)
  4147. plist total header)
  4148. (while (not (eobp))
  4149. (if (< (point-max) (+ p message-send-mail-partially-limit))
  4150. (goto-char (point-max))
  4151. (goto-char (+ p message-send-mail-partially-limit))
  4152. (beginning-of-line)
  4153. (if (<= (point) p) (forward-line 1))) ;; In case of bad message.
  4154. (push p plist)
  4155. (setq p (point)))
  4156. (setq total (length plist))
  4157. (push (point-max) plist)
  4158. (setq plist (nreverse plist))
  4159. (unwind-protect
  4160. (save-excursion
  4161. (setq p (pop plist))
  4162. (while plist
  4163. (set-buffer curbuf)
  4164. (copy-to-buffer tembuf p (car plist))
  4165. (set-buffer tembuf)
  4166. (goto-char (point-min))
  4167. (if header
  4168. (progn
  4169. (goto-char (point-min))
  4170. (narrow-to-region (point) (point))
  4171. (insert header))
  4172. (message-goto-eoh)
  4173. (setq header (buffer-substring (point-min) (point)))
  4174. (goto-char (point-min))
  4175. (narrow-to-region (point) (point))
  4176. (insert header)
  4177. (message-remove-header "Mime-Version")
  4178. (message-remove-header "Content-Type")
  4179. (message-remove-header "Content-Transfer-Encoding")
  4180. (message-remove-header "Message-ID")
  4181. (message-remove-header "Lines")
  4182. (goto-char (point-max))
  4183. (insert "Mime-Version: 1.0\n")
  4184. (setq header (buffer-string)))
  4185. (goto-char (point-max))
  4186. (insert (format "Content-Type: message/partial; id=\"%s\"; number=%d; total=%d\n\n"
  4187. id n total))
  4188. (forward-char -1)
  4189. (let ((mail-header-separator ""))
  4190. (when (memq 'Message-ID message-required-mail-headers)
  4191. (insert "Message-ID: " (message-make-message-id) "\n"))
  4192. (when (memq 'Lines message-required-mail-headers)
  4193. (insert "Lines: " (message-make-lines) "\n"))
  4194. (message-goto-subject)
  4195. (end-of-line)
  4196. (insert (format " (%d/%d)" n total))
  4197. (widen)
  4198. (if message-send-mail-real-function
  4199. (funcall message-send-mail-real-function)
  4200. (message-multi-smtp-send-mail)))
  4201. (setq n (+ n 1))
  4202. (setq p (pop plist))
  4203. (erase-buffer)))
  4204. (kill-buffer tembuf))))
  4205. (declare-function hashcash-wait-async "hashcash" (&optional buffer))
  4206. (defun message-send-mail (&optional arg)
  4207. (require 'mail-utils)
  4208. (let* ((tembuf (message-generate-new-buffer-clone-locals " message temp"))
  4209. (case-fold-search nil)
  4210. (news (message-news-p))
  4211. (mailbuf (current-buffer))
  4212. (message-this-is-mail t)
  4213. ;; gnus-setup-posting-charset is autoloaded in mml.el (FIXME
  4214. ;; maybe it should not be), which this file requires. Hence
  4215. ;; the fboundp test is always true. Loading it from gnus-msg
  4216. ;; loads many Gnus files (Bug#5642). If
  4217. ;; gnus-group-posting-charset-alist hasn't been customized,
  4218. ;; this is just going to return nil anyway. FIXME it would
  4219. ;; be good to improve this further, because even if g-g-p-c-a
  4220. ;; has been customized, that is likely to just be for news.
  4221. ;; Eg either move the definition from gnus-msg, or separate out
  4222. ;; the mail and news parts.
  4223. (message-posting-charset
  4224. (if (and (fboundp 'gnus-setup-posting-charset)
  4225. (boundp 'gnus-group-posting-charset-alist))
  4226. (gnus-setup-posting-charset nil)
  4227. message-posting-charset))
  4228. (headers message-required-mail-headers)
  4229. options)
  4230. (when (and message-generate-hashcash
  4231. (not (eq message-generate-hashcash 'opportunistic)))
  4232. (message "Generating hashcash...")
  4233. (require 'hashcash)
  4234. ;; Wait for calculations already started to finish...
  4235. (hashcash-wait-async)
  4236. ;; ...and do calculations not already done. mail-add-payment
  4237. ;; will leave existing X-Hashcash headers alone.
  4238. (mail-add-payment)
  4239. (message "Generating hashcash...done"))
  4240. (save-restriction
  4241. (message-narrow-to-headers)
  4242. ;; Generate the Mail-Followup-To header if the header is not there...
  4243. (if (and (message-subscribed-p)
  4244. (not (mail-fetch-field "mail-followup-to")))
  4245. (setq headers
  4246. (cons
  4247. (cons "Mail-Followup-To" (message-make-mail-followup-to))
  4248. message-required-mail-headers))
  4249. ;; otherwise, delete the MFT header if the field is empty
  4250. (when (equal "" (mail-fetch-field "mail-followup-to"))
  4251. (message-remove-header "^Mail-Followup-To:")))
  4252. ;; Insert some headers.
  4253. (let ((message-deletable-headers
  4254. (if news nil message-deletable-headers)))
  4255. (message-generate-headers headers))
  4256. ;; Check continuation headers.
  4257. (message-check 'continuation-headers
  4258. (goto-char (point-min))
  4259. (while (re-search-forward "^[^ \t\n][^ \t\n:]*[ \t\n]" nil t)
  4260. (goto-char (match-beginning 0))
  4261. (if (y-or-n-p "Fix continuation lines? ")
  4262. (insert " ")
  4263. (forward-line 1)
  4264. (unless (y-or-n-p "Send anyway? ")
  4265. (error "Failed to send the message")))))
  4266. ;; Let the user do all of the above.
  4267. (run-hooks 'message-header-hook))
  4268. (setq options message-options)
  4269. (unwind-protect
  4270. (with-current-buffer tembuf
  4271. (erase-buffer)
  4272. (setq message-options options)
  4273. ;; Avoid copying text props (except hard newlines).
  4274. (insert (with-current-buffer mailbuf
  4275. (mml-buffer-substring-no-properties-except-hard-newlines
  4276. (point-min) (point-max))))
  4277. ;; Remove some headers.
  4278. (message-encode-message-body)
  4279. (save-restriction
  4280. (message-narrow-to-headers)
  4281. ;; We (re)generate the Lines header.
  4282. (when (memq 'Lines message-required-mail-headers)
  4283. (message-generate-headers '(Lines)))
  4284. ;; Remove some headers.
  4285. (message-remove-header message-ignored-mail-headers t)
  4286. (let ((mail-parse-charset message-default-charset))
  4287. (mail-encode-encoded-word-buffer)))
  4288. (goto-char (point-max))
  4289. ;; require one newline at the end.
  4290. (or (= (preceding-char) ?\n)
  4291. (insert ?\n))
  4292. (message-cleanup-headers)
  4293. ;; FIXME: we're inserting the courtesy copy after encoding.
  4294. ;; This is wrong if the courtesy copy string contains
  4295. ;; non-ASCII characters. -- jh
  4296. (when
  4297. (save-restriction
  4298. (message-narrow-to-headers)
  4299. (and news
  4300. (not (message-fetch-field "List-Post"))
  4301. (not (message-fetch-field "List-ID"))
  4302. (or (message-fetch-field "cc")
  4303. (message-fetch-field "bcc")
  4304. (message-fetch-field "to"))
  4305. (let ((content-type (message-fetch-field
  4306. "content-type")))
  4307. (and
  4308. (or
  4309. (not content-type)
  4310. (string= "text/plain"
  4311. (car
  4312. (mail-header-parse-content-type
  4313. content-type))))
  4314. (not
  4315. (string= "base64"
  4316. (message-fetch-field
  4317. "content-transfer-encoding")))))))
  4318. (message-insert-courtesy-copy
  4319. (with-current-buffer mailbuf
  4320. message-courtesy-message)))
  4321. ;; Let's make sure we encoded all the body.
  4322. (assert (save-excursion
  4323. (goto-char (point-min))
  4324. (not (re-search-forward "[^\000-\377]" nil t))))
  4325. (mm-disable-multibyte)
  4326. (if (or (not message-send-mail-partially-limit)
  4327. (< (buffer-size) message-send-mail-partially-limit)
  4328. (not (message-y-or-n-p
  4329. "The message size is too large, split? "
  4330. t
  4331. "\
  4332. The message size, "
  4333. (/ (buffer-size) 1000) "KB, is too large.
  4334. Some mail gateways (MTA's) bounce large messages. To avoid the
  4335. problem, answer `y', and the message will be split into several
  4336. smaller pieces, the size of each is about "
  4337. (/ message-send-mail-partially-limit 1000)
  4338. "KB except the last
  4339. one.
  4340. However, some mail readers (MUA's) can't read split messages, i.e.,
  4341. mails in message/partially format. Answer `n', and the message will be
  4342. sent in one piece.
  4343. The size limit is controlled by `message-send-mail-partially-limit'.
  4344. If you always want Gnus to send messages in one piece, set
  4345. `message-send-mail-partially-limit' to nil.
  4346. ")))
  4347. (progn
  4348. (message "Sending via mail...")
  4349. (if message-send-mail-real-function
  4350. (funcall message-send-mail-real-function)
  4351. (message-multi-smtp-send-mail)))
  4352. (message-send-mail-partially))
  4353. (setq options message-options))
  4354. (kill-buffer tembuf))
  4355. (set-buffer mailbuf)
  4356. (setq message-options options)
  4357. (push 'mail message-sent-message-via)))
  4358. (defvar sendmail-program)
  4359. (defvar smtpmail-smtp-user)
  4360. (defun message-multi-smtp-send-mail ()
  4361. "Send the current buffer to `message-send-mail-function'.
  4362. Or, if there's a header that specifies a different method, use
  4363. that instead."
  4364. (let ((method (message-field-value "X-Message-SMTP-Method")))
  4365. (if (not method)
  4366. (funcall message-send-mail-function)
  4367. (message-remove-header "X-Message-SMTP-Method")
  4368. (setq method (split-string method))
  4369. (cond
  4370. ((equal (car method) "sendmail")
  4371. (message-send-mail-with-sendmail))
  4372. ((equal (car method) "smtp")
  4373. (require 'smtpmail)
  4374. (let ((smtpmail-smtp-server (nth 1 method))
  4375. (smtpmail-smtp-service (nth 2 method))
  4376. (smtpmail-smtp-user (or (nth 3 method) smtpmail-smtp-user)))
  4377. (message-smtpmail-send-it)))
  4378. (t
  4379. (error "Unknown method %s" method))))))
  4380. (defun message-send-mail-with-sendmail ()
  4381. "Send off the prepared buffer with sendmail."
  4382. (require 'sendmail)
  4383. (let ((errbuf (if message-interactive
  4384. (message-generate-new-buffer-clone-locals
  4385. " sendmail errors")
  4386. 0))
  4387. resend-to-addresses delimline)
  4388. (unwind-protect
  4389. (progn
  4390. (let ((case-fold-search t))
  4391. (save-restriction
  4392. (message-narrow-to-headers)
  4393. (setq resend-to-addresses (message-fetch-field "resent-to")))
  4394. ;; Change header-delimiter to be what sendmail expects.
  4395. (goto-char (point-min))
  4396. (re-search-forward
  4397. (concat "^" (regexp-quote mail-header-separator) "\n"))
  4398. (replace-match "\n")
  4399. (backward-char 1)
  4400. (setq delimline (point-marker))
  4401. (run-hooks 'message-send-mail-hook)
  4402. ;; Insert an extra newline if we need it to work around
  4403. ;; Sun's bug that swallows newlines.
  4404. (goto-char (1+ delimline))
  4405. (when (eval message-mailer-swallows-blank-line)
  4406. (newline))
  4407. (when message-interactive
  4408. (with-current-buffer errbuf
  4409. (erase-buffer))))
  4410. (let* ((default-directory "/")
  4411. (coding-system-for-write message-send-coding-system)
  4412. (cpr (apply
  4413. 'call-process-region
  4414. (append
  4415. (list (point-min) (point-max) sendmail-program
  4416. nil errbuf nil "-oi")
  4417. message-sendmail-extra-arguments
  4418. ;; Always specify who from,
  4419. ;; since some systems have broken sendmails.
  4420. ;; But some systems are more broken with -f, so
  4421. ;; we'll let users override this.
  4422. (and (null message-sendmail-f-is-evil)
  4423. (list "-f" (message-sendmail-envelope-from)))
  4424. ;; These mean "report errors by mail"
  4425. ;; and "deliver in background".
  4426. (if (null message-interactive) '("-oem" "-odb"))
  4427. ;; Get the addresses from the message
  4428. ;; unless this is a resend.
  4429. ;; We must not do that for a resend
  4430. ;; because we would find the original addresses.
  4431. ;; For a resend, include the specific addresses.
  4432. (if resend-to-addresses
  4433. (list resend-to-addresses)
  4434. '("-t"))))))
  4435. (unless (or (null cpr) (and (numberp cpr) (zerop cpr)))
  4436. (when errbuf
  4437. (pop-to-buffer errbuf)
  4438. (setq errbuf nil))
  4439. (error "Sending...failed with exit value %d" cpr)))
  4440. (when message-interactive
  4441. (with-current-buffer errbuf
  4442. (goto-char (point-min))
  4443. (while (re-search-forward "\n+ *" nil t)
  4444. (replace-match "; "))
  4445. (if (not (zerop (buffer-size)))
  4446. (error "Sending...failed to %s"
  4447. (buffer-string))))))
  4448. (when (bufferp errbuf)
  4449. (kill-buffer errbuf)))))
  4450. (defun message-send-mail-with-qmail ()
  4451. "Pass the prepared message buffer to qmail-inject.
  4452. Refer to the documentation for the variable `message-send-mail-function'
  4453. to find out how to use this."
  4454. ;; replace the header delimiter with a blank line
  4455. (goto-char (point-min))
  4456. (re-search-forward
  4457. (concat "^" (regexp-quote mail-header-separator) "\n"))
  4458. (replace-match "\n")
  4459. (run-hooks 'message-send-mail-hook)
  4460. ;; send the message
  4461. (case
  4462. (let ((coding-system-for-write message-send-coding-system))
  4463. (apply
  4464. 'call-process-region (point-min) (point-max)
  4465. message-qmail-inject-program nil nil nil
  4466. ;; qmail-inject's default behavior is to look for addresses on the
  4467. ;; command line; if there're none, it scans the headers.
  4468. ;; yes, it does The Right Thing w.r.t. Resent-To and it's kin.
  4469. ;;
  4470. ;; in general, ALL of qmail-inject's defaults are perfect for simply
  4471. ;; reading a formatted (i. e., at least a To: or Resent-To header)
  4472. ;; message from stdin.
  4473. ;;
  4474. ;; qmail also has the advantage of not having been raped by
  4475. ;; various vendors, so we don't have to allow for that, either --
  4476. ;; compare this with message-send-mail-with-sendmail and weep
  4477. ;; for sendmail's lost innocence.
  4478. ;;
  4479. ;; all this is way cool coz it lets us keep the arguments entirely
  4480. ;; free for -inject-arguments -- a big win for the user and for us
  4481. ;; since we don't have to play that double-guessing game and the user
  4482. ;; gets full control (no gestapo'ish -f's, for instance). --sj
  4483. (if (functionp message-qmail-inject-args)
  4484. (funcall message-qmail-inject-args)
  4485. message-qmail-inject-args)))
  4486. ;; qmail-inject doesn't say anything on it's stdout/stderr,
  4487. ;; we have to look at the retval instead
  4488. (0 nil)
  4489. (100 (error "qmail-inject reported permanent failure"))
  4490. (111 (error "qmail-inject reported transient failure"))
  4491. ;; should never happen
  4492. (t (error "qmail-inject reported unknown failure"))))
  4493. (defvar mh-previous-window-config)
  4494. (defun message-send-mail-with-mh ()
  4495. "Send the prepared message buffer with mh."
  4496. (let ((mh-previous-window-config nil)
  4497. (name (mh-new-draft-name)))
  4498. (setq buffer-file-name name)
  4499. ;; MH wants to generate these headers itself.
  4500. (when message-mh-deletable-headers
  4501. (let ((headers message-mh-deletable-headers))
  4502. (while headers
  4503. (goto-char (point-min))
  4504. (and (re-search-forward
  4505. (concat "^" (symbol-name (car headers)) ": *") nil t)
  4506. (message-delete-line))
  4507. (pop headers))))
  4508. (run-hooks 'message-send-mail-hook)
  4509. ;; Pass it on to mh.
  4510. (mh-send-letter)))
  4511. (defun message-smtpmail-send-it ()
  4512. "Send the prepared message buffer with `smtpmail-send-it'.
  4513. The only difference from `smtpmail-send-it' is that this command
  4514. evaluates `message-send-mail-hook' just before sending a message.
  4515. It is useful if your ISP requires the POP-before-SMTP
  4516. authentication. See the Gnus manual for details."
  4517. (run-hooks 'message-send-mail-hook)
  4518. ;; Change header-delimiter to be what smtpmail expects.
  4519. (goto-char (point-min))
  4520. (when (re-search-forward
  4521. (concat "^" (regexp-quote mail-header-separator) "\n"))
  4522. (replace-match "\n"))
  4523. (smtpmail-send-it))
  4524. (defun message-send-mail-with-mailclient ()
  4525. "Send the prepared message buffer with `mailclient-send-it'.
  4526. The only difference from `mailclient-send-it' is that this
  4527. command evaluates `message-send-mail-hook' just before sending a message."
  4528. (run-hooks 'message-send-mail-hook)
  4529. (mailclient-send-it))
  4530. (defun message-canlock-generate ()
  4531. "Return a string that is non-trivial to guess.
  4532. Do not use this for anything important, it is cryptographically weak."
  4533. (require 'sha1)
  4534. (let (sha1-maximum-internal-length)
  4535. (sha1 (concat (message-unique-id)
  4536. (format "%x%x%x" (random) (random) (random))
  4537. (prin1-to-string (recent-keys))
  4538. (prin1-to-string (garbage-collect))))))
  4539. (defvar canlock-password)
  4540. (defvar canlock-password-for-verify)
  4541. (defun message-canlock-password ()
  4542. "The password used by message for cancel locks.
  4543. This is the value of `canlock-password', if that option is non-nil.
  4544. Otherwise, generate and save a value for `canlock-password' first."
  4545. (require 'canlock)
  4546. (unless canlock-password
  4547. (customize-save-variable 'canlock-password (message-canlock-generate))
  4548. (setq canlock-password-for-verify canlock-password))
  4549. canlock-password)
  4550. (defun message-insert-canlock ()
  4551. (when message-insert-canlock
  4552. (message-canlock-password)
  4553. (canlock-insert-header)))
  4554. (autoload 'nnheader-get-report "nnheader")
  4555. (declare-function gnus-setup-posting-charset "gnus-msg" (group))
  4556. (defun message-send-news (&optional arg)
  4557. (require 'gnus-msg)
  4558. (let* ((tembuf (message-generate-new-buffer-clone-locals " *message temp*"))
  4559. (case-fold-search nil)
  4560. (method (if (functionp message-post-method)
  4561. (funcall message-post-method arg)
  4562. message-post-method))
  4563. (newsgroups-field (save-restriction
  4564. (message-narrow-to-headers-or-head)
  4565. (message-fetch-field "Newsgroups")))
  4566. (followup-field (save-restriction
  4567. (message-narrow-to-headers-or-head)
  4568. (message-fetch-field "Followup-To")))
  4569. ;; BUG: We really need to get the charset for each name in the
  4570. ;; Newsgroups and Followup-To lines to allow crossposting
  4571. ;; between group names with incompatible character sets.
  4572. ;; -- Per Abrahamsen <abraham@dina.kvl.dk> 2001-10-08.
  4573. (group-field-charset
  4574. (gnus-group-name-charset method newsgroups-field))
  4575. (followup-field-charset
  4576. (gnus-group-name-charset method (or followup-field "")))
  4577. (rfc2047-header-encoding-alist
  4578. (append (when group-field-charset
  4579. (list (cons "Newsgroups" group-field-charset)))
  4580. (when followup-field-charset
  4581. (list (cons "Followup-To" followup-field-charset)))
  4582. rfc2047-header-encoding-alist))
  4583. (messbuf (current-buffer))
  4584. (message-syntax-checks
  4585. (if (and arg
  4586. (listp message-syntax-checks))
  4587. (cons '(existing-newsgroups . disabled)
  4588. message-syntax-checks)
  4589. message-syntax-checks))
  4590. (message-this-is-news t)
  4591. (message-posting-charset
  4592. (gnus-setup-posting-charset newsgroups-field))
  4593. result)
  4594. (if (not (message-check-news-body-syntax))
  4595. nil
  4596. (save-restriction
  4597. (message-narrow-to-headers)
  4598. ;; Insert some headers.
  4599. (message-generate-headers message-required-news-headers)
  4600. (message-insert-canlock)
  4601. ;; Let the user do all of the above.
  4602. (run-hooks 'message-header-hook))
  4603. ;; Note: This check will be disabled by the ".*" default value for
  4604. ;; gnus-group-name-charset-group-alist. -- Pa 2001-10-07.
  4605. (when (and group-field-charset
  4606. (listp message-syntax-checks))
  4607. (setq message-syntax-checks
  4608. (cons '(valid-newsgroups . disabled)
  4609. message-syntax-checks)))
  4610. (message-cleanup-headers)
  4611. (if (not (let ((message-post-method method))
  4612. (message-check-news-syntax)))
  4613. nil
  4614. (unwind-protect
  4615. (with-current-buffer tembuf
  4616. (buffer-disable-undo)
  4617. (erase-buffer)
  4618. ;; Avoid copying text props (except hard newlines).
  4619. (insert
  4620. (with-current-buffer messbuf
  4621. (mml-buffer-substring-no-properties-except-hard-newlines
  4622. (point-min) (point-max))))
  4623. (message-encode-message-body)
  4624. ;; Remove some headers.
  4625. (save-restriction
  4626. (message-narrow-to-headers)
  4627. ;; We (re)generate the Lines header.
  4628. (when (memq 'Lines message-required-mail-headers)
  4629. (message-generate-headers '(Lines)))
  4630. ;; Remove some headers.
  4631. (message-remove-header message-ignored-news-headers t)
  4632. (let ((mail-parse-charset message-default-charset))
  4633. (mail-encode-encoded-word-buffer)))
  4634. (goto-char (point-max))
  4635. ;; require one newline at the end.
  4636. (or (= (preceding-char) ?\n)
  4637. (insert ?\n))
  4638. (let ((case-fold-search t))
  4639. ;; Remove the delimiter.
  4640. (goto-char (point-min))
  4641. (re-search-forward
  4642. (concat "^" (regexp-quote mail-header-separator) "\n"))
  4643. (replace-match "\n")
  4644. (backward-char 1))
  4645. (run-hooks 'message-send-news-hook)
  4646. (gnus-open-server method)
  4647. (message "Sending news via %s..." (gnus-server-string method))
  4648. (setq result (let ((mail-header-separator ""))
  4649. (gnus-request-post method))))
  4650. (kill-buffer tembuf))
  4651. (set-buffer messbuf)
  4652. (if result
  4653. (push 'news message-sent-message-via)
  4654. (message "Couldn't send message via news: %s"
  4655. (nnheader-get-report (car method)))
  4656. nil)))))
  4657. ;;;
  4658. ;;; Header generation & syntax checking.
  4659. ;;;
  4660. (defun message-check-element (type)
  4661. "Return non-nil if this TYPE is not to be checked."
  4662. (if (eq message-syntax-checks 'dont-check-for-anything-just-trust-me)
  4663. t
  4664. (let ((able (assq type message-syntax-checks)))
  4665. (and (consp able)
  4666. (eq (cdr able) 'disabled)))))
  4667. (defun message-check-news-syntax ()
  4668. "Check the syntax of the message."
  4669. (save-excursion
  4670. (save-restriction
  4671. (widen)
  4672. ;; We narrow to the headers and check them first.
  4673. (save-excursion
  4674. (save-restriction
  4675. (message-narrow-to-headers)
  4676. (message-check-news-header-syntax))))))
  4677. (defun message-check-news-header-syntax ()
  4678. (and
  4679. ;; Check Newsgroups header.
  4680. (message-check 'newsgroups
  4681. (let ((group (message-fetch-field "newsgroups")))
  4682. (or
  4683. (and group
  4684. (not (string-match "\\`[ \t]*\\'" group)))
  4685. (ignore
  4686. (message
  4687. "The newsgroups field is empty or missing. Posting is denied.")))))
  4688. ;; Check the Subject header.
  4689. (message-check 'subject
  4690. (let* ((case-fold-search t)
  4691. (subject (message-fetch-field "subject")))
  4692. (or
  4693. (and subject
  4694. (not (string-match "\\`[ \t]*\\'" subject)))
  4695. (ignore
  4696. (message
  4697. "The subject field is empty or missing. Posting is denied.")))))
  4698. ;; Check for commands in Subject.
  4699. (message-check 'subject-cmsg
  4700. (if (string-match "^cmsg " (message-fetch-field "subject"))
  4701. (y-or-n-p
  4702. "The control code \"cmsg\" is in the subject. Really post? ")
  4703. t))
  4704. ;; Check long header lines.
  4705. (message-check 'long-header-lines
  4706. (let ((header nil)
  4707. (length 0)
  4708. found)
  4709. (while (and (not found)
  4710. (re-search-forward "^\\([^ \t:]+\\): " nil t))
  4711. (if (> (- (point) (match-beginning 0)) 998)
  4712. (setq found t
  4713. length (- (point) (match-beginning 0)))
  4714. (setq header (match-string-no-properties 1)))
  4715. (forward-line 1))
  4716. (if found
  4717. (y-or-n-p (format "Your %s header is too long (%d). Really post? "
  4718. header length))
  4719. t)))
  4720. ;; Check for multiple identical headers.
  4721. (message-check 'multiple-headers
  4722. (let (found)
  4723. (while (and (not found)
  4724. (re-search-forward "^[^ \t:]+: " nil t))
  4725. (save-excursion
  4726. (or (re-search-forward
  4727. (concat "^"
  4728. (regexp-quote
  4729. (setq found
  4730. (buffer-substring
  4731. (match-beginning 0) (- (match-end 0) 2))))
  4732. ":")
  4733. nil t)
  4734. (setq found nil))))
  4735. (if found
  4736. (y-or-n-p (format "Multiple %s headers. Really post? " found))
  4737. t)))
  4738. ;; Check for Version and Sendsys.
  4739. (message-check 'sendsys
  4740. (if (re-search-forward "^Sendsys:\\|^Version:" nil t)
  4741. (y-or-n-p
  4742. (format "The article contains a %s command. Really post? "
  4743. (buffer-substring (match-beginning 0)
  4744. (1- (match-end 0)))))
  4745. t))
  4746. ;; See whether we can shorten Followup-To.
  4747. (message-check 'shorten-followup-to
  4748. (let ((newsgroups (message-fetch-field "newsgroups"))
  4749. (followup-to (message-fetch-field "followup-to"))
  4750. to)
  4751. (when (and newsgroups
  4752. (string-match "," newsgroups)
  4753. (not followup-to)
  4754. (not
  4755. (zerop
  4756. (length
  4757. (setq to (completing-read
  4758. "Followups to (default no Followup-To header): "
  4759. (mapcar #'list
  4760. (cons "poster"
  4761. (message-tokenize-header
  4762. newsgroups)))))))))
  4763. (goto-char (point-min))
  4764. (insert "Followup-To: " to "\n"))
  4765. t))
  4766. ;; Check "Shoot me".
  4767. (message-check 'shoot
  4768. (if (re-search-forward
  4769. "Message-ID.*.i-did-not-set--mail-host-address--so-tickle-me" nil t)
  4770. (y-or-n-p "You appear to have a misconfigured system. Really post? ")
  4771. t))
  4772. ;; Check for Approved.
  4773. (message-check 'approved
  4774. (if (re-search-forward "^Approved:" nil t)
  4775. (y-or-n-p "The article contains an Approved header. Really post? ")
  4776. t))
  4777. ;; Check the Message-ID header.
  4778. (message-check 'message-id
  4779. (let* ((case-fold-search t)
  4780. (message-id (message-fetch-field "message-id" t)))
  4781. (or (not message-id)
  4782. ;; Is there an @ in the ID?
  4783. (and (string-match "@" message-id)
  4784. ;; Is there a dot in the ID?
  4785. (string-match "@[^.]*\\." message-id)
  4786. ;; Does the ID end with a dot?
  4787. (not (string-match "\\.>" message-id)))
  4788. (y-or-n-p
  4789. (format "The Message-ID looks strange: \"%s\". Really post? "
  4790. message-id)))))
  4791. ;; Check the Newsgroups & Followup-To headers.
  4792. (message-check 'existing-newsgroups
  4793. (let* ((case-fold-search t)
  4794. (newsgroups (message-fetch-field "newsgroups"))
  4795. (followup-to (message-fetch-field "followup-to"))
  4796. (groups (message-tokenize-header
  4797. (if followup-to
  4798. (concat newsgroups "," followup-to)
  4799. newsgroups)))
  4800. (post-method (if (functionp message-post-method)
  4801. (funcall message-post-method)
  4802. message-post-method))
  4803. ;; KLUDGE to handle nnvirtual groups. Doing this right
  4804. ;; would probably involve a new nnoo function.
  4805. ;; -- Per Abrahamsen <abraham@dina.kvl.dk>, 2001-10-17.
  4806. (method (if (and (consp post-method)
  4807. (eq (car post-method) 'nnvirtual)
  4808. gnus-message-group-art)
  4809. (let ((group (car (nnvirtual-find-group-art
  4810. (car gnus-message-group-art)
  4811. (cdr gnus-message-group-art)))))
  4812. (gnus-find-method-for-group group))
  4813. post-method))
  4814. (known-groups
  4815. (mapcar (lambda (n)
  4816. (gnus-group-name-decode
  4817. (gnus-group-real-name n)
  4818. (gnus-group-name-charset method n)))
  4819. (gnus-groups-from-server method)))
  4820. errors)
  4821. (while groups
  4822. (when (and (not (equal (car groups) "poster"))
  4823. (not (member (car groups) known-groups))
  4824. (not (member (car groups) errors)))
  4825. (push (car groups) errors))
  4826. (pop groups))
  4827. (cond
  4828. ;; Gnus is not running.
  4829. ((or (not (and (boundp 'gnus-active-hashtb)
  4830. gnus-active-hashtb))
  4831. (not (boundp 'gnus-read-active-file)))
  4832. t)
  4833. ;; We don't have all the group names.
  4834. ((and (or (not gnus-read-active-file)
  4835. (eq gnus-read-active-file 'some))
  4836. errors)
  4837. (y-or-n-p
  4838. (format
  4839. "Really use %s possibly unknown group%s: %s? "
  4840. (if (= (length errors) 1) "this" "these")
  4841. (if (= (length errors) 1) "" "s")
  4842. (mapconcat 'identity errors ", "))))
  4843. ;; There were no errors.
  4844. ((not errors)
  4845. t)
  4846. ;; There are unknown groups.
  4847. (t
  4848. (y-or-n-p
  4849. (format
  4850. "Really post to %s unknown group%s: %s? "
  4851. (if (= (length errors) 1) "this" "these")
  4852. (if (= (length errors) 1) "" "s")
  4853. (mapconcat 'identity errors ", ")))))))
  4854. ;; Check continuation headers.
  4855. (message-check 'continuation-headers
  4856. (goto-char (point-min))
  4857. (let ((do-posting t))
  4858. (while (re-search-forward "^[^ \t\n][^ \t\n:]*[ \t\n]" nil t)
  4859. (goto-char (match-beginning 0))
  4860. (if (y-or-n-p "Fix continuation lines? ")
  4861. (insert " ")
  4862. (forward-line 1)
  4863. (unless (y-or-n-p "Send anyway? ")
  4864. (setq do-posting nil))))
  4865. do-posting))
  4866. ;; Check the Newsgroups & Followup-To headers for syntax errors.
  4867. (message-check 'valid-newsgroups
  4868. (let ((case-fold-search t)
  4869. (headers '("Newsgroups" "Followup-To"))
  4870. header error)
  4871. (while (and headers (not error))
  4872. (when (setq header (mail-fetch-field (car headers)))
  4873. (if (or
  4874. (not
  4875. (string-match
  4876. "\\`\\([-+_&.a-zA-Z0-9]+\\)?\\(,[-+_&.a-zA-Z0-9]+\\)*\\'"
  4877. header))
  4878. (memq
  4879. nil (mapcar
  4880. (lambda (g)
  4881. (not (string-match "\\.\\'\\|\\.\\." g)))
  4882. (message-tokenize-header header ","))))
  4883. (setq error t)))
  4884. (unless error
  4885. (pop headers)))
  4886. (if (not error)
  4887. t
  4888. (y-or-n-p
  4889. (format "The %s header looks odd: \"%s\". Really post? "
  4890. (car headers) header)))))
  4891. (message-check 'repeated-newsgroups
  4892. (let ((case-fold-search t)
  4893. (headers '("Newsgroups" "Followup-To"))
  4894. header error groups group)
  4895. (while (and headers
  4896. (not error))
  4897. (when (setq header (mail-fetch-field (pop headers)))
  4898. (setq groups (message-tokenize-header header ","))
  4899. (while (setq group (pop groups))
  4900. (when (member group groups)
  4901. (setq error group
  4902. groups nil)))))
  4903. (if (not error)
  4904. t
  4905. (y-or-n-p
  4906. (format "Group %s is repeated in headers. Really post? " error)))))
  4907. ;; Check the From header.
  4908. (message-check 'from
  4909. (let* ((case-fold-search t)
  4910. (from (message-fetch-field "from"))
  4911. ad)
  4912. (cond
  4913. ((not from)
  4914. (message "There is no From line. Posting is denied.")
  4915. nil)
  4916. ((or (not (string-match
  4917. "@[^\\.]*\\."
  4918. (setq ad (nth 1 (mail-extract-address-components
  4919. from))))) ;larsi@ifi
  4920. (string-match "\\.\\." ad) ;larsi@ifi..uio
  4921. (string-match "@\\." ad) ;larsi@.ifi.uio
  4922. (string-match "\\.$" ad) ;larsi@ifi.uio.
  4923. (not (string-match "^[^@]+@[^@]+$" ad)) ;larsi.ifi.uio
  4924. (string-match "(.*).*(.*)" from)) ;(lars) (lars)
  4925. (message
  4926. "Denied posting -- the From looks strange: \"%s\"." from)
  4927. nil)
  4928. ((let ((addresses (rfc822-addresses from)))
  4929. ;; `rfc822-addresses' returns a string if parsing fails.
  4930. (while (and (consp addresses)
  4931. (not (eq (string-to-char (car addresses)) ?\()))
  4932. (setq addresses (cdr addresses)))
  4933. addresses)
  4934. (message
  4935. "Denied posting -- bad From address: \"%s\"." from)
  4936. nil)
  4937. (t t))))
  4938. ;; Check the Reply-To header.
  4939. (message-check 'reply-to
  4940. (let* ((case-fold-search t)
  4941. (reply-to (message-fetch-field "reply-to"))
  4942. ad)
  4943. (cond
  4944. ((not reply-to)
  4945. t)
  4946. ((string-match "," reply-to)
  4947. (y-or-n-p
  4948. (format "Multiple Reply-To addresses: \"%s\". Really post? "
  4949. reply-to)))
  4950. ((or (not (string-match
  4951. "@[^\\.]*\\."
  4952. (setq ad (nth 1 (mail-extract-address-components
  4953. reply-to))))) ;larsi@ifi
  4954. (string-match "\\.\\." ad) ;larsi@ifi..uio
  4955. (string-match "@\\." ad) ;larsi@.ifi.uio
  4956. (string-match "\\.$" ad) ;larsi@ifi.uio.
  4957. (not (string-match "^[^@]+@[^@]+$" ad)) ;larsi.ifi.uio
  4958. (string-match "(.*).*(.*)" reply-to)) ;(lars) (lars)
  4959. (y-or-n-p
  4960. (format
  4961. "The Reply-To looks strange: \"%s\". Really post? "
  4962. reply-to)))
  4963. (t t))))))
  4964. (defun message-check-news-body-syntax ()
  4965. (and
  4966. ;; Check for long lines.
  4967. (message-check 'long-lines
  4968. (goto-char (point-min))
  4969. (re-search-forward
  4970. (concat "^" (regexp-quote mail-header-separator) "$"))
  4971. (forward-line 1)
  4972. (while (and
  4973. (or (looking-at
  4974. "<#\\(/\\)?\\(multipart\\|part\\|external\\|mml\\)")
  4975. (let ((p (point)))
  4976. (end-of-line)
  4977. (< (- (point) p) 80)))
  4978. (zerop (forward-line 1))))
  4979. (or (bolp)
  4980. (eobp)
  4981. (y-or-n-p
  4982. "You have lines longer than 79 characters. Really post? ")))
  4983. ;; Check whether the article is empty.
  4984. (message-check 'empty
  4985. (goto-char (point-min))
  4986. (re-search-forward
  4987. (concat "^" (regexp-quote mail-header-separator) "$"))
  4988. (forward-line 1)
  4989. (let ((b (point)))
  4990. (goto-char (point-max))
  4991. (re-search-backward message-signature-separator nil t)
  4992. (beginning-of-line)
  4993. (or (re-search-backward "[^ \n\t]" b t)
  4994. (if (message-gnksa-enable-p 'empty-article)
  4995. (y-or-n-p "Empty article. Really post? ")
  4996. (message "Denied posting -- Empty article.")
  4997. nil))))
  4998. ;; Check for control characters.
  4999. (message-check 'control-chars
  5000. (if (re-search-forward
  5001. (mm-string-to-multibyte "[\000-\007\013\015-\032\034-\037\200-\237]")
  5002. nil t)
  5003. (y-or-n-p
  5004. "The article contains control characters. Really post? ")
  5005. t))
  5006. ;; Check excessive size.
  5007. (message-check 'size
  5008. (if (> (buffer-size) 60000)
  5009. (y-or-n-p
  5010. (format "The article is %d octets long. Really post? "
  5011. (buffer-size)))
  5012. t))
  5013. ;; Check whether any new text has been added.
  5014. (message-check 'new-text
  5015. (or
  5016. (not message-checksum)
  5017. (not (eq (message-checksum) message-checksum))
  5018. (if (message-gnksa-enable-p 'quoted-text-only)
  5019. (y-or-n-p
  5020. "It looks like no new text has been added. Really post? ")
  5021. (message "Denied posting -- no new text has been added.")
  5022. nil)))
  5023. ;; Check the length of the signature.
  5024. (message-check 'signature
  5025. (let (sig-start sig-end)
  5026. (goto-char (point-max))
  5027. (if (not (re-search-backward message-signature-separator nil t))
  5028. t
  5029. (setq sig-start (1+ (point-at-eol)))
  5030. (setq sig-end
  5031. (if (re-search-forward
  5032. "<#/?\\(multipart\\|part\\|external\\|mml\\)" nil t)
  5033. (- (point-at-bol) 1)
  5034. (point-max)))
  5035. (if (>= (count-lines sig-start sig-end) 5)
  5036. (if (message-gnksa-enable-p 'signature)
  5037. (y-or-n-p
  5038. (format "Signature is excessively long (%d lines). Really post? "
  5039. (count-lines sig-start sig-end)))
  5040. (message "Denied posting -- Excessive signature.")
  5041. nil)
  5042. t))))
  5043. ;; Ensure that text follows last quoted portion.
  5044. (message-check 'quoting-style
  5045. (goto-char (point-max))
  5046. (let ((no-problem t))
  5047. (when (search-backward-regexp "^>[^\n]*\n" nil t)
  5048. (setq no-problem (search-forward-regexp "^[ \t]*[^>\n]" nil t)))
  5049. (if no-problem
  5050. t
  5051. (if (message-gnksa-enable-p 'quoted-text-only)
  5052. (y-or-n-p "Your text should follow quoted text. Really post? ")
  5053. ;; Ensure that
  5054. (goto-char (point-min))
  5055. (re-search-forward
  5056. (concat "^" (regexp-quote mail-header-separator) "$"))
  5057. (if (search-forward-regexp "^[ \t]*[^>\n]" nil t)
  5058. (y-or-n-p "Your text should follow quoted text. Really post? ")
  5059. (message "Denied posting -- only quoted text.")
  5060. nil)))))))
  5061. (defun message-checksum ()
  5062. "Return a \"checksum\" for the current buffer."
  5063. (let ((sum 0))
  5064. (save-excursion
  5065. (goto-char (point-min))
  5066. (re-search-forward
  5067. (concat "^" (regexp-quote mail-header-separator) "$"))
  5068. (while (not (eobp))
  5069. (when (not (looking-at "[ \t\n]"))
  5070. (setq sum (logxor (ash sum 1) (if (natnump sum) 0 1)
  5071. (char-after))))
  5072. (forward-char 1)))
  5073. sum))
  5074. (defun message-do-fcc ()
  5075. "Process Fcc headers in the current buffer."
  5076. (let ((case-fold-search t)
  5077. (buf (current-buffer))
  5078. list file
  5079. (mml-externalize-attachments message-fcc-externalize-attachments))
  5080. (save-excursion
  5081. (save-restriction
  5082. (message-narrow-to-headers)
  5083. (setq file (message-fetch-field "fcc" t)))
  5084. (when file
  5085. (set-buffer (get-buffer-create " *message temp*"))
  5086. (erase-buffer)
  5087. (insert-buffer-substring buf)
  5088. (message-encode-message-body)
  5089. (save-restriction
  5090. (message-narrow-to-headers)
  5091. (while (setq file (message-fetch-field "fcc" t))
  5092. (push file list)
  5093. (message-remove-header "fcc" nil t))
  5094. (let ((mail-parse-charset message-default-charset)
  5095. (rfc2047-header-encoding-alist
  5096. (cons '("Newsgroups" . default)
  5097. rfc2047-header-encoding-alist)))
  5098. (mail-encode-encoded-word-buffer)))
  5099. (goto-char (point-min))
  5100. (when (re-search-forward
  5101. (concat "^" (regexp-quote mail-header-separator) "$")
  5102. nil t)
  5103. (replace-match "" t t ))
  5104. ;; Process FCC operations.
  5105. (while list
  5106. (setq file (pop list))
  5107. (if (string-match "^[ \t]*|[ \t]*\\(.*\\)[ \t]*$" file)
  5108. ;; Pipe the article to the program in question.
  5109. (call-process-region (point-min) (point-max) shell-file-name
  5110. nil nil nil shell-command-switch
  5111. (match-string 1 file))
  5112. ;; Save the article.
  5113. (setq file (expand-file-name file))
  5114. (unless (file-exists-p (file-name-directory file))
  5115. (make-directory (file-name-directory file) t))
  5116. (if (and message-fcc-handler-function
  5117. (not (eq message-fcc-handler-function 'rmail-output)))
  5118. (funcall message-fcc-handler-function file)
  5119. ;; FIXME this option, rmail-output (also used if
  5120. ;; message-fcc-handler-function is nil) is not
  5121. ;; documented anywhere AFAICS. It should work in Emacs
  5122. ;; 23; I suspect it does not work in Emacs 22.
  5123. ;; FIXME I don't see the need for the two different cases here.
  5124. ;; mail-use-rfc822 makes no difference (in Emacs 23),and
  5125. ;; the third argument just controls \"Wrote file\" message.
  5126. (if (and (file-readable-p file) (mail-file-babyl-p file))
  5127. (rmail-output file 1 nil t)
  5128. (let ((mail-use-rfc822 t))
  5129. (rmail-output file 1 t t))))))
  5130. (kill-buffer (current-buffer))))))
  5131. (defun message-output (filename)
  5132. "Append this article to Unix/babyl mail file FILENAME."
  5133. (if (or (and (file-readable-p filename)
  5134. (mail-file-babyl-p filename))
  5135. ;; gnus-output-to-mail does the wrong thing with live, mbox
  5136. ;; Rmail buffers in Emacs 23.
  5137. ;; http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=597255
  5138. (let ((buff (find-buffer-visiting filename)))
  5139. (and buff (with-current-buffer buff
  5140. (eq major-mode 'rmail-mode)))))
  5141. (gnus-output-to-rmail filename t)
  5142. (gnus-output-to-mail filename t)))
  5143. (defun message-cleanup-headers ()
  5144. "Do various automatic cleanups of the headers."
  5145. ;; Remove empty lines in the header.
  5146. (save-restriction
  5147. (message-narrow-to-headers)
  5148. ;; Remove blank lines.
  5149. (while (re-search-forward "^[ \t]*\n" nil t)
  5150. (replace-match "" t t))
  5151. ;; Correct Newsgroups and Followup-To headers: Change sequence of
  5152. ;; spaces to comma and eliminate spaces around commas. Eliminate
  5153. ;; embedded line breaks.
  5154. (goto-char (point-min))
  5155. (while (re-search-forward "^\\(Newsgroups\\|Followup-To\\): +" nil t)
  5156. (save-restriction
  5157. (narrow-to-region
  5158. (point)
  5159. (if (re-search-forward "^[^ \t]" nil t)
  5160. (match-beginning 0)
  5161. (forward-line 1)
  5162. (point)))
  5163. (goto-char (point-min))
  5164. (while (re-search-forward "\n[ \t]+" nil t)
  5165. (replace-match " " t t)) ;No line breaks (too confusing)
  5166. (goto-char (point-min))
  5167. (while (re-search-forward "[ \t\n]*,[ \t\n]*\\|[ \t]+" nil t)
  5168. (replace-match "," t t))
  5169. (goto-char (point-min))
  5170. ;; Remove trailing commas.
  5171. (when (re-search-forward ",+$" nil t)
  5172. (replace-match "" t t))))))
  5173. (defun message-make-date (&optional now)
  5174. "Make a valid data header.
  5175. If NOW, use that time instead."
  5176. (let ((system-time-locale "C"))
  5177. (format-time-string "%a, %d %b %Y %T %z" now)))
  5178. (defun message-insert-expires (days)
  5179. "Insert the Expires header. Expiry in DAYS days."
  5180. (interactive "NExpire article in how many days? ")
  5181. (save-excursion
  5182. (message-position-on-field "Expires" "X-Draft-From")
  5183. (insert (message-make-expires-date days))))
  5184. (defun message-make-expires-date (days)
  5185. "Make date string for the Expires header. Expiry in DAYS days.
  5186. In posting styles use `(\"Expires\" (make-expires-date 30))'."
  5187. (let* ((cur (decode-time))
  5188. (nday (+ days (nth 3 cur))))
  5189. (setf (nth 3 cur) nday)
  5190. (message-make-date (apply 'encode-time cur))))
  5191. (defun message-make-message-id ()
  5192. "Make a unique Message-ID."
  5193. (concat "<" (message-unique-id)
  5194. (let ((psubject (save-excursion (message-fetch-field "subject")))
  5195. (psupersedes
  5196. (save-excursion (message-fetch-field "supersedes"))))
  5197. (if (or
  5198. (and message-reply-headers
  5199. (mail-header-references message-reply-headers)
  5200. (mail-header-subject message-reply-headers)
  5201. psubject
  5202. (not (string=
  5203. (message-strip-subject-re
  5204. (mail-header-subject message-reply-headers))
  5205. (message-strip-subject-re psubject))))
  5206. (and psupersedes
  5207. (string-match "_-_@" psupersedes)))
  5208. "_-_" ""))
  5209. "@" (message-make-fqdn) ">"))
  5210. (defvar message-unique-id-char nil)
  5211. ;; If you ever change this function, make sure the new version
  5212. ;; cannot generate IDs that the old version could.
  5213. ;; You might for example insert a "." somewhere (not next to another dot
  5214. ;; or string boundary), or modify the "fsf" string.
  5215. (defun message-unique-id ()
  5216. ;; Don't use microseconds from (current-time), they may be unsupported.
  5217. ;; Instead we use this randomly inited counter.
  5218. (setq message-unique-id-char
  5219. (% (1+ (or message-unique-id-char
  5220. (logand (random most-positive-fixnum) (1- (lsh 1 20)))))
  5221. ;; (current-time) returns 16-bit ints,
  5222. ;; and 2^16*25 just fits into 4 digits i base 36.
  5223. (* 25 25)))
  5224. (let ((tm (current-time)))
  5225. (concat
  5226. (if (or (eq system-type 'ms-dos)
  5227. ;; message-number-base36 doesn't handle bigints.
  5228. (floatp (user-uid)))
  5229. (let ((user (downcase (user-login-name))))
  5230. (while (string-match "[^a-z0-9_]" user)
  5231. (aset user (match-beginning 0) ?_))
  5232. user)
  5233. (message-number-base36 (user-uid) -1))
  5234. (message-number-base36 (+ (car tm)
  5235. (lsh (% message-unique-id-char 25) 16)) 4)
  5236. (message-number-base36 (+ (nth 1 tm)
  5237. (lsh (/ message-unique-id-char 25) 16)) 4)
  5238. ;; Append a given name, because while the generated ID is unique
  5239. ;; to this newsreader, other newsreaders might otherwise generate
  5240. ;; the same ID via another algorithm.
  5241. ".fsf")))
  5242. (defun message-number-base36 (num len)
  5243. (if (if (< len 0)
  5244. (<= num 0)
  5245. (= len 0))
  5246. ""
  5247. (concat (message-number-base36 (/ num 36) (1- len))
  5248. (char-to-string (aref "zyxwvutsrqponmlkjihgfedcba9876543210"
  5249. (% num 36))))))
  5250. (defun message-make-organization ()
  5251. "Make an Organization header."
  5252. (let* ((organization
  5253. (when message-user-organization
  5254. (if (functionp message-user-organization)
  5255. (funcall message-user-organization)
  5256. message-user-organization))))
  5257. (with-temp-buffer
  5258. (mm-enable-multibyte)
  5259. (cond ((stringp organization)
  5260. (insert organization))
  5261. ((and (eq t organization)
  5262. message-user-organization-file
  5263. (file-exists-p message-user-organization-file))
  5264. (insert-file-contents message-user-organization-file)))
  5265. (goto-char (point-min))
  5266. (while (re-search-forward "[\t\n]+" nil t)
  5267. (replace-match "" t t))
  5268. (unless (zerop (buffer-size))
  5269. (buffer-string)))))
  5270. (defun message-make-lines ()
  5271. "Count the number of lines and return numeric string."
  5272. (save-excursion
  5273. (save-restriction
  5274. (widen)
  5275. (message-goto-body)
  5276. (int-to-string (count-lines (point) (point-max))))))
  5277. (defun message-make-references ()
  5278. "Return the References header for this message."
  5279. (when message-reply-headers
  5280. (let ((message-id (mail-header-id message-reply-headers))
  5281. (references (mail-header-references message-reply-headers)))
  5282. (if (or references message-id)
  5283. (concat (or references "") (and references " ")
  5284. (or message-id ""))
  5285. nil))))
  5286. (defun message-make-in-reply-to ()
  5287. "Return the In-Reply-To header for this message."
  5288. (when message-reply-headers
  5289. (let ((from (mail-header-from message-reply-headers))
  5290. (date (mail-header-date message-reply-headers))
  5291. (msg-id (mail-header-id message-reply-headers)))
  5292. (when from
  5293. (let ((name (mail-extract-address-components from)))
  5294. (concat
  5295. msg-id (if msg-id " (")
  5296. (if (car name)
  5297. (if (string-match "[^\000-\177]" (car name))
  5298. ;; Quote a string containing non-ASCII characters.
  5299. ;; It will make the RFC2047 encoder cause an error
  5300. ;; if there are special characters.
  5301. (mm-with-multibyte-buffer
  5302. (insert (car name))
  5303. (goto-char (point-min))
  5304. (while (search-forward "\"" nil t)
  5305. (when (prog2
  5306. (backward-char)
  5307. (zerop (% (skip-chars-backward "\\\\") 2))
  5308. (goto-char (match-beginning 0)))
  5309. (insert "\\"))
  5310. (forward-char))
  5311. ;; Those quotes will be removed by the RFC2047 encoder.
  5312. (concat "\"" (buffer-string) "\""))
  5313. (car name))
  5314. (nth 1 name))
  5315. "'s message of \""
  5316. (if (or (not date) (string= date ""))
  5317. "(unknown date)" date)
  5318. "\"" (if msg-id ")")))))))
  5319. (defun message-make-distribution ()
  5320. "Make a Distribution header."
  5321. (let ((orig-distribution (message-fetch-reply-field "distribution")))
  5322. (cond ((functionp message-distribution-function)
  5323. (funcall message-distribution-function))
  5324. (t orig-distribution))))
  5325. (defun message-make-expires ()
  5326. "Return an Expires header based on `message-expires'."
  5327. (let ((current (current-time))
  5328. (future (* 1.0 message-expires 60 60 24)))
  5329. ;; Add the future to current.
  5330. (setcar current (+ (car current) (round (/ future (expt 2 16)))))
  5331. (setcar (cdr current) (+ (nth 1 current) (% (round future) (expt 2 16))))
  5332. (message-make-date current)))
  5333. (defun message-make-path ()
  5334. "Return uucp path."
  5335. (let ((login-name (user-login-name)))
  5336. (cond ((null message-user-path)
  5337. (concat (system-name) "!" login-name))
  5338. ((stringp message-user-path)
  5339. ;; Support GENERICPATH. Suggested by vixie@decwrl.dec.com.
  5340. (concat message-user-path "!" login-name))
  5341. (t login-name))))
  5342. (defun message-make-from (&optional name address)
  5343. "Make a From header."
  5344. (let* ((style message-from-style)
  5345. (login (or address (message-make-address)))
  5346. (fullname (or name
  5347. (and (boundp 'user-full-name)
  5348. user-full-name)
  5349. (user-full-name))))
  5350. (when (string= fullname "&")
  5351. (setq fullname (user-login-name)))
  5352. (with-temp-buffer
  5353. (mm-enable-multibyte)
  5354. (cond
  5355. ((or (null style)
  5356. (equal fullname ""))
  5357. (insert login))
  5358. ((or (eq style 'angles)
  5359. (and (not (eq style 'parens))
  5360. ;; Use angles if no quoting is needed, or if parens would
  5361. ;; need quoting too.
  5362. (or (not (string-match "[^- !#-'*+/-9=?A-Z^-~]" fullname))
  5363. (let ((tmp (concat fullname nil)))
  5364. (while (string-match "([^()]*)" tmp)
  5365. (aset tmp (match-beginning 0) ?-)
  5366. (aset tmp (1- (match-end 0)) ?-))
  5367. (string-match "[\\()]" tmp)))))
  5368. (insert fullname)
  5369. (goto-char (point-min))
  5370. ;; Look for a character that cannot appear unquoted
  5371. ;; according to RFC 822.
  5372. (when (re-search-forward "[^- !#-'*+/-9=?A-Z^-~]" nil 1)
  5373. ;; Quote fullname, escaping specials.
  5374. (goto-char (point-min))
  5375. (insert "\"")
  5376. (while (re-search-forward "[\"\\]" nil 1)
  5377. (replace-match "\\\\\\&" t))
  5378. (insert "\""))
  5379. (insert " <" login ">"))
  5380. (t ; 'parens or default
  5381. (insert login " (")
  5382. (let ((fullname-start (point)))
  5383. (insert fullname)
  5384. (goto-char fullname-start)
  5385. ;; RFC 822 says \ and nonmatching parentheses
  5386. ;; must be escaped in comments.
  5387. ;; Escape every instance of ()\ ...
  5388. (while (re-search-forward "[()\\]" nil 1)
  5389. (replace-match "\\\\\\&" t))
  5390. ;; ... then undo escaping of matching parentheses,
  5391. ;; including matching nested parentheses.
  5392. (goto-char fullname-start)
  5393. (while (re-search-forward
  5394. "\\(\\=\\|[^\\]\\(\\\\\\\\\\)*\\)\\\\(\\(\\([^\\]\\|\\\\\\\\\\)*\\)\\\\)"
  5395. nil 1)
  5396. (replace-match "\\1(\\3)" t)
  5397. (goto-char fullname-start)))
  5398. (insert ")")))
  5399. (buffer-string))))
  5400. (defun message-make-sender ()
  5401. "Return the \"real\" user address.
  5402. This function tries to ignore all user modifications, and
  5403. give as trustworthy answer as possible."
  5404. (concat (user-login-name) "@" (system-name)))
  5405. (defun message-make-address ()
  5406. "Make the address of the user."
  5407. (or (message-user-mail-address)
  5408. (concat (user-login-name) "@" (message-make-domain))))
  5409. (defun message-user-mail-address ()
  5410. "Return the pertinent part of `user-mail-address'."
  5411. (when (and user-mail-address
  5412. (string-match "@.*\\." user-mail-address))
  5413. (if (string-match " " user-mail-address)
  5414. (nth 1 (mail-extract-address-components user-mail-address))
  5415. user-mail-address)))
  5416. (defun message-sendmail-envelope-from ()
  5417. "Return the envelope from."
  5418. (cond ((eq message-sendmail-envelope-from 'header)
  5419. (nth 1 (mail-extract-address-components
  5420. (message-fetch-field "from"))))
  5421. ((stringp message-sendmail-envelope-from)
  5422. message-sendmail-envelope-from)
  5423. (t
  5424. (message-make-address))))
  5425. (defun message-make-fqdn ()
  5426. "Return user's fully qualified domain name."
  5427. (let* ((sysname (system-name))
  5428. (user-mail (message-user-mail-address))
  5429. (user-domain
  5430. (if (and user-mail
  5431. (string-match "@\\(.*\\)\\'" user-mail))
  5432. (match-string 1 user-mail)))
  5433. (case-fold-search t))
  5434. (cond
  5435. ((and message-user-fqdn
  5436. (stringp message-user-fqdn)
  5437. (string-match message-valid-fqdn-regexp message-user-fqdn)
  5438. (not (string-match message-bogus-system-names message-user-fqdn)))
  5439. ;; `message-user-fqdn' seems to be valid
  5440. message-user-fqdn)
  5441. ((and (string-match message-valid-fqdn-regexp sysname)
  5442. (not (string-match message-bogus-system-names sysname)))
  5443. ;; `system-name' returned the right result.
  5444. sysname)
  5445. ;; Try `mail-host-address'.
  5446. ((and (boundp 'mail-host-address)
  5447. (stringp mail-host-address)
  5448. (string-match message-valid-fqdn-regexp mail-host-address)
  5449. (not (string-match message-bogus-system-names mail-host-address)))
  5450. mail-host-address)
  5451. ;; We try `user-mail-address' as a backup.
  5452. ((and user-domain
  5453. (stringp user-domain)
  5454. (string-match message-valid-fqdn-regexp user-domain)
  5455. (not (string-match message-bogus-system-names user-domain)))
  5456. user-domain)
  5457. ;; Default to this bogus thing.
  5458. (t
  5459. (concat sysname
  5460. ".i-did-not-set--mail-host-address--so-tickle-me")))))
  5461. (defun message-make-domain ()
  5462. "Return the domain name."
  5463. (or mail-host-address
  5464. (message-make-fqdn)))
  5465. (defun message-to-list-only ()
  5466. "Send a message to the list only.
  5467. Remove all addresses but the list address from To and Cc headers."
  5468. (interactive)
  5469. (let ((listaddr (message-make-mail-followup-to t)))
  5470. (when listaddr
  5471. (save-excursion
  5472. (message-remove-header "to")
  5473. (message-remove-header "cc")
  5474. (message-position-on-field "To" "X-Draft-From")
  5475. (insert listaddr)))))
  5476. (defun message-make-mail-followup-to (&optional only-show-subscribed)
  5477. "Return the Mail-Followup-To header.
  5478. If passed the optional argument ONLY-SHOW-SUBSCRIBED only return the
  5479. subscribed address (and not the additional To and Cc header contents)."
  5480. (let* ((case-fold-search t)
  5481. (to (message-fetch-field "To"))
  5482. (cc (message-fetch-field "cc"))
  5483. (msg-recipients (concat to (and to cc ", ") cc))
  5484. (recipients
  5485. (mapcar 'mail-strip-quoted-names
  5486. (message-tokenize-header msg-recipients)))
  5487. (file-regexps
  5488. (if message-subscribed-address-file
  5489. (let (begin end item re)
  5490. (save-excursion
  5491. (with-temp-buffer
  5492. (insert-file-contents message-subscribed-address-file)
  5493. (while (not (eobp))
  5494. (setq begin (point))
  5495. (forward-line 1)
  5496. (setq end (point))
  5497. (if (bolp) (setq end (1- end)))
  5498. (setq item (regexp-quote (buffer-substring begin end)))
  5499. (if re (setq re (concat re "\\|" item))
  5500. (setq re (concat "\\`\\(" item))))
  5501. (and re (list (concat re "\\)\\'"))))))))
  5502. (mft-regexps (apply 'append message-subscribed-regexps
  5503. (mapcar 'regexp-quote
  5504. message-subscribed-addresses)
  5505. file-regexps
  5506. (mapcar 'funcall
  5507. message-subscribed-address-functions))))
  5508. (save-match-data
  5509. (let ((list
  5510. (loop for recipient in recipients
  5511. when (loop for regexp in mft-regexps
  5512. when (string-match regexp recipient) return t)
  5513. return recipient)))
  5514. (when list
  5515. (if only-show-subscribed
  5516. list
  5517. msg-recipients))))))
  5518. (defun message-idna-to-ascii-rhs-1 (header)
  5519. "Interactively potentially IDNA encode domain names in HEADER."
  5520. (let ((field (message-fetch-field header))
  5521. ace)
  5522. (when field
  5523. (dolist (rhs
  5524. (mm-delete-duplicates
  5525. (mapcar (lambda (rhs) (or (cadr (split-string rhs "@")) ""))
  5526. (mapcar 'downcase
  5527. (mapcar
  5528. (lambda (elem)
  5529. (or (cadr elem)
  5530. ""))
  5531. (mail-extract-address-components field t))))))
  5532. ;; Note that `rhs' will be "" if the address does not have
  5533. ;; the domain part, i.e., if it is a local user's address.
  5534. (setq ace (if (string-match "\\`[[:ascii:]]*\\'" rhs)
  5535. rhs
  5536. (downcase (idna-to-ascii rhs))))
  5537. (when (and (not (equal rhs ace))
  5538. (or (not (eq message-use-idna 'ask))
  5539. (y-or-n-p (format "Replace %s with %s in %s:? "
  5540. rhs ace header))))
  5541. (goto-char (point-min))
  5542. (while (re-search-forward (concat "^" header ":") nil t)
  5543. (message-narrow-to-field)
  5544. (while (search-forward (concat "@" rhs) nil t)
  5545. (replace-match (concat "@" ace) t t))
  5546. (goto-char (point-max))
  5547. (widen)))))))
  5548. (defun message-idna-to-ascii-rhs ()
  5549. "Possibly IDNA encode non-ASCII domain names in From:, To: and Cc: headers.
  5550. See `message-idna-encode'."
  5551. (interactive)
  5552. (when message-use-idna
  5553. (save-excursion
  5554. (save-restriction
  5555. ;; `message-narrow-to-head' that recognizes only the first empty
  5556. ;; line as the message header separator used to be used here.
  5557. ;; However, since there is the "--text follows this line--" line
  5558. ;; normally, it failed in narrowing to the headers and potentially
  5559. ;; caused the IDNA encoding on lines that look like headers in
  5560. ;; the message body.
  5561. (message-narrow-to-headers-or-head)
  5562. (message-idna-to-ascii-rhs-1 "From")
  5563. (message-idna-to-ascii-rhs-1 "To")
  5564. (message-idna-to-ascii-rhs-1 "Reply-To")
  5565. (message-idna-to-ascii-rhs-1 "Mail-Reply-To")
  5566. (message-idna-to-ascii-rhs-1 "Mail-Followup-To")
  5567. (message-idna-to-ascii-rhs-1 "Cc")))))
  5568. (defvar Date)
  5569. (defvar Message-ID)
  5570. (defvar Organization)
  5571. (defvar From)
  5572. (defvar Path)
  5573. (defvar Subject)
  5574. (defvar Newsgroups)
  5575. (defvar In-Reply-To)
  5576. (defvar References)
  5577. (defvar To)
  5578. (defvar Distribution)
  5579. (defvar Lines)
  5580. (defvar User-Agent)
  5581. (defvar Expires)
  5582. (defun message-generate-headers (headers)
  5583. "Prepare article HEADERS.
  5584. Headers already prepared in the buffer are not modified."
  5585. (setq headers (append headers message-required-headers))
  5586. (save-restriction
  5587. (message-narrow-to-headers)
  5588. (let* ((Date (message-make-date))
  5589. (Message-ID (message-make-message-id))
  5590. (Organization (message-make-organization))
  5591. (From (message-make-from))
  5592. (Path (message-make-path))
  5593. (Subject nil)
  5594. (Newsgroups nil)
  5595. (In-Reply-To (message-make-in-reply-to))
  5596. (References (message-make-references))
  5597. (To nil)
  5598. (Distribution (message-make-distribution))
  5599. (Lines (message-make-lines))
  5600. (User-Agent message-newsreader)
  5601. (Expires (message-make-expires))
  5602. (case-fold-search t)
  5603. (optionalp nil)
  5604. header value elem header-string)
  5605. ;; First we remove any old generated headers.
  5606. (let ((headers message-deletable-headers))
  5607. (unless (buffer-modified-p)
  5608. (setq headers (delq 'Message-ID (copy-sequence headers))))
  5609. (while headers
  5610. (goto-char (point-min))
  5611. (and (re-search-forward
  5612. (concat "^" (symbol-name (car headers)) ": *") nil t)
  5613. (get-text-property (1+ (match-beginning 0)) 'message-deletable)
  5614. (message-delete-line))
  5615. (pop headers)))
  5616. ;; Go through all the required headers and see if they are in the
  5617. ;; articles already. If they are not, or are empty, they are
  5618. ;; inserted automatically - except for Subject, Newsgroups and
  5619. ;; Distribution.
  5620. (while headers
  5621. (goto-char (point-min))
  5622. (setq elem (pop headers))
  5623. (if (consp elem)
  5624. (if (eq (car elem) 'optional)
  5625. (setq header (cdr elem)
  5626. optionalp t)
  5627. (setq header (car elem)))
  5628. (setq header elem))
  5629. (setq header-string (if (stringp header)
  5630. header
  5631. (symbol-name header)))
  5632. (when (or (not (re-search-forward
  5633. (concat "^"
  5634. (regexp-quote (downcase header-string))
  5635. ":")
  5636. nil t))
  5637. (progn
  5638. ;; The header was found. We insert a space after the
  5639. ;; colon, if there is none.
  5640. (if (/= (char-after) ? ) (insert " ") (forward-char 1))
  5641. ;; Find out whether the header is empty.
  5642. (looking-at "[ \t]*\n[^ \t]")))
  5643. ;; So we find out what value we should insert.
  5644. (setq value
  5645. (cond
  5646. ((and (consp elem)
  5647. (eq (car elem) 'optional)
  5648. (not (member header-string message-inserted-headers)))
  5649. ;; This is an optional header. If the cdr of this
  5650. ;; is something that is nil, then we do not insert
  5651. ;; this header.
  5652. (setq header (cdr elem))
  5653. (or (and (functionp (cdr elem))
  5654. (funcall (cdr elem)))
  5655. (and (boundp (cdr elem))
  5656. (symbol-value (cdr elem)))))
  5657. ((consp elem)
  5658. ;; The element is a cons. Either the cdr is a
  5659. ;; string to be inserted verbatim, or it is a
  5660. ;; function, and we insert the value returned from
  5661. ;; this function.
  5662. (or (and (stringp (cdr elem))
  5663. (cdr elem))
  5664. (and (functionp (cdr elem))
  5665. (funcall (cdr elem)))))
  5666. ((and (boundp header)
  5667. (symbol-value header))
  5668. ;; The element is a symbol. We insert the value
  5669. ;; of this symbol, if any.
  5670. (symbol-value header))
  5671. ((not (message-check-element
  5672. (intern (downcase (symbol-name header)))))
  5673. ;; We couldn't generate a value for this header,
  5674. ;; so we just ask the user.
  5675. (read-from-minibuffer
  5676. (format "Empty header for %s; enter value: " header)))))
  5677. ;; Finally insert the header.
  5678. (when (and value
  5679. (not (equal value "")))
  5680. (save-excursion
  5681. (if (bolp)
  5682. (progn
  5683. ;; This header didn't exist, so we insert it.
  5684. (goto-char (point-max))
  5685. (let ((formatter
  5686. (cdr (assq header message-header-format-alist))))
  5687. (if formatter
  5688. (funcall formatter header value)
  5689. (insert header-string ": " value))
  5690. (push header-string message-inserted-headers)
  5691. (goto-char (message-fill-field))
  5692. ;; We check whether the value was ended by a
  5693. ;; newline. If not, we insert one.
  5694. (unless (bolp)
  5695. (insert "\n"))
  5696. (forward-line -1)))
  5697. ;; The value of this header was empty, so we clear
  5698. ;; totally and insert the new value.
  5699. (delete-region (point) (point-at-eol))
  5700. ;; If the header is optional, and the header was
  5701. ;; empty, we can't insert it anyway.
  5702. (unless optionalp
  5703. (push header-string message-inserted-headers)
  5704. (insert value)
  5705. (message-fill-field)))
  5706. ;; Add the deletable property to the headers that require it.
  5707. (and (memq header message-deletable-headers)
  5708. (progn (beginning-of-line) (looking-at "[^:]+: "))
  5709. (add-text-properties
  5710. (point) (match-end 0)
  5711. '(message-deletable t face italic) (current-buffer)))))))
  5712. ;; Insert new Sender if the From is strange.
  5713. (let ((from (message-fetch-field "from"))
  5714. (sender (message-fetch-field "sender"))
  5715. (secure-sender (message-make-sender)))
  5716. (when (and from
  5717. (not (message-check-element 'sender))
  5718. (not (string=
  5719. (downcase
  5720. (cadr (mail-extract-address-components from)))
  5721. (downcase secure-sender)))
  5722. (or (null sender)
  5723. (not
  5724. (string=
  5725. (downcase
  5726. (cadr (mail-extract-address-components sender)))
  5727. (downcase secure-sender)))))
  5728. (goto-char (point-min))
  5729. ;; Rename any old Sender headers to Original-Sender.
  5730. (when (re-search-forward "^\\(Original-\\)*Sender:" nil t)
  5731. (beginning-of-line)
  5732. (insert "Original-")
  5733. (beginning-of-line))
  5734. (when (or (message-news-p)
  5735. (string-match "@.+\\.." secure-sender))
  5736. (insert "Sender: " secure-sender "\n"))))
  5737. ;; Check for IDNA
  5738. (message-idna-to-ascii-rhs))))
  5739. (defun message-insert-courtesy-copy (message)
  5740. "Insert a courtesy message in mail copies of combined messages."
  5741. (let (newsgroups)
  5742. (save-excursion
  5743. (save-restriction
  5744. (message-narrow-to-headers)
  5745. (when (setq newsgroups (message-fetch-field "newsgroups"))
  5746. (goto-char (point-max))
  5747. (insert "Posted-To: " newsgroups "\n")))
  5748. (forward-line 1)
  5749. (when message
  5750. (cond
  5751. ((string-match "%s" message)
  5752. (insert (format message newsgroups)))
  5753. (t
  5754. (insert message)))))))
  5755. ;;;
  5756. ;;; Setting up a message buffer
  5757. ;;;
  5758. (defun message-skip-to-next-address ()
  5759. (let ((end (save-excursion
  5760. (message-next-header)
  5761. (point)))
  5762. quoted char)
  5763. (when (looking-at ",")
  5764. (forward-char 1))
  5765. (while (and (not (= (point) end))
  5766. (or (not (eq char ?,))
  5767. quoted))
  5768. (skip-chars-forward "^,\"" end)
  5769. (when (eq (setq char (following-char)) ?\")
  5770. (setq quoted (not quoted)))
  5771. (unless (= (point) end)
  5772. (forward-char 1)))
  5773. (skip-chars-forward " \t\n")))
  5774. (defun message-split-line ()
  5775. "Split current line, moving portion beyond point vertically down.
  5776. If the current line has `message-yank-prefix', insert it on the new line."
  5777. (interactive "*")
  5778. (condition-case nil
  5779. (split-line message-yank-prefix) ;; Emacs 22.1+ supports arg.
  5780. (error
  5781. (split-line))))
  5782. (defun message-insert-header (header value)
  5783. (insert (capitalize (symbol-name header))
  5784. ": "
  5785. (if (consp value) (car value) value)))
  5786. (defun message-field-name ()
  5787. (save-excursion
  5788. (goto-char (point-min))
  5789. (when (looking-at "\\([^:]+\\):")
  5790. (intern (capitalize (match-string 1))))))
  5791. (defun message-fill-field ()
  5792. (save-excursion
  5793. (save-restriction
  5794. (message-narrow-to-field)
  5795. (let ((field-name (message-field-name)))
  5796. (funcall (or (cadr (assq field-name message-field-fillers))
  5797. 'message-fill-field-general)))
  5798. (point-max))))
  5799. (defun message-fill-field-address ()
  5800. (let (end last)
  5801. (while (not end)
  5802. (message-skip-to-next-address)
  5803. (cond ((bolp)
  5804. (end-of-line 0)
  5805. (setq end 1))
  5806. ((eobp)
  5807. (setq end 0)))
  5808. (when (and (> (current-column) 78)
  5809. last)
  5810. (save-excursion
  5811. (goto-char last)
  5812. (delete-char (- (skip-chars-backward " \t")))
  5813. (insert "\n\t")))
  5814. (setq last (point)))
  5815. (forward-line end)))
  5816. (defun message-fill-field-general ()
  5817. (let ((begin (point))
  5818. (fill-column 78)
  5819. (fill-prefix "\t"))
  5820. (while (and (search-forward "\n" nil t)
  5821. (not (eobp)))
  5822. (replace-match " " t t))
  5823. (fill-region-as-paragraph begin (point-max))
  5824. ;; Tapdance around looong Message-IDs.
  5825. (forward-line -1)
  5826. (when (looking-at "[ \t]*$")
  5827. (message-delete-line))
  5828. (goto-char begin)
  5829. (search-forward ":" nil t)
  5830. (when (looking-at "\n[ \t]+")
  5831. (replace-match " " t t))
  5832. (goto-char (point-max))))
  5833. (defun message-shorten-1 (list cut surplus)
  5834. "Cut SURPLUS elements out of LIST, beginning with CUTth one."
  5835. (setcdr (nthcdr (- cut 2) list)
  5836. (nthcdr (+ (- cut 2) surplus 1) list)))
  5837. (defun message-shorten-references (header references)
  5838. "Trim REFERENCES to be 21 Message-ID long or less, and fold them.
  5839. When sending via news, also check that the REFERENCES are less
  5840. than 988 characters long, and if they are not, trim them until
  5841. they are."
  5842. ;; 21 is the number suggested by USAGE.
  5843. (let ((maxcount 21)
  5844. (count 0)
  5845. (cut 2)
  5846. refs)
  5847. (with-temp-buffer
  5848. (insert references)
  5849. (goto-char (point-min))
  5850. ;; Cons a list of valid references. GNKSA says we must not include MIDs
  5851. ;; with whitespace or missing brackets (7.a "Does not propagate broken
  5852. ;; Message-IDs in original References").
  5853. (while (re-search-forward "<[^ <]+@[^ <]+>" nil t)
  5854. (push (match-string 0) refs))
  5855. (setq refs (nreverse refs)
  5856. count (length refs)))
  5857. ;; If the list has more than MAXCOUNT elements, trim it by
  5858. ;; removing the CUTth element and the required number of
  5859. ;; elements that follow.
  5860. (when (> count maxcount)
  5861. (let ((surplus (- count maxcount)))
  5862. (message-shorten-1 refs cut surplus)
  5863. (decf count surplus)))
  5864. ;; When sending via news, make sure the total folded length will
  5865. ;; be less than 998 characters. This is to cater to broken INN
  5866. ;; 2.3 which counts the total number of characters in a header
  5867. ;; rather than the physical line length of each line, as it should.
  5868. ;;
  5869. ;; This hack should be removed when it's believed than INN 2.3 is
  5870. ;; no longer widely used.
  5871. ;;
  5872. ;; At this point the headers have not been generated, thus we use
  5873. ;; message-this-is-news directly.
  5874. (when message-this-is-news
  5875. (while (< 998
  5876. (with-temp-buffer
  5877. (message-insert-header
  5878. header (mapconcat #'identity refs " "))
  5879. (buffer-size)))
  5880. (message-shorten-1 refs cut 1)))
  5881. ;; Finally, collect the references back into a string and insert
  5882. ;; it into the buffer.
  5883. (message-insert-header header (mapconcat #'identity refs " "))))
  5884. (defun message-position-point ()
  5885. "Move point to where the user probably wants to find it."
  5886. (message-narrow-to-headers)
  5887. (cond
  5888. ((re-search-forward "^[^:]+:[ \t]*$" nil t)
  5889. (search-backward ":" )
  5890. (widen)
  5891. (forward-char 1)
  5892. (if (eq (char-after) ? )
  5893. (forward-char 1)
  5894. (insert " ")))
  5895. (t
  5896. (goto-char (point-max))
  5897. (widen)
  5898. (forward-line 1)
  5899. (unless (looking-at "$")
  5900. (forward-line 2)))
  5901. (sit-for 0)))
  5902. (defcustom message-beginning-of-line t
  5903. "Whether \\<message-mode-map>\\[message-beginning-of-line]\
  5904. goes to beginning of header values."
  5905. :version "22.1"
  5906. :group 'message-buffers
  5907. :link '(custom-manual "(message)Movement")
  5908. :type 'boolean)
  5909. (defvar visual-line-mode)
  5910. (declare-function beginning-of-visual-line "simple" (&optional n))
  5911. (defun message-beginning-of-line (&optional n)
  5912. "Move point to beginning of header value or to beginning of line.
  5913. The prefix argument N is passed directly to `beginning-of-line'.
  5914. This command is identical to `beginning-of-line' if point is
  5915. outside the message header or if the option `message-beginning-of-line'
  5916. is nil.
  5917. If point is in the message header and on a (non-continued) header
  5918. line, move point to the beginning of the header value or the beginning of line,
  5919. whichever is closer. If point is already at beginning of line, move point to
  5920. beginning of header value. Therefore, repeated calls will toggle point
  5921. between beginning of field and beginning of line."
  5922. (interactive "p")
  5923. (let ((zrs 'zmacs-region-stays))
  5924. (when (and (featurep 'xemacs) (interactive-p) (boundp zrs))
  5925. (set zrs t)))
  5926. (if (and message-beginning-of-line
  5927. (message-point-in-header-p))
  5928. (let* ((here (point))
  5929. (bol (progn (beginning-of-line n) (point)))
  5930. (eol (point-at-eol))
  5931. (eoh (re-search-forward ": *" eol t)))
  5932. (goto-char
  5933. (if (and eoh (or (< eoh here) (= bol here)))
  5934. eoh bol)))
  5935. (if (and (boundp 'visual-line-mode) visual-line-mode)
  5936. (beginning-of-visual-line n)
  5937. (beginning-of-line n))))
  5938. (defun message-buffer-name (type &optional to group)
  5939. "Return a new (unique) buffer name based on TYPE and TO."
  5940. (cond
  5941. ;; Generate a new buffer name The Message Way.
  5942. ((memq message-generate-new-buffers '(unique t))
  5943. (generate-new-buffer-name
  5944. (concat "*" type
  5945. (if to
  5946. (concat " to "
  5947. (or (car (mail-extract-address-components to))
  5948. to) "")
  5949. "")
  5950. (if (and group (not (string= group ""))) (concat " on " group) "")
  5951. "*")))
  5952. ;; Check whether `message-generate-new-buffers' is a function,
  5953. ;; and if so, call it.
  5954. ((functionp message-generate-new-buffers)
  5955. (funcall message-generate-new-buffers type to group))
  5956. ((eq message-generate-new-buffers 'unsent)
  5957. (generate-new-buffer-name
  5958. (concat "*unsent " type
  5959. (if to
  5960. (concat " to "
  5961. (or (car (mail-extract-address-components to))
  5962. to) "")
  5963. "")
  5964. (if (and group (not (string= group ""))) (concat " on " group) "")
  5965. "*")))
  5966. ;; Search for the existing message buffer with the specified name.
  5967. (t
  5968. (let* ((new (if (eq message-generate-new-buffers 'standard)
  5969. (generate-new-buffer-name (concat "*" type " message*"))
  5970. (let ((message-generate-new-buffers 'unique))
  5971. (message-buffer-name type to group))))
  5972. (regexp (concat "\\`"
  5973. (regexp-quote
  5974. (if (string-match "<[0-9]+>\\'" new)
  5975. (substring new 0 (match-beginning 0))
  5976. new))
  5977. "\\(?:<\\([0-9]+\\)>\\)?\\'"))
  5978. (case-fold-search nil))
  5979. (or (cdar
  5980. (last
  5981. (sort
  5982. (delq nil
  5983. (mapcar
  5984. (lambda (b)
  5985. (when (and (string-match regexp (setq b (buffer-name b)))
  5986. (eq (with-current-buffer b major-mode)
  5987. 'message-mode))
  5988. (cons (string-to-number (or (match-string 1 b) "1"))
  5989. b)))
  5990. (buffer-list)))
  5991. 'car-less-than-car)))
  5992. new)))))
  5993. (defun message-pop-to-buffer (name &optional switch-function)
  5994. "Pop to buffer NAME, and warn if it already exists and is modified."
  5995. (let ((buffer (get-buffer name)))
  5996. (if (and buffer
  5997. (buffer-name buffer))
  5998. (let ((window (get-buffer-window buffer 0)))
  5999. (if window
  6000. ;; Raise the frame already displaying the message buffer.
  6001. (progn
  6002. (gnus-select-frame-set-input-focus (window-frame window))
  6003. (select-window window))
  6004. (funcall (or switch-function #'pop-to-buffer) buffer)
  6005. (set-buffer buffer))
  6006. (when (and (buffer-modified-p)
  6007. (not (prog1
  6008. (y-or-n-p
  6009. "Message already being composed; erase? ")
  6010. (message nil))))
  6011. (error "Message being composed")))
  6012. (funcall (or switch-function
  6013. (if (fboundp #'pop-to-buffer-same-window)
  6014. #'pop-to-buffer-same-window
  6015. #'pop-to-buffer))
  6016. name)
  6017. (set-buffer name))
  6018. (erase-buffer)
  6019. (message-mode)))
  6020. (defun message-do-send-housekeeping ()
  6021. "Kill old message buffers."
  6022. ;; We might have sent this buffer already. Delete it from the
  6023. ;; list of buffers.
  6024. (setq message-buffer-list (delq (current-buffer) message-buffer-list))
  6025. (while (and message-max-buffers
  6026. message-buffer-list
  6027. (>= (length message-buffer-list) message-max-buffers))
  6028. ;; Kill the oldest buffer -- unless it has been changed.
  6029. (let ((buffer (pop message-buffer-list)))
  6030. (when (and (buffer-name buffer)
  6031. (not (buffer-modified-p buffer)))
  6032. (kill-buffer buffer))))
  6033. ;; Rename the buffer.
  6034. (if message-send-rename-function
  6035. (funcall message-send-rename-function)
  6036. (message-default-send-rename-function))
  6037. ;; Push the current buffer onto the list.
  6038. (when message-max-buffers
  6039. (setq message-buffer-list
  6040. (nconc message-buffer-list (list (current-buffer))))))
  6041. (defun message-default-send-rename-function ()
  6042. ;; Note: mail-abbrevs of XEmacs renames buffer name behind Gnus.
  6043. (when (string-match
  6044. "\\`\\*\\(sent \\|unsent \\)?\\(.+\\)\\*[^\\*]*\\|\\`mail to "
  6045. (buffer-name))
  6046. (let ((name (match-string 2 (buffer-name)))
  6047. to group)
  6048. (if (not (or (null name)
  6049. (string-equal name "mail")
  6050. (string-equal name "posting")))
  6051. (setq name (concat "*sent " name "*"))
  6052. (message-narrow-to-headers)
  6053. (setq to (message-fetch-field "to"))
  6054. (setq group (message-fetch-field "newsgroups"))
  6055. (widen)
  6056. (setq name
  6057. (cond
  6058. (to (concat "*sent mail to "
  6059. (or (car (mail-extract-address-components to))
  6060. to) "*"))
  6061. ((and group (not (string= group "")))
  6062. (concat "*sent posting on " group "*"))
  6063. (t "*sent mail*"))))
  6064. (unless (string-equal name (buffer-name))
  6065. (rename-buffer name t)))))
  6066. (defun message-mail-user-agent ()
  6067. (let ((mua (cond
  6068. ((not message-mail-user-agent) nil)
  6069. ((eq message-mail-user-agent t) mail-user-agent)
  6070. (t message-mail-user-agent))))
  6071. (if (memq mua '(message-user-agent gnus-user-agent))
  6072. nil
  6073. mua)))
  6074. ;; YANK-ACTION, if non-nil, can be a buffer or a yank action of the
  6075. ;; form (FUNCTION . ARGS).
  6076. (defun message-setup (headers &optional yank-action actions
  6077. continue switch-function return-action)
  6078. (let ((mua (message-mail-user-agent))
  6079. subject to field)
  6080. (if (not (and message-this-is-mail mua))
  6081. (message-setup-1 headers yank-action actions return-action)
  6082. (setq headers (copy-sequence headers))
  6083. (setq field (assq 'Subject headers))
  6084. (when field
  6085. (setq subject (cdr field))
  6086. (setq headers (delq field headers)))
  6087. (setq field (assq 'To headers))
  6088. (when field
  6089. (setq to (cdr field))
  6090. (setq headers (delq field headers)))
  6091. (let ((mail-user-agent mua))
  6092. (compose-mail to subject
  6093. (mapcar (lambda (item)
  6094. (cons
  6095. (format "%s" (car item))
  6096. (cdr item)))
  6097. headers)
  6098. continue switch-function
  6099. (if (bufferp yank-action)
  6100. (list 'insert-buffer yank-action)
  6101. yank-action)
  6102. actions)))))
  6103. (defun message-headers-to-generate (headers included-headers excluded-headers)
  6104. "Return a list that includes all headers from HEADERS.
  6105. If INCLUDED-HEADERS is a list, just include those headers. If it is
  6106. t, include all headers. In any case, headers from EXCLUDED-HEADERS
  6107. are not included."
  6108. (let ((result nil)
  6109. header-name)
  6110. (dolist (header headers)
  6111. (setq header-name (cond
  6112. ((and (consp header)
  6113. (eq (car header) 'optional))
  6114. ;; On the form (optional . Header)
  6115. (cdr header))
  6116. ((consp header)
  6117. ;; On the form (Header . function)
  6118. (car header))
  6119. (t
  6120. ;; Just a Header.
  6121. header)))
  6122. (when (and (not (memq header-name excluded-headers))
  6123. (or (eq included-headers t)
  6124. (memq header-name included-headers)))
  6125. (push header result)))
  6126. (nreverse result)))
  6127. (defun message-setup-1 (headers &optional yank-action actions return-action)
  6128. (dolist (action actions)
  6129. (condition-case nil
  6130. (add-to-list 'message-send-actions
  6131. `(apply ',(car action) ',(cdr action)))))
  6132. (setq message-return-action return-action)
  6133. (setq message-reply-buffer
  6134. (if (and (consp yank-action)
  6135. (eq (car yank-action) 'insert-buffer))
  6136. (nth 1 yank-action)
  6137. yank-action))
  6138. (goto-char (point-min))
  6139. ;; Insert all the headers.
  6140. (mail-header-format
  6141. (let ((h headers)
  6142. (alist message-header-format-alist))
  6143. (while h
  6144. (unless (assq (caar h) message-header-format-alist)
  6145. (push (list (caar h)) alist))
  6146. (pop h))
  6147. alist)
  6148. headers)
  6149. (delete-region (point) (progn (forward-line -1) (point)))
  6150. (when message-default-headers
  6151. (insert
  6152. (if (functionp message-default-headers)
  6153. (funcall message-default-headers)
  6154. message-default-headers))
  6155. (or (bolp) (insert ?\n)))
  6156. (insert (concat mail-header-separator "\n"))
  6157. (forward-line -1)
  6158. ;; If a crash happens while replying, the auto-save file would *not* have a
  6159. ;; `References:' header if `message-generate-headers-first' was nil.
  6160. ;; Therefore, always generate it first.
  6161. (let ((message-generate-headers-first
  6162. (if (eq message-generate-headers-first t)
  6163. t
  6164. (append message-generate-headers-first '(References)))))
  6165. (when (message-news-p)
  6166. (when message-default-news-headers
  6167. (insert message-default-news-headers)
  6168. (or (bolp) (insert ?\n)))
  6169. (message-generate-headers
  6170. (message-headers-to-generate
  6171. (append message-required-news-headers
  6172. message-required-headers)
  6173. message-generate-headers-first
  6174. '(Lines Subject))))
  6175. (when (message-mail-p)
  6176. (when message-default-mail-headers
  6177. (insert message-default-mail-headers)
  6178. (or (bolp) (insert ?\n)))
  6179. (message-generate-headers
  6180. (message-headers-to-generate
  6181. (append message-required-mail-headers
  6182. message-required-headers)
  6183. message-generate-headers-first
  6184. '(Lines Subject)))))
  6185. (run-hooks 'message-signature-setup-hook)
  6186. (message-insert-signature)
  6187. (save-restriction
  6188. (message-narrow-to-headers)
  6189. (run-hooks 'message-header-setup-hook))
  6190. (setq buffer-undo-list nil)
  6191. (when message-generate-hashcash
  6192. ;; Generate hashcash headers for recipients already known
  6193. (mail-add-payment-async))
  6194. ;; Gnus posting styles are applied via buffer-local `message-setup-hook'
  6195. ;; values.
  6196. (run-hooks 'message-setup-hook)
  6197. ;; Do this last to give it precedence over posting styles, etc.
  6198. (when (message-mail-p)
  6199. (save-restriction
  6200. (message-narrow-to-headers)
  6201. (if message-alternative-emails
  6202. (message-use-alternative-email-as-from))))
  6203. (message-position-point)
  6204. ;; Allow correct handling of `message-checksum' in `message-yank-original':
  6205. (set-buffer-modified-p nil)
  6206. (undo-boundary)
  6207. ;; rmail-start-mail expects message-mail to return t (Bug#9392)
  6208. t)
  6209. (defun message-set-auto-save-file-name ()
  6210. "Associate the message buffer with a file in the drafts directory."
  6211. (when message-auto-save-directory
  6212. (unless (file-directory-p
  6213. (directory-file-name message-auto-save-directory))
  6214. (make-directory message-auto-save-directory t))
  6215. (if (gnus-alive-p)
  6216. (setq message-draft-article
  6217. (nndraft-request-associate-buffer "drafts"))
  6218. ;; If Gnus were alive, draft messages would be saved in the drafts folder.
  6219. ;; But Gnus is not alive, so arrange to save the draft message in a
  6220. ;; regular file in message-auto-save-directory. Append a unique
  6221. ;; time-based suffix to the filename to allow multiple drafts to be saved
  6222. ;; simultaneously without overwriting each other (which mimics the
  6223. ;; functionality of the Gnus drafts folder).
  6224. (setq buffer-file-name (expand-file-name
  6225. (concat
  6226. (if (memq system-type
  6227. '(ms-dos windows-nt cygwin))
  6228. "message"
  6229. "*message*")
  6230. (format-time-string "-%Y%m%d-%H%M%S"))
  6231. message-auto-save-directory))
  6232. (setq buffer-auto-save-file-name (make-auto-save-file-name)))
  6233. (clear-visited-file-modtime)
  6234. (setq buffer-file-coding-system message-draft-coding-system)))
  6235. (defun message-disassociate-draft ()
  6236. "Disassociate the message buffer from the drafts directory."
  6237. (when message-draft-article
  6238. (nndraft-request-expire-articles
  6239. (list message-draft-article) "drafts" nil t)))
  6240. (defun message-insert-headers ()
  6241. "Generate the headers for the article."
  6242. (interactive)
  6243. (save-excursion
  6244. (save-restriction
  6245. (message-narrow-to-headers)
  6246. (when (message-news-p)
  6247. (message-generate-headers
  6248. (delq 'Lines
  6249. (delq 'Subject
  6250. (copy-sequence message-required-news-headers)))))
  6251. (when (message-mail-p)
  6252. (message-generate-headers
  6253. (delq 'Lines
  6254. (delq 'Subject
  6255. (copy-sequence message-required-mail-headers))))))))
  6256. ;;;
  6257. ;;; Commands for interfacing with message
  6258. ;;;
  6259. ;;;###autoload
  6260. (defun message-mail (&optional to subject other-headers continue
  6261. switch-function yank-action send-actions
  6262. return-action &rest ignored)
  6263. "Start editing a mail message to be sent.
  6264. OTHER-HEADERS is an alist of header/value pairs. CONTINUE says whether
  6265. to continue editing a message already being composed. SWITCH-FUNCTION
  6266. is a function used to switch to and display the mail buffer."
  6267. (interactive)
  6268. (let ((message-this-is-mail t))
  6269. (unless (message-mail-user-agent)
  6270. (message-pop-to-buffer
  6271. ;; Search for the existing message buffer if `continue' is non-nil.
  6272. (let ((message-generate-new-buffers
  6273. (when (or (not continue)
  6274. (eq message-generate-new-buffers 'standard)
  6275. (functionp message-generate-new-buffers))
  6276. message-generate-new-buffers)))
  6277. (message-buffer-name "mail" to))
  6278. switch-function))
  6279. (message-setup
  6280. (nconc
  6281. `((To . ,(or to "")) (Subject . ,(or subject "")))
  6282. ;; C-h f compose-mail says that headers should be specified as
  6283. ;; (string . value); however all the rest of message expects
  6284. ;; headers to be symbols, not strings (eg message-header-format-alist).
  6285. ;; http://lists.gnu.org/archive/html/emacs-devel/2011-01/msg00337.html
  6286. ;; We need to convert any string input, eg from rmail-start-mail.
  6287. (dolist (h other-headers other-headers)
  6288. (if (stringp (car h)) (setcar h (intern (capitalize (car h)))))))
  6289. yank-action send-actions continue switch-function
  6290. return-action)))
  6291. ;;;###autoload
  6292. (defun message-news (&optional newsgroups subject)
  6293. "Start editing a news article to be sent."
  6294. (interactive)
  6295. (let ((message-this-is-news t))
  6296. (message-pop-to-buffer (message-buffer-name "posting" nil newsgroups))
  6297. (message-setup `((Newsgroups . ,(or newsgroups ""))
  6298. (Subject . ,(or subject ""))))))
  6299. (defun message-alter-recipients-discard-bogus-full-name (addrcell)
  6300. "Discard mail address in full names.
  6301. When the full name in reply headers contains the mail
  6302. address (e.g. \"foo@bar <foo@bar>\"), discard full name.
  6303. ADDRCELL is a cons cell where the car is the mail address and the
  6304. cdr is the complete address (full name and mail address)."
  6305. (if (string-match (concat (regexp-quote (car addrcell)) ".*"
  6306. (regexp-quote (car addrcell)))
  6307. (cdr addrcell))
  6308. (cons (car addrcell) (car addrcell))
  6309. addrcell))
  6310. (defcustom message-alter-recipients-function nil
  6311. "Function called to allow alteration of reply header structures.
  6312. It is called in `message-get-reply-headers' for each recipient.
  6313. The function is called with one parameter, a cons cell ..."
  6314. :type '(choice (const :tag "None" nil)
  6315. (const :tag "Discard bogus full name"
  6316. message-alter-recipients-discard-bogus-full-name)
  6317. function)
  6318. :version "23.1" ;; No Gnus
  6319. :group 'message-headers)
  6320. (defun message-get-reply-headers (wide &optional to-address address-headers)
  6321. (let (follow-to mct never-mct to cc author mft recipients extra)
  6322. ;; Find all relevant headers we need.
  6323. (save-restriction
  6324. (message-narrow-to-headers-or-head)
  6325. ;; Gmane renames "To". Look at "Original-To", too, if it is present in
  6326. ;; message-header-synonyms.
  6327. (setq to (or (message-fetch-field "to")
  6328. (and (loop for synonym in message-header-synonyms
  6329. when (memq 'Original-To synonym)
  6330. return t)
  6331. (message-fetch-field "original-to")))
  6332. cc (message-fetch-field "cc")
  6333. extra (when message-extra-wide-headers
  6334. (mapconcat 'identity
  6335. (mapcar 'message-fetch-field
  6336. message-extra-wide-headers)
  6337. ", "))
  6338. mct (message-fetch-field "mail-copies-to")
  6339. author (or (message-fetch-field "mail-reply-to")
  6340. (message-fetch-field "reply-to"))
  6341. mft (and message-use-mail-followup-to
  6342. (message-fetch-field "mail-followup-to")))
  6343. ;; Make sure this message goes to the author if this is a wide
  6344. ;; reply, since Reply-To address may be a list address a mailing
  6345. ;; list server added.
  6346. (when (and wide author)
  6347. (setq cc (concat author ", " cc)))
  6348. (when (or wide (not author))
  6349. (setq author (or (message-fetch-field "from") ""))))
  6350. ;; Handle special values of Mail-Copies-To.
  6351. (when mct
  6352. (cond ((or (equal (downcase mct) "never")
  6353. (equal (downcase mct) "nobody"))
  6354. (setq never-mct t)
  6355. (setq mct nil))
  6356. ((or (equal (downcase mct) "always")
  6357. (equal (downcase mct) "poster"))
  6358. (setq mct author))))
  6359. (save-match-data
  6360. ;; Build (textual) list of new recipient addresses.
  6361. (cond
  6362. (to-address
  6363. (setq recipients (concat ", " to-address))
  6364. ;; If the author explicitly asked for a copy, we don't deny it to them.
  6365. (if mct (setq recipients (concat recipients ", " mct))))
  6366. ((not wide)
  6367. (setq recipients (concat ", " author)))
  6368. (address-headers
  6369. (dolist (header address-headers)
  6370. (let ((value (message-fetch-field header)))
  6371. (when value
  6372. (setq recipients (concat recipients ", " value))))))
  6373. ((and mft
  6374. (string-match "[^ \t,]" mft)
  6375. (or (not (eq message-use-mail-followup-to 'ask))
  6376. (message-y-or-n-p "Obey Mail-Followup-To? " t "\
  6377. You should normally obey the Mail-Followup-To: header. In this
  6378. article, it has the value of
  6379. " mft "
  6380. which directs your response to " (if (string-match "," mft)
  6381. "the specified addresses"
  6382. "that address only") ".
  6383. Most commonly, Mail-Followup-To is used by a mailing list poster to
  6384. express that responses should be sent to just the list, and not the
  6385. poster as well.
  6386. If a message is posted to several mailing lists, Mail-Followup-To may
  6387. also be used to direct the following discussion to one list only,
  6388. because discussions that are spread over several lists tend to be
  6389. fragmented and very difficult to follow.
  6390. Also, some source/announcement lists are not intended for discussion;
  6391. responses here are directed to other addresses.
  6392. You may customize the variable `message-use-mail-followup-to', if you
  6393. want to get rid of this query permanently.")))
  6394. (setq recipients (concat ", " mft)))
  6395. (t
  6396. (setq recipients (if never-mct "" (concat ", " author)))
  6397. (if to (setq recipients (concat recipients ", " to)))
  6398. (if cc (setq recipients (concat recipients ", " cc)))
  6399. (if extra (setq recipients (concat recipients ", " extra)))
  6400. (if mct (setq recipients (concat recipients ", " mct)))))
  6401. (if (>= (length recipients) 2)
  6402. ;; Strip the leading ", ".
  6403. (setq recipients (substring recipients 2)))
  6404. ;; Squeeze whitespace.
  6405. (while (string-match "[ \t][ \t]+" recipients)
  6406. (setq recipients (replace-match " " t t recipients)))
  6407. ;; Remove addresses that match `mail-dont-reply-to-names'.
  6408. (let ((mail-dont-reply-to-names (message-dont-reply-to-names)))
  6409. (setq recipients (mail-dont-reply-to recipients)))
  6410. ;; Perhaps "Mail-Copies-To: never" removed the only address?
  6411. (if (string-equal recipients "")
  6412. (setq recipients author))
  6413. ;; Convert string to a list of (("foo@bar" . "Name <Foo@BAR>") ...).
  6414. (setq recipients
  6415. (mapcar
  6416. (lambda (addr)
  6417. (if message-alter-recipients-function
  6418. (funcall message-alter-recipients-function
  6419. (cons (downcase (mail-strip-quoted-names addr))
  6420. addr))
  6421. (cons (downcase (mail-strip-quoted-names addr)) addr)))
  6422. (message-tokenize-header recipients)))
  6423. ;; Remove all duplicates.
  6424. (let ((s recipients))
  6425. (while s
  6426. (let ((address (car (pop s))))
  6427. (while (assoc address s)
  6428. (setq recipients (delq (assoc address s) recipients)
  6429. s (delq (assoc address s) s))))))
  6430. ;; Remove hierarchical lists that are contained within each other,
  6431. ;; if message-hierarchical-addresses is defined.
  6432. (when message-hierarchical-addresses
  6433. (let ((plain-addrs (mapcar 'car recipients))
  6434. subaddrs recip)
  6435. (while plain-addrs
  6436. (setq subaddrs (assoc (car plain-addrs)
  6437. message-hierarchical-addresses)
  6438. plain-addrs (cdr plain-addrs))
  6439. (when subaddrs
  6440. (setq subaddrs (cdr subaddrs))
  6441. (while subaddrs
  6442. (setq recip (assoc (car subaddrs) recipients)
  6443. subaddrs (cdr subaddrs))
  6444. (if recip
  6445. (setq recipients (delq recip recipients))))))))
  6446. (setq recipients (message-prune-recipients recipients))
  6447. ;; Build the header alist. Allow the user to be asked whether
  6448. ;; or not to reply to all recipients in a wide reply.
  6449. (setq follow-to (list (cons 'To (cdr (pop recipients)))))
  6450. (when (and recipients
  6451. (or (not message-wide-reply-confirm-recipients)
  6452. (y-or-n-p "Reply to all recipients? ")))
  6453. (setq recipients (mapconcat
  6454. (lambda (addr) (cdr addr)) recipients ", "))
  6455. (if (string-match "^ +" recipients)
  6456. (setq recipients (substring recipients (match-end 0))))
  6457. (push (cons 'Cc recipients) follow-to)))
  6458. follow-to))
  6459. (defun message-prune-recipients (recipients)
  6460. (dolist (rule message-prune-recipient-rules)
  6461. (let ((match (car rule))
  6462. dup-match
  6463. address)
  6464. (dolist (recipient recipients)
  6465. (setq address (car recipient))
  6466. (when (string-match match address)
  6467. (setq dup-match (replace-match (cadr rule) nil nil address))
  6468. (dolist (recipient recipients)
  6469. ;; Don't delete the address that triggered this.
  6470. (when (and (not (eq address (car recipient)))
  6471. (string-match dup-match (car recipient)))
  6472. (setq recipients (delq recipient recipients))))))))
  6473. recipients)
  6474. (defcustom message-simplify-subject-functions
  6475. '(message-strip-list-identifiers
  6476. message-strip-subject-re
  6477. message-strip-subject-trailing-was
  6478. message-strip-subject-encoded-words)
  6479. "List of functions taking a string argument that simplify subjects.
  6480. The functions are applied when replying to a message.
  6481. Useful functions to put in this list include:
  6482. `message-strip-list-identifiers', `message-strip-subject-re',
  6483. `message-strip-subject-trailing-was', and
  6484. `message-strip-subject-encoded-words'."
  6485. :version "22.1" ;; Gnus 5.10.9
  6486. :group 'message-various
  6487. :type '(repeat function))
  6488. (defun message-simplify-subject (subject &optional functions)
  6489. "Return simplified SUBJECT."
  6490. (unless functions
  6491. ;; Simplify fully:
  6492. (setq functions message-simplify-subject-functions))
  6493. (when (and (memq 'message-strip-list-identifiers functions)
  6494. gnus-list-identifiers)
  6495. (setq subject (message-strip-list-identifiers subject)))
  6496. (when (memq 'message-strip-subject-re functions)
  6497. (setq subject (concat "Re: " (message-strip-subject-re subject))))
  6498. (when (and (memq 'message-strip-subject-trailing-was functions)
  6499. message-subject-trailing-was-query)
  6500. (setq subject (message-strip-subject-trailing-was subject)))
  6501. (when (memq 'message-strip-subject-encoded-words functions)
  6502. (setq subject (message-strip-subject-encoded-words subject)))
  6503. subject)
  6504. ;;;###autoload
  6505. (defun message-reply (&optional to-address wide switch-function)
  6506. "Start editing a reply to the article in the current buffer."
  6507. (interactive)
  6508. (require 'gnus-sum) ; for gnus-list-identifiers
  6509. (let ((cur (current-buffer))
  6510. from subject date
  6511. references message-id follow-to
  6512. (inhibit-point-motion-hooks t)
  6513. (message-this-is-mail t)
  6514. gnus-warning)
  6515. (save-restriction
  6516. (message-narrow-to-head-1)
  6517. ;; Allow customizations to have their say.
  6518. (if (not wide)
  6519. ;; This is a regular reply.
  6520. (when (functionp message-reply-to-function)
  6521. (save-excursion
  6522. (setq follow-to (funcall message-reply-to-function))))
  6523. ;; This is a followup.
  6524. (when (functionp message-wide-reply-to-function)
  6525. (save-excursion
  6526. (setq follow-to
  6527. (funcall message-wide-reply-to-function)))))
  6528. (setq message-id (message-fetch-field "message-id" t)
  6529. references (message-fetch-field "references")
  6530. date (message-fetch-field "date")
  6531. from (or (message-fetch-field "from") "nobody")
  6532. subject (or (message-fetch-field "subject") "none"))
  6533. ;; Strip list identifiers, "Re: ", and "was:"
  6534. (setq subject (message-simplify-subject subject))
  6535. (when (and (setq gnus-warning (message-fetch-field "gnus-warning"))
  6536. (string-match "<[^>]+>" gnus-warning))
  6537. (setq message-id (match-string 0 gnus-warning)))
  6538. (unless follow-to
  6539. (setq follow-to (message-get-reply-headers wide to-address))))
  6540. (let ((headers
  6541. `((Subject . ,subject)
  6542. ,@follow-to)))
  6543. (unless (message-mail-user-agent)
  6544. (message-pop-to-buffer
  6545. (message-buffer-name
  6546. (if wide "wide reply" "reply") from
  6547. (if wide to-address nil))
  6548. switch-function))
  6549. (setq message-reply-headers
  6550. (vector 0 (cdr (assq 'Subject headers))
  6551. from date message-id references 0 0 ""))
  6552. (message-setup headers cur))))
  6553. ;;;###autoload
  6554. (defun message-wide-reply (&optional to-address)
  6555. "Make a \"wide\" reply to the message in the current buffer."
  6556. (interactive)
  6557. (message-reply to-address t))
  6558. ;;;###autoload
  6559. (defun message-followup (&optional to-newsgroups)
  6560. "Follow up to the message in the current buffer.
  6561. If TO-NEWSGROUPS, use that as the new Newsgroups line."
  6562. (interactive)
  6563. (require 'gnus-sum) ; for gnus-list-identifiers
  6564. (let ((cur (current-buffer))
  6565. from subject date reply-to mrt mct
  6566. references message-id follow-to
  6567. (inhibit-point-motion-hooks t)
  6568. (message-this-is-news t)
  6569. followup-to distribution newsgroups gnus-warning posted-to)
  6570. (save-restriction
  6571. (narrow-to-region
  6572. (goto-char (point-min))
  6573. (if (search-forward "\n\n" nil t)
  6574. (1- (point))
  6575. (point-max)))
  6576. (when (functionp message-followup-to-function)
  6577. (setq follow-to
  6578. (funcall message-followup-to-function)))
  6579. (setq from (message-fetch-field "from")
  6580. date (message-fetch-field "date")
  6581. subject (or (message-fetch-field "subject") "none")
  6582. references (message-fetch-field "references")
  6583. message-id (message-fetch-field "message-id" t)
  6584. followup-to (message-fetch-field "followup-to")
  6585. newsgroups (message-fetch-field "newsgroups")
  6586. posted-to (message-fetch-field "posted-to")
  6587. reply-to (message-fetch-field "reply-to")
  6588. mrt (message-fetch-field "mail-reply-to")
  6589. distribution (message-fetch-field "distribution")
  6590. mct (message-fetch-field "mail-copies-to"))
  6591. (when (and (setq gnus-warning (message-fetch-field "gnus-warning"))
  6592. (string-match "<[^>]+>" gnus-warning))
  6593. (setq message-id (match-string 0 gnus-warning)))
  6594. ;; Remove bogus distribution.
  6595. (when (and (stringp distribution)
  6596. (let ((case-fold-search t))
  6597. (string-match "world" distribution)))
  6598. (setq distribution nil))
  6599. ;; Strip list identifiers, "Re: ", and "was:"
  6600. (setq subject (message-simplify-subject subject))
  6601. (widen))
  6602. (message-pop-to-buffer (message-buffer-name "followup" from newsgroups))
  6603. (setq message-reply-headers
  6604. (vector 0 subject from date message-id references 0 0 ""))
  6605. (message-setup
  6606. `((Subject . ,subject)
  6607. ,@(cond
  6608. (to-newsgroups
  6609. (list (cons 'Newsgroups to-newsgroups)))
  6610. (follow-to follow-to)
  6611. ((and followup-to message-use-followup-to)
  6612. (list
  6613. (cond
  6614. ((equal (downcase followup-to) "poster")
  6615. (if (or (eq message-use-followup-to 'use)
  6616. (message-y-or-n-p "Obey Followup-To: poster? " t "\
  6617. You should normally obey the Followup-To: header.
  6618. `Followup-To: poster' sends your response via e-mail instead of news.
  6619. A typical situation where `Followup-To: poster' is used is when the poster
  6620. does not read the newsgroup, so he wouldn't see any replies sent to it.
  6621. You may customize the variable `message-use-followup-to', if you
  6622. want to get rid of this query permanently."))
  6623. (progn
  6624. (setq message-this-is-news nil)
  6625. (cons 'To (or mrt reply-to from "")))
  6626. (cons 'Newsgroups newsgroups)))
  6627. (t
  6628. (if (or (equal followup-to newsgroups)
  6629. (not (eq message-use-followup-to 'ask))
  6630. (message-y-or-n-p
  6631. (concat "Obey Followup-To: " followup-to "? ") t "\
  6632. You should normally obey the Followup-To: header.
  6633. `Followup-To: " followup-to "'
  6634. directs your response to " (if (string-match "," followup-to)
  6635. "the specified newsgroups"
  6636. "that newsgroup only") ".
  6637. If a message is posted to several newsgroups, Followup-To is often
  6638. used to direct the following discussion to one newsgroup only,
  6639. because discussions that are spread over several newsgroup tend to
  6640. be fragmented and very difficult to follow.
  6641. Also, some source/announcement newsgroups are not intended for discussion;
  6642. responses here are directed to other newsgroups.
  6643. You may customize the variable `message-use-followup-to', if you
  6644. want to get rid of this query permanently."))
  6645. (cons 'Newsgroups followup-to)
  6646. (cons 'Newsgroups newsgroups))))))
  6647. (posted-to
  6648. `((Newsgroups . ,posted-to)))
  6649. (t
  6650. `((Newsgroups . ,newsgroups))))
  6651. ,@(and distribution (list (cons 'Distribution distribution)))
  6652. ,@(when (and mct
  6653. (not (or (equal (downcase mct) "never")
  6654. (equal (downcase mct) "nobody"))))
  6655. (list (cons 'Cc (if (or (equal (downcase mct) "always")
  6656. (equal (downcase mct) "poster"))
  6657. (or mrt reply-to from "")
  6658. mct)))))
  6659. cur)))
  6660. (defun message-is-yours-p ()
  6661. "Non-nil means current article is yours.
  6662. If you have added `cancel-messages' to `message-shoot-gnksa-feet', all articles
  6663. are yours except those that have Cancel-Lock header not belonging to you.
  6664. Instead of shooting GNKSA feet, you should modify `message-alternative-emails'
  6665. regexp to match all of yours addresses."
  6666. ;; Canlock-logic as suggested by Per Abrahamsen
  6667. ;; <abraham@dina.kvl.dk>
  6668. ;;
  6669. ;; IF article has cancel-lock THEN
  6670. ;; IF we can verify it THEN
  6671. ;; issue cancel
  6672. ;; ELSE
  6673. ;; error: cancellock: article is not yours
  6674. ;; ELSE
  6675. ;; Use old rules, comparing sender...
  6676. (save-excursion
  6677. (save-restriction
  6678. (message-narrow-to-head-1)
  6679. (if (and (message-fetch-field "Cancel-Lock")
  6680. (message-gnksa-enable-p 'canlock-verify))
  6681. (if (null (canlock-verify))
  6682. t
  6683. (error "Failed to verify Cancel-lock: This article is not yours"))
  6684. (let (sender from)
  6685. (or
  6686. (message-gnksa-enable-p 'cancel-messages)
  6687. (and (setq sender (message-fetch-field "sender"))
  6688. (string-equal (downcase sender)
  6689. (downcase (message-make-sender))))
  6690. ;; Email address in From field equals to our address
  6691. (and (setq from (message-fetch-field "from"))
  6692. (string-equal
  6693. (downcase (car (mail-header-parse-address from)))
  6694. (downcase (car (mail-header-parse-address
  6695. (message-make-from))))))
  6696. ;; Email address in From field matches
  6697. ;; 'message-alternative-emails' regexp
  6698. (and from
  6699. message-alternative-emails
  6700. (string-match
  6701. message-alternative-emails
  6702. (car (mail-header-parse-address from))))))))))
  6703. ;;;###autoload
  6704. (defun message-cancel-news (&optional arg)
  6705. "Cancel an article you posted.
  6706. If ARG, allow editing of the cancellation message."
  6707. (interactive "P")
  6708. (unless (message-news-p)
  6709. (error "This is not a news article; canceling is impossible"))
  6710. (let (from newsgroups message-id distribution buf)
  6711. (save-excursion
  6712. ;; Get header info from original article.
  6713. (save-restriction
  6714. (message-narrow-to-head-1)
  6715. (setq from (message-fetch-field "from")
  6716. newsgroups (message-fetch-field "newsgroups")
  6717. message-id (message-fetch-field "message-id" t)
  6718. distribution (message-fetch-field "distribution")))
  6719. ;; Make sure that this article was written by the user.
  6720. (unless (message-is-yours-p)
  6721. (error "This article is not yours"))
  6722. (when (yes-or-no-p "Do you really want to cancel this article? ")
  6723. ;; Make control message.
  6724. (if arg
  6725. (message-news)
  6726. (setq buf (set-buffer (get-buffer-create " *message cancel*"))))
  6727. (erase-buffer)
  6728. (insert "Newsgroups: " newsgroups "\n"
  6729. "From: " from "\n"
  6730. "Subject: cancel " message-id "\n"
  6731. "Control: cancel " message-id "\n"
  6732. (if distribution
  6733. (concat "Distribution: " distribution "\n")
  6734. "")
  6735. mail-header-separator "\n"
  6736. message-cancel-message)
  6737. (run-hooks 'message-cancel-hook)
  6738. (unless arg
  6739. (message "Canceling your article...")
  6740. (if (let ((message-syntax-checks
  6741. 'dont-check-for-anything-just-trust-me))
  6742. (funcall message-send-news-function))
  6743. (message "Canceling your article...done"))
  6744. (kill-buffer buf))))))
  6745. ;;;###autoload
  6746. (defun message-supersede ()
  6747. "Start composing a message to supersede the current message.
  6748. This is done simply by taking the old article and adding a Supersedes
  6749. header line with the old Message-ID."
  6750. (interactive)
  6751. (let ((cur (current-buffer)))
  6752. ;; Check whether the user owns the article that is to be superseded.
  6753. (unless (message-is-yours-p)
  6754. (error "This article is not yours"))
  6755. ;; Get a normal message buffer.
  6756. (message-pop-to-buffer (message-buffer-name "supersede"))
  6757. (insert-buffer-substring cur)
  6758. (mime-to-mml)
  6759. (message-narrow-to-head-1)
  6760. ;; Remove unwanted headers.
  6761. (when message-ignored-supersedes-headers
  6762. (message-remove-header message-ignored-supersedes-headers t))
  6763. (goto-char (point-min))
  6764. (if (not (re-search-forward "^Message-ID: " nil t))
  6765. (error "No Message-ID in this article")
  6766. (replace-match "Supersedes: " t t))
  6767. (goto-char (point-max))
  6768. (insert mail-header-separator)
  6769. (widen)
  6770. (forward-line 1)))
  6771. ;;;###autoload
  6772. (defun message-recover ()
  6773. "Reread contents of current buffer from its last auto-save file."
  6774. (interactive)
  6775. (let ((file-name (make-auto-save-file-name)))
  6776. (cond ((save-window-excursion
  6777. (with-output-to-temp-buffer "*Directory*"
  6778. (with-current-buffer standard-output
  6779. (fundamental-mode)) ; for Emacs 20.4+
  6780. (buffer-disable-undo standard-output)
  6781. (let ((default-directory "/"))
  6782. (call-process
  6783. "ls" nil standard-output nil "-l" file-name)))
  6784. (yes-or-no-p (format "Recover auto save file %s? " file-name)))
  6785. (let ((buffer-read-only nil))
  6786. (erase-buffer)
  6787. (insert-file-contents file-name nil)))
  6788. (t (error "message-recover canceled")))))
  6789. ;;; Washing Subject:
  6790. (defun message-wash-subject (subject)
  6791. "Remove junk like \"Re:\", \"(fwd)\", etc. added to subject string SUBJECT.
  6792. Previous forwarders, repliers, etc. may add it."
  6793. (with-temp-buffer
  6794. (insert subject)
  6795. (goto-char (point-min))
  6796. ;; strip Re/Fwd stuff off the beginning
  6797. (while (re-search-forward
  6798. "\\([Rr][Ee]:\\|[Ff][Ww][Dd]\\(\\[[0-9]*\\]\\)?:\\|[Ff][Ww]:\\)" nil t)
  6799. (replace-match ""))
  6800. ;; and gnus-style forwards [foo@bar.com] subject
  6801. (goto-char (point-min))
  6802. (while (re-search-forward "\\[[^ \t]*\\(@\\|\\.\\)[^ \t]*\\]" nil t)
  6803. (replace-match ""))
  6804. ;; and off the end
  6805. (goto-char (point-max))
  6806. (while (re-search-backward "([Ff][Ww][Dd])" nil t)
  6807. (replace-match ""))
  6808. ;; and finally, any whitespace that was left-over
  6809. (goto-char (point-min))
  6810. (while (re-search-forward "^[ \t]+" nil t)
  6811. (replace-match ""))
  6812. (goto-char (point-max))
  6813. (while (re-search-backward "[ \t]+$" nil t)
  6814. (replace-match ""))
  6815. (buffer-string)))
  6816. ;;; Forwarding messages.
  6817. (defvar message-forward-decoded-p nil
  6818. "Non-nil means the original message is decoded.")
  6819. (defun message-forward-subject-name-subject (subject)
  6820. "Generate a SUBJECT for a forwarded message.
  6821. The form is: [Source] Subject, where if the original message was mail,
  6822. Source is the name of the sender, and if the original message was
  6823. news, Source is the list of newsgroups is was posted to."
  6824. (let* ((group (message-fetch-field "newsgroups"))
  6825. (from (message-fetch-field "from"))
  6826. (prefix
  6827. (if group
  6828. (gnus-group-decoded-name group)
  6829. (or (and from (or
  6830. (car (gnus-extract-address-components from))
  6831. (cadr (gnus-extract-address-components from))))
  6832. "(nowhere)"))))
  6833. (concat "["
  6834. (if message-forward-decoded-p
  6835. prefix
  6836. (mail-decode-encoded-word-string prefix))
  6837. "] " subject)))
  6838. (defun message-forward-subject-author-subject (subject)
  6839. "Generate a SUBJECT for a forwarded message.
  6840. The form is: [Source] Subject, where if the original message was mail,
  6841. Source is the sender, and if the original message was news, Source is
  6842. the list of newsgroups is was posted to."
  6843. (let* ((group (message-fetch-field "newsgroups"))
  6844. (prefix
  6845. (if group
  6846. (gnus-group-decoded-name group)
  6847. (or (message-fetch-field "from")
  6848. "(nowhere)"))))
  6849. (concat "["
  6850. (if message-forward-decoded-p
  6851. prefix
  6852. (mail-decode-encoded-word-string prefix))
  6853. "] " subject)))
  6854. (defun message-forward-subject-fwd (subject)
  6855. "Generate a SUBJECT for a forwarded message.
  6856. The form is: Fwd: Subject, where Subject is the original subject of
  6857. the message."
  6858. (if (string-match "^Fwd: " subject)
  6859. subject
  6860. (concat "Fwd: " subject)))
  6861. (defun message-make-forward-subject ()
  6862. "Return a Subject header suitable for the message in the current buffer."
  6863. (save-excursion
  6864. (save-restriction
  6865. (message-narrow-to-head-1)
  6866. (let ((funcs message-make-forward-subject-function)
  6867. (subject (message-fetch-field "Subject")))
  6868. (setq subject
  6869. (if subject
  6870. (if message-forward-decoded-p
  6871. subject
  6872. (mail-decode-encoded-word-string subject))
  6873. ""))
  6874. (when message-wash-forwarded-subjects
  6875. (setq subject (message-wash-subject subject)))
  6876. ;; Make sure funcs is a list.
  6877. (and funcs
  6878. (not (listp funcs))
  6879. (setq funcs (list funcs)))
  6880. ;; Apply funcs in order, passing subject generated by previous
  6881. ;; func to the next one.
  6882. (dolist (func funcs)
  6883. (when (functionp func)
  6884. (setq subject (funcall func subject))))
  6885. subject))))
  6886. (defvar gnus-article-decoded-p)
  6887. ;;;###autoload
  6888. (defun message-forward (&optional news digest)
  6889. "Forward the current message via mail.
  6890. Optional NEWS will use news to forward instead of mail.
  6891. Optional DIGEST will use digest to forward."
  6892. (interactive "P")
  6893. (let* ((cur (current-buffer))
  6894. (message-forward-decoded-p
  6895. (if (local-variable-p 'gnus-article-decoded-p (current-buffer))
  6896. gnus-article-decoded-p ;; In an article buffer.
  6897. message-forward-decoded-p))
  6898. (subject (message-make-forward-subject)))
  6899. (if news
  6900. (message-news nil subject)
  6901. (message-mail nil subject))
  6902. (message-forward-make-body cur digest)))
  6903. (defun message-forward-make-body-plain (forward-buffer)
  6904. (insert
  6905. "\n-------------------- Start of forwarded message --------------------\n")
  6906. (let ((b (point))
  6907. (contents (with-current-buffer forward-buffer (buffer-string)))
  6908. e)
  6909. (unless (featurep 'xemacs)
  6910. (unless (mm-multibyte-string-p contents)
  6911. (error "Attempt to insert unibyte string from the buffer \"%s\"\
  6912. to the multibyte buffer \"%s\""
  6913. (if (bufferp forward-buffer)
  6914. (buffer-name forward-buffer)
  6915. forward-buffer)
  6916. (buffer-name))))
  6917. (insert (mm-with-multibyte-buffer
  6918. (insert contents)
  6919. (mime-to-mml)
  6920. (goto-char (point-min))
  6921. (when (looking-at "From ")
  6922. (replace-match "X-From-Line: "))
  6923. (buffer-string)))
  6924. (unless (bolp) (insert "\n"))
  6925. (setq e (point))
  6926. (insert
  6927. "-------------------- End of forwarded message --------------------\n")
  6928. (message-remove-ignored-headers b e)))
  6929. (defun message-remove-ignored-headers (b e)
  6930. (when (or message-forward-ignored-headers
  6931. message-forward-included-headers)
  6932. (save-restriction
  6933. (narrow-to-region b e)
  6934. (goto-char b)
  6935. (narrow-to-region (point)
  6936. (or (search-forward "\n\n" nil t) (point)))
  6937. (when message-forward-ignored-headers
  6938. (let ((ignored (if (stringp message-forward-ignored-headers)
  6939. (list message-forward-ignored-headers)
  6940. message-forward-ignored-headers)))
  6941. (dolist (elem ignored)
  6942. (message-remove-header elem t))))
  6943. (when message-forward-included-headers
  6944. (message-remove-header
  6945. (if (listp message-forward-included-headers)
  6946. (regexp-opt message-forward-included-headers)
  6947. message-forward-included-headers)
  6948. t nil t)))))
  6949. (defun message-forward-make-body-mime (forward-buffer &optional beg end)
  6950. (let ((b (point)))
  6951. (insert "\n\n<#part type=message/rfc822 disposition=inline raw=t>\n")
  6952. (save-restriction
  6953. (narrow-to-region (point) (point))
  6954. (insert-buffer-substring forward-buffer beg end)
  6955. (mml-quote-region (point-min) (point-max))
  6956. (goto-char (point-min))
  6957. (when (looking-at "From ")
  6958. (replace-match "X-From-Line: "))
  6959. (goto-char (point-max)))
  6960. (insert "<#/part>\n")
  6961. ;; Consider there is no illegible text.
  6962. (add-text-properties
  6963. b (point)
  6964. `(no-illegible-text t rear-nonsticky t start-open t))))
  6965. (defun message-forward-make-body-mml (forward-buffer)
  6966. (insert "\n\n<#mml type=message/rfc822 disposition=inline>\n")
  6967. (let ((b (point)) e)
  6968. (if (not message-forward-decoded-p)
  6969. (let ((contents (with-current-buffer forward-buffer (buffer-string))))
  6970. (unless (featurep 'xemacs)
  6971. (unless (mm-multibyte-string-p contents)
  6972. (error "Attempt to insert unibyte string from the buffer \"%s\"\
  6973. to the multibyte buffer \"%s\""
  6974. (if (bufferp forward-buffer)
  6975. (buffer-name forward-buffer)
  6976. forward-buffer)
  6977. (buffer-name))))
  6978. (insert (mm-with-multibyte-buffer
  6979. (insert contents)
  6980. (mime-to-mml)
  6981. (goto-char (point-min))
  6982. (when (looking-at "From ")
  6983. (replace-match "X-From-Line: "))
  6984. (buffer-string))))
  6985. (save-restriction
  6986. (narrow-to-region (point) (point))
  6987. (mml-insert-buffer forward-buffer)
  6988. (goto-char (point-min))
  6989. (when (looking-at "From ")
  6990. (replace-match "X-From-Line: "))
  6991. (goto-char (point-max))))
  6992. (setq e (point))
  6993. (insert "<#/mml>\n")
  6994. (when (not message-forward-decoded-p)
  6995. (message-remove-ignored-headers b e))))
  6996. (defun message-forward-make-body-digest-plain (forward-buffer)
  6997. (insert
  6998. "\n-------------------- Start of forwarded message --------------------\n")
  6999. (mml-insert-buffer forward-buffer)
  7000. (insert
  7001. "\n-------------------- End of forwarded message --------------------\n"))
  7002. (defun message-forward-make-body-digest-mime (forward-buffer)
  7003. (insert "\n<#multipart type=digest>\n")
  7004. (let ((b (point)) e)
  7005. (insert-buffer-substring forward-buffer)
  7006. (setq e (point))
  7007. (insert "<#/multipart>\n")
  7008. (save-restriction
  7009. (narrow-to-region b e)
  7010. (goto-char b)
  7011. (narrow-to-region (point)
  7012. (or (search-forward "\n\n" nil t) (point)))
  7013. (delete-region (point-min) (point-max)))))
  7014. (defun message-forward-make-body-digest (forward-buffer)
  7015. (if message-forward-as-mime
  7016. (message-forward-make-body-digest-mime forward-buffer)
  7017. (message-forward-make-body-digest-plain forward-buffer)))
  7018. (autoload 'mm-uu-dissect-text-parts "mm-uu")
  7019. (autoload 'mm-uu-dissect "mm-uu")
  7020. (defun message-signed-or-encrypted-p (&optional dont-emulate-mime handles)
  7021. "Say whether the current buffer contains signed or encrypted message.
  7022. If DONT-EMULATE-MIME is nil, this function does the MIME emulation on
  7023. messages that don't conform to PGP/MIME described in RFC2015. HANDLES
  7024. is for the internal use."
  7025. (unless handles
  7026. (let ((mm-decrypt-option 'never)
  7027. (mm-verify-option 'never))
  7028. (if (setq handles (mm-dissect-buffer nil t))
  7029. (unless dont-emulate-mime
  7030. (mm-uu-dissect-text-parts handles))
  7031. (unless dont-emulate-mime
  7032. (setq handles (mm-uu-dissect))))))
  7033. ;; Check text/plain message in which there is a signed or encrypted
  7034. ;; body that has been encoded by B or Q.
  7035. (unless (or handles dont-emulate-mime)
  7036. (let ((cur (current-buffer))
  7037. (mm-decrypt-option 'never)
  7038. (mm-verify-option 'never))
  7039. (with-temp-buffer
  7040. (insert-buffer-substring cur)
  7041. (when (setq handles (mm-dissect-buffer t t))
  7042. (if (and (bufferp (car handles))
  7043. (equal (mm-handle-media-type handles) "text/plain"))
  7044. (progn
  7045. (erase-buffer)
  7046. (insert-buffer-substring (car handles))
  7047. (mm-decode-content-transfer-encoding
  7048. (mm-handle-encoding handles))
  7049. (mm-destroy-parts handles)
  7050. (setq handles (mm-uu-dissect)))
  7051. (mm-destroy-parts handles)
  7052. (setq handles nil))))))
  7053. (when handles
  7054. (prog1
  7055. (catch 'found
  7056. (dolist (handle (if (stringp (car handles))
  7057. (if (member (car handles)
  7058. '("multipart/signed"
  7059. "multipart/encrypted"))
  7060. (throw 'found t)
  7061. (cdr handles))
  7062. (list handles)))
  7063. (if (stringp (car handle))
  7064. (when (message-signed-or-encrypted-p dont-emulate-mime handle)
  7065. (throw 'found t))
  7066. (when (and (bufferp (car handle))
  7067. (equal (mm-handle-media-type handle)
  7068. "message/rfc822"))
  7069. (with-current-buffer (mm-handle-buffer handle)
  7070. (when (message-signed-or-encrypted-p dont-emulate-mime)
  7071. (throw 'found t)))))))
  7072. (mm-destroy-parts handles))))
  7073. ;;;###autoload
  7074. (defun message-forward-make-body (forward-buffer &optional digest)
  7075. ;; Put point where we want it before inserting the forwarded
  7076. ;; message.
  7077. (if message-forward-before-signature
  7078. (message-goto-body)
  7079. (goto-char (point-max)))
  7080. (if digest
  7081. (message-forward-make-body-digest forward-buffer)
  7082. (if message-forward-as-mime
  7083. (if (and message-forward-show-mml
  7084. (not (and (eq message-forward-show-mml 'best)
  7085. ;; Use the raw form in the body if it contains
  7086. ;; signed or encrypted message so as not to be
  7087. ;; destroyed by re-encoding.
  7088. (with-current-buffer forward-buffer
  7089. (condition-case nil
  7090. (message-signed-or-encrypted-p)
  7091. (error t))))))
  7092. (message-forward-make-body-mml forward-buffer)
  7093. (message-forward-make-body-mime forward-buffer))
  7094. (message-forward-make-body-plain forward-buffer)))
  7095. (message-position-point))
  7096. (declare-function rmail-toggle-header "rmail" (&optional arg))
  7097. ;;;###autoload
  7098. (defun message-forward-rmail-make-body (forward-buffer)
  7099. (save-window-excursion
  7100. (set-buffer forward-buffer)
  7101. (if (rmail-msg-is-pruned)
  7102. (if (fboundp 'rmail-msg-restore-non-pruned-header)
  7103. (rmail-msg-restore-non-pruned-header) ; Emacs 22
  7104. (rmail-toggle-header 0)))) ; Emacs 23
  7105. (message-forward-make-body forward-buffer))
  7106. ;; Fixme: Should have defcustom.
  7107. ;;;###autoload
  7108. (defun message-insinuate-rmail ()
  7109. "Let RMAIL use message to forward."
  7110. (interactive)
  7111. (setq rmail-enable-mime-composing t)
  7112. (setq rmail-insert-mime-forwarded-message-function
  7113. 'message-forward-rmail-make-body))
  7114. (defvar message-inhibit-body-encoding nil)
  7115. ;;;###autoload
  7116. (defun message-resend (address)
  7117. "Resend the current article to ADDRESS."
  7118. (interactive
  7119. (list (message-read-from-minibuffer "Resend message to: ")))
  7120. (message "Resending message to %s..." address)
  7121. (save-excursion
  7122. (let ((cur (current-buffer))
  7123. gcc beg)
  7124. ;; We first set up a normal mail buffer.
  7125. (unless (message-mail-user-agent)
  7126. (set-buffer (get-buffer-create " *message resend*"))
  7127. (let ((inhibit-read-only t))
  7128. (erase-buffer)))
  7129. (let ((message-this-is-mail t)
  7130. message-generate-hashcash
  7131. message-setup-hook)
  7132. (message-setup `((To . ,address))))
  7133. ;; Insert our usual headers.
  7134. (message-generate-headers '(From Date To Message-ID))
  7135. (message-narrow-to-headers)
  7136. (when (setq gcc (mail-fetch-field "gcc" nil t))
  7137. (message-remove-header "gcc"))
  7138. ;; Remove X-Draft-From header etc.
  7139. (message-remove-header message-ignored-mail-headers t)
  7140. ;; Rename them all to "Resent-*".
  7141. (goto-char (point-min))
  7142. (while (re-search-forward "^[A-Za-z]" nil t)
  7143. (forward-char -1)
  7144. (insert "Resent-"))
  7145. (widen)
  7146. (forward-line)
  7147. (let ((inhibit-read-only t))
  7148. (delete-region (point) (point-max)))
  7149. (setq beg (point))
  7150. ;; Insert the message to be resent.
  7151. (insert-buffer-substring cur)
  7152. (goto-char (point-min))
  7153. (search-forward "\n\n")
  7154. (forward-char -1)
  7155. (save-restriction
  7156. (narrow-to-region beg (point))
  7157. (message-remove-header message-ignored-resent-headers t)
  7158. (goto-char (point-max)))
  7159. (insert mail-header-separator)
  7160. ;; Rename all old ("Also-")Resent headers.
  7161. (while (re-search-backward "^\\(Also-\\)*Resent-" beg t)
  7162. (beginning-of-line)
  7163. (insert "Also-"))
  7164. ;; Quote any "From " lines at the beginning.
  7165. (goto-char beg)
  7166. (when (looking-at "From ")
  7167. (replace-match "X-From-Line: "))
  7168. ;; Send it.
  7169. (let ((message-inhibit-body-encoding
  7170. ;; Don't do any further encoding if it looks like the
  7171. ;; message has already been encoded.
  7172. (let ((case-fold-search t))
  7173. (re-search-forward "^mime-version:" nil t)))
  7174. (message-inhibit-ecomplete t)
  7175. message-required-mail-headers
  7176. message-generate-hashcash
  7177. rfc2047-encode-encoded-words)
  7178. (message-send-mail))
  7179. (when gcc
  7180. (message-goto-eoh)
  7181. (insert "Gcc: " gcc "\n"))
  7182. (run-hooks 'message-sent-hook)
  7183. (kill-buffer (current-buffer)))
  7184. (message "Resending message to %s...done" address)))
  7185. ;;;###autoload
  7186. (defun message-bounce ()
  7187. "Re-mail the current message.
  7188. This only makes sense if the current message is a bounce message that
  7189. contains some mail you have written which has been bounced back to
  7190. you."
  7191. (interactive)
  7192. (let ((handles (mm-dissect-buffer t))
  7193. boundary)
  7194. (message-pop-to-buffer (message-buffer-name "bounce"))
  7195. (if (stringp (car handles))
  7196. ;; This is a MIME bounce.
  7197. (mm-insert-part (car (last handles)))
  7198. ;; This is a non-MIME bounce, so we try to remove things
  7199. ;; manually.
  7200. (mm-insert-part handles)
  7201. (undo-boundary)
  7202. (goto-char (point-min))
  7203. (re-search-forward "\n\n+" nil t)
  7204. (setq boundary (point))
  7205. ;; We remove everything before the bounced mail.
  7206. (if (or (re-search-forward message-unsent-separator nil t)
  7207. (progn
  7208. (search-forward "\n\n" nil 'move)
  7209. (re-search-backward "^Return-Path:.*\n" boundary t)))
  7210. (progn
  7211. (forward-line 1)
  7212. (delete-region (point-min)
  7213. (if (re-search-forward "^[^ \n\t]+:" nil t)
  7214. (match-beginning 0)
  7215. (point))))
  7216. (goto-char boundary)
  7217. (when (re-search-backward "^.?From .*\n" nil t)
  7218. (delete-region (match-beginning 0) (match-end 0)))))
  7219. (mime-to-mml)
  7220. (save-restriction
  7221. (message-narrow-to-head-1)
  7222. (message-remove-header message-ignored-bounced-headers t)
  7223. (goto-char (point-max))
  7224. (insert mail-header-separator))
  7225. (message-position-point)))
  7226. ;;;
  7227. ;;; Interactive entry points for new message buffers.
  7228. ;;;
  7229. ;;;###autoload
  7230. (defun message-mail-other-window (&optional to subject)
  7231. "Like `message-mail' command, but display mail buffer in another window."
  7232. (interactive)
  7233. (unless (message-mail-user-agent)
  7234. (message-pop-to-buffer (message-buffer-name "mail" to)
  7235. 'switch-to-buffer-other-window))
  7236. (let ((message-this-is-mail t))
  7237. (message-setup `((To . ,(or to "")) (Subject . ,(or subject "")))
  7238. nil nil nil 'switch-to-buffer-other-window)))
  7239. ;;;###autoload
  7240. (defun message-mail-other-frame (&optional to subject)
  7241. "Like `message-mail' command, but display mail buffer in another frame."
  7242. (interactive)
  7243. (unless (message-mail-user-agent)
  7244. (message-pop-to-buffer (message-buffer-name "mail" to)
  7245. 'switch-to-buffer-other-frame))
  7246. (let ((message-this-is-mail t))
  7247. (message-setup `((To . ,(or to "")) (Subject . ,(or subject "")))
  7248. nil nil nil 'switch-to-buffer-other-frame)))
  7249. ;;;###autoload
  7250. (defun message-news-other-window (&optional newsgroups subject)
  7251. "Start editing a news article to be sent."
  7252. (interactive)
  7253. (message-pop-to-buffer (message-buffer-name "posting" nil newsgroups)
  7254. 'switch-to-buffer-other-window)
  7255. (let ((message-this-is-news t))
  7256. (message-setup `((Newsgroups . ,(or newsgroups ""))
  7257. (Subject . ,(or subject ""))))))
  7258. ;;;###autoload
  7259. (defun message-news-other-frame (&optional newsgroups subject)
  7260. "Start editing a news article to be sent."
  7261. (interactive)
  7262. (message-pop-to-buffer (message-buffer-name "posting" nil newsgroups)
  7263. 'switch-to-buffer-other-frame)
  7264. (let ((message-this-is-news t))
  7265. (message-setup `((Newsgroups . ,(or newsgroups ""))
  7266. (Subject . ,(or subject ""))))))
  7267. ;;; underline.el
  7268. ;; This code should be moved to underline.el (from which it is stolen).
  7269. ;;;###autoload
  7270. (defun message-bold-region (start end)
  7271. "Bold all nonblank characters in the region.
  7272. Works by overstriking characters.
  7273. Called from program, takes two arguments START and END
  7274. which specify the range to operate on."
  7275. (interactive "r")
  7276. (save-excursion
  7277. (let ((end1 (make-marker)))
  7278. (move-marker end1 (max start end))
  7279. (goto-char (min start end))
  7280. (while (< (point) end1)
  7281. (or (looking-at "[_\^@- ]")
  7282. (insert (char-after) "\b"))
  7283. (forward-char 1)))))
  7284. ;;;###autoload
  7285. (defun message-unbold-region (start end)
  7286. "Remove all boldness (overstruck characters) in the region.
  7287. Called from program, takes two arguments START and END
  7288. which specify the range to operate on."
  7289. (interactive "r")
  7290. (save-excursion
  7291. (let ((end1 (make-marker)))
  7292. (move-marker end1 (max start end))
  7293. (goto-char (min start end))
  7294. (while (search-forward "\b" end1 t)
  7295. (if (eq (char-after) (char-after (- (point) 2)))
  7296. (delete-char -2))))))
  7297. (defun message-exchange-point-and-mark ()
  7298. "Exchange point and mark, but don't activate region if it was inactive."
  7299. (goto-char (prog1 (mark t)
  7300. (set-marker (mark-marker) (point)))))
  7301. ;; Support for toolbar
  7302. (defvar tool-bar-mode)
  7303. ;; Note: The :set function in the `message-tool-bar*' variables will only
  7304. ;; affect _new_ message buffers. We might add a function that walks thru all
  7305. ;; message-mode buffers and force the update.
  7306. (defun message-tool-bar-update (&optional symbol value)
  7307. "Update message mode toolbar.
  7308. Setter function for custom variables."
  7309. (setq-default message-tool-bar-map nil)
  7310. (when symbol
  7311. ;; When used as ":set" function:
  7312. (set-default symbol value)))
  7313. (defcustom message-tool-bar (if (eq gmm-tool-bar-style 'gnome)
  7314. 'message-tool-bar-gnome
  7315. 'message-tool-bar-retro)
  7316. "Specifies the message mode tool bar.
  7317. It can be either a list or a symbol referring to a list. See
  7318. `gmm-tool-bar-from-list' for the format of the list. The
  7319. default key map is `message-mode-map'.
  7320. Pre-defined symbols include `message-tool-bar-gnome' and
  7321. `message-tool-bar-retro'."
  7322. :type '(repeat gmm-tool-bar-list-item)
  7323. :type '(choice (const :tag "GNOME style" message-tool-bar-gnome)
  7324. (const :tag "Retro look" message-tool-bar-retro)
  7325. (repeat :tag "User defined list" gmm-tool-bar-item)
  7326. (symbol))
  7327. :version "23.1" ;; No Gnus
  7328. :initialize 'custom-initialize-default
  7329. :set 'message-tool-bar-update
  7330. :group 'message)
  7331. (defcustom message-tool-bar-gnome
  7332. '((ispell-message "spell" nil
  7333. :vert-only t
  7334. :visible (or (not (boundp 'flyspell-mode))
  7335. (not flyspell-mode)))
  7336. (flyspell-buffer "spell" t
  7337. :vert-only t
  7338. :visible (and (boundp 'flyspell-mode)
  7339. flyspell-mode)
  7340. :help "Flyspell whole buffer")
  7341. (message-send-and-exit "mail/send" t :label "Send")
  7342. (message-dont-send "mail/save-draft")
  7343. (mml-attach-file "attach" mml-mode-map :vert-only t)
  7344. (mml-preview "mail/preview" mml-mode-map)
  7345. (mml-secure-message-sign-encrypt "lock" mml-mode-map :visible nil)
  7346. (message-insert-importance-high "important" nil :visible nil)
  7347. (message-insert-importance-low "unimportant" nil :visible nil)
  7348. (message-insert-disposition-notification-to "receipt" nil :visible nil))
  7349. "List of items for the message tool bar (GNOME style).
  7350. See `gmm-tool-bar-from-list' for details on the format of the list."
  7351. :type '(repeat gmm-tool-bar-item)
  7352. :version "23.1" ;; No Gnus
  7353. :initialize 'custom-initialize-default
  7354. :set 'message-tool-bar-update
  7355. :group 'message)
  7356. (defcustom message-tool-bar-retro
  7357. '(;; Old Emacs 21 icon for consistency.
  7358. (message-send-and-exit "gnus/mail-send")
  7359. (message-kill-buffer "close")
  7360. (message-dont-send "cancel")
  7361. (mml-attach-file "attach" mml-mode-map)
  7362. (ispell-message "spell")
  7363. (mml-preview "preview" mml-mode-map)
  7364. (message-insert-importance-high "gnus/important")
  7365. (message-insert-importance-low "gnus/unimportant")
  7366. (message-insert-disposition-notification-to "gnus/receipt"))
  7367. "List of items for the message tool bar (retro style).
  7368. See `gmm-tool-bar-from-list' for details on the format of the list."
  7369. :type '(repeat gmm-tool-bar-item)
  7370. :version "23.1" ;; No Gnus
  7371. :initialize 'custom-initialize-default
  7372. :set 'message-tool-bar-update
  7373. :group 'message)
  7374. (defcustom message-tool-bar-zap-list
  7375. '(new-file open-file dired kill-buffer write-file
  7376. print-buffer customize help)
  7377. "List of icon items from the global tool bar.
  7378. These items are not displayed on the message mode tool bar.
  7379. See `gmm-tool-bar-from-list' for the format of the list."
  7380. :type 'gmm-tool-bar-zap-list
  7381. :version "23.1" ;; No Gnus
  7382. :initialize 'custom-initialize-default
  7383. :set 'message-tool-bar-update
  7384. :group 'message)
  7385. (defvar image-load-path)
  7386. (defun message-make-tool-bar (&optional force)
  7387. "Make a message mode tool bar from `message-tool-bar-list'.
  7388. When FORCE, rebuild the tool bar."
  7389. (when (and (not (featurep 'xemacs))
  7390. (boundp 'tool-bar-mode)
  7391. tool-bar-mode
  7392. (or (not message-tool-bar-map) force))
  7393. (setq message-tool-bar-map
  7394. (let* ((load-path
  7395. (gmm-image-load-path-for-library "message"
  7396. "mail/save-draft.xpm"
  7397. nil t))
  7398. (image-load-path (cons (car load-path)
  7399. (when (boundp 'image-load-path)
  7400. image-load-path))))
  7401. (gmm-tool-bar-from-list message-tool-bar
  7402. message-tool-bar-zap-list
  7403. 'message-mode-map))))
  7404. message-tool-bar-map)
  7405. ;;; Group name completion.
  7406. (defcustom message-newgroups-header-regexp
  7407. "^\\(Newsgroups\\|Followup-To\\|Posted-To\\|Gcc\\):"
  7408. "Regexp that match headers that lists groups."
  7409. :group 'message
  7410. :type 'regexp)
  7411. (defcustom message-completion-alist
  7412. (list (cons message-newgroups-header-regexp 'message-expand-group)
  7413. '("^\\(Resent-\\)?\\(To\\|B?Cc\\):" . message-expand-name)
  7414. '("^\\(Reply-To\\|From\\|Mail-Followup-To\\|Mail-Copies-To\\):"
  7415. . message-expand-name)
  7416. '("^\\(Disposition-Notification-To\\|Return-Receipt-To\\):"
  7417. . message-expand-name))
  7418. "Alist of (RE . FUN). Use FUN for completion on header lines matching RE."
  7419. :version "22.1"
  7420. :group 'message
  7421. :type '(alist :key-type regexp :value-type function))
  7422. (defcustom message-expand-name-databases
  7423. '(bbdb eudc)
  7424. "List of databases to try for name completion (`message-expand-name').
  7425. Each element is a symbol and can be `bbdb' or `eudc'."
  7426. :group 'message
  7427. :type '(set (const bbdb) (const eudc)))
  7428. (defcustom message-tab-body-function nil
  7429. "*Function to execute when `message-tab' (TAB) is executed in the body.
  7430. If nil, the function bound in `text-mode-map' or `global-map' is executed."
  7431. :version "22.1"
  7432. :group 'message
  7433. :link '(custom-manual "(message)Various Commands")
  7434. :type '(choice (const nil)
  7435. function))
  7436. (declare-function mail-abbrev-in-expansion-header-p "mailabbrev" ())
  7437. (defun message-tab ()
  7438. "Complete names according to `message-completion-alist'.
  7439. Execute function specified by `message-tab-body-function' when
  7440. not in those headers. If that variable is nil, indent with the
  7441. regular text mode tabbing command."
  7442. (interactive)
  7443. (cond
  7444. ((if (and (boundp 'completion-fail-discreetly)
  7445. (fboundp 'completion-at-point))
  7446. (let ((completion-fail-discreetly t)) (completion-at-point))
  7447. (funcall (or (message-completion-function) #'ignore)))
  7448. ;; Completion was performed; nothing else to do.
  7449. nil)
  7450. (message-tab-body-function (funcall message-tab-body-function))
  7451. (t (funcall (or (lookup-key text-mode-map "\t")
  7452. (lookup-key global-map "\t")
  7453. 'indent-relative)))))
  7454. (defvar mail-abbrev-mode-regexp)
  7455. (defun message-completion-function ()
  7456. (let ((alist message-completion-alist))
  7457. (while (and alist
  7458. (let ((mail-abbrev-mode-regexp (caar alist)))
  7459. (not (mail-abbrev-in-expansion-header-p))))
  7460. (setq alist (cdr alist)))
  7461. (when (cdar alist)
  7462. (lexical-let ((fun (cdar alist)))
  7463. ;; Even if completion fails, return a non-nil value, so as to avoid
  7464. ;; falling back to message-tab-body-function.
  7465. (lambda () (funcall fun) 'completion-attempted)))))
  7466. (defun message-expand-group ()
  7467. "Expand the group name under point."
  7468. (let ((b (save-excursion
  7469. (save-restriction
  7470. (narrow-to-region
  7471. (save-excursion
  7472. (beginning-of-line)
  7473. (skip-chars-forward "^:")
  7474. (1+ (point)))
  7475. (point))
  7476. (skip-chars-backward "^, \t\n") (point))))
  7477. (completion-ignore-case t)
  7478. (e (progn (skip-chars-forward "^,\t\n ") (point)))
  7479. group collection)
  7480. (when (and (boundp 'gnus-active-hashtb)
  7481. gnus-active-hashtb)
  7482. (mapatoms
  7483. (lambda (symbol)
  7484. (setq group (symbol-name symbol))
  7485. (push (if (string-match "[^\000-\177]" group)
  7486. (gnus-group-decoded-name group)
  7487. group)
  7488. collection))
  7489. gnus-active-hashtb))
  7490. (message-completion-in-region b e collection)))
  7491. (defalias 'message-completion-in-region
  7492. (if (fboundp 'completion-in-region)
  7493. 'completion-in-region
  7494. (lambda (b e hashtb)
  7495. (let* ((string (buffer-substring b e))
  7496. (completions (all-completions string hashtb))
  7497. comp)
  7498. (delete-region b (point))
  7499. (cond
  7500. ((= (length completions) 1)
  7501. (if (string= (car completions) string)
  7502. (progn
  7503. (insert string)
  7504. (message "Only matching group"))
  7505. (insert (car completions))))
  7506. ((and (setq comp (try-completion string hashtb))
  7507. (not (string= comp string)))
  7508. (insert comp))
  7509. (t
  7510. (insert string)
  7511. (if (not comp)
  7512. (message "No matching groups")
  7513. (save-selected-window
  7514. (pop-to-buffer "*Completions*")
  7515. (buffer-disable-undo)
  7516. (let ((buffer-read-only nil))
  7517. (erase-buffer)
  7518. (let ((standard-output (current-buffer)))
  7519. (display-completion-list (sort completions 'string<)))
  7520. (setq buffer-read-only nil)
  7521. (goto-char (point-min))
  7522. (delete-region (point)
  7523. (progn (forward-line 3) (point))))))))))))
  7524. (defun message-expand-name ()
  7525. (cond ((and (memq 'eudc message-expand-name-databases)
  7526. (boundp 'eudc-protocol)
  7527. eudc-protocol)
  7528. (eudc-expand-inline))
  7529. ((and (memq 'bbdb message-expand-name-databases)
  7530. (fboundp 'bbdb-complete-name))
  7531. (let ((starttick (buffer-modified-tick)))
  7532. (or (bbdb-complete-name)
  7533. ;; Apparently, bbdb-complete-name can return nil even when
  7534. ;; completion took place. So let's double check the buffer was
  7535. ;; not modified.
  7536. (/= starttick (buffer-modified-tick)))))
  7537. (t
  7538. (expand-abbrev))))
  7539. ;;; Help stuff.
  7540. (defun message-talkative-question (ask question show &rest text)
  7541. "Call FUNCTION with argument QUESTION; optionally display TEXT... args.
  7542. If SHOW is non-nil, the arguments TEXT... are displayed in a temp buffer.
  7543. The following arguments may contain lists of values."
  7544. (if (and show
  7545. (setq text (message-flatten-list text)))
  7546. (save-window-excursion
  7547. (with-output-to-temp-buffer " *MESSAGE information message*"
  7548. (with-current-buffer " *MESSAGE information message*"
  7549. (fundamental-mode) ; for Emacs 20.4+
  7550. (mapc 'princ text)
  7551. (goto-char (point-min))))
  7552. (funcall ask question))
  7553. (funcall ask question)))
  7554. (defun message-flatten-list (list)
  7555. "Return a new, flat list that contains all elements of LIST.
  7556. \(message-flatten-list \\='(1 (2 3 (4 5 (6))) 7))
  7557. => (1 2 3 4 5 6 7)"
  7558. (cond ((consp list)
  7559. (apply 'append (mapcar 'message-flatten-list list)))
  7560. (list
  7561. (list list))))
  7562. (defun message-generate-new-buffer-clone-locals (name &optional varstr)
  7563. "Create and return a buffer with name based on NAME using `generate-new-buffer'.
  7564. Then clone the local variables and values from the old buffer to the
  7565. new one, cloning only the locals having a substring matching the
  7566. regexp VARSTR."
  7567. (let ((oldbuf (current-buffer)))
  7568. (with-current-buffer (generate-new-buffer name)
  7569. (message-clone-locals oldbuf varstr)
  7570. (current-buffer))))
  7571. (defun message-clone-locals (buffer &optional varstr)
  7572. "Clone the local variables from BUFFER to the current buffer."
  7573. (let ((locals (with-current-buffer buffer (buffer-local-variables)))
  7574. (regexp "^gnus\\|^nn\\|^message\\|^sendmail\\|^smtp\\|^user-mail-address"))
  7575. (mapcar
  7576. (lambda (local)
  7577. (when (and (consp local)
  7578. (car local)
  7579. (string-match regexp (symbol-name (car local)))
  7580. (or (null varstr)
  7581. (string-match varstr (symbol-name (car local)))))
  7582. (ignore-errors
  7583. (set (make-local-variable (car local))
  7584. (cdr local)))))
  7585. locals)))
  7586. ;;;
  7587. ;;; MIME functions
  7588. ;;;
  7589. (defun message-encode-message-body ()
  7590. (unless message-inhibit-body-encoding
  7591. (let ((mail-parse-charset (or mail-parse-charset
  7592. message-default-charset))
  7593. (case-fold-search t)
  7594. lines content-type-p)
  7595. (message-goto-body)
  7596. (save-restriction
  7597. (narrow-to-region (point) (point-max))
  7598. (let ((new (mml-generate-mime)))
  7599. (when new
  7600. (delete-region (point-min) (point-max))
  7601. (insert new)
  7602. (goto-char (point-min))
  7603. (if (eq (aref new 0) ?\n)
  7604. (delete-char 1)
  7605. (search-forward "\n\n")
  7606. (setq lines (buffer-substring (point-min) (1- (point))))
  7607. (delete-region (point-min) (point))))))
  7608. (save-restriction
  7609. (message-narrow-to-headers-or-head)
  7610. (message-remove-header "Mime-Version")
  7611. (goto-char (point-max))
  7612. (insert "MIME-Version: 1.0\n")
  7613. (when lines
  7614. (insert lines))
  7615. (setq content-type-p
  7616. (or mml-boundary
  7617. (re-search-backward "^Content-Type:" nil t))))
  7618. (save-restriction
  7619. (message-narrow-to-headers-or-head)
  7620. (message-remove-first-header "Content-Type")
  7621. (message-remove-first-header "Content-Transfer-Encoding"))
  7622. ;; We always make sure that the message has a Content-Type
  7623. ;; header. This is because some broken MTAs and MUAs get
  7624. ;; awfully confused when confronted with a message with a
  7625. ;; MIME-Version header and without a Content-Type header. For
  7626. ;; instance, Solaris' /usr/bin/mail.
  7627. (unless content-type-p
  7628. (goto-char (point-min))
  7629. ;; For unknown reason, MIME-Version doesn't exist.
  7630. (when (re-search-forward "^MIME-Version:" nil t)
  7631. (forward-line 1)
  7632. (insert "Content-Type: text/plain; charset=us-ascii\n"))))))
  7633. (defun message-read-from-minibuffer (prompt &optional initial-contents)
  7634. "Read from the minibuffer while providing abbrev expansion."
  7635. (if (fboundp 'mail-abbrevs-setup)
  7636. (let ((minibuffer-setup-hook 'mail-abbrevs-setup)
  7637. (minibuffer-local-map message-minibuffer-local-map))
  7638. (read-from-minibuffer prompt initial-contents))
  7639. (let ((minibuffer-setup-hook 'mail-abbrev-minibuffer-setup-hook)
  7640. (minibuffer-local-map message-minibuffer-local-map))
  7641. (read-string prompt initial-contents))))
  7642. (defun message-use-alternative-email-as-from ()
  7643. "Set From field of the outgoing message to the first matching
  7644. address in `message-alternative-emails', looking at To, Cc and
  7645. From headers in the original article."
  7646. (require 'mail-utils)
  7647. (let* ((fields '("To" "Cc" "From"))
  7648. (emails
  7649. (split-string
  7650. (mail-strip-quoted-names
  7651. (mapconcat 'message-fetch-reply-field fields ","))
  7652. "[ \f\t\n\r\v,]+"))
  7653. email)
  7654. (while emails
  7655. (if (string-match message-alternative-emails (car emails))
  7656. (setq email (car emails)
  7657. emails nil))
  7658. (pop emails))
  7659. (unless (or (not email) (equal email user-mail-address))
  7660. (message-remove-header "From")
  7661. (goto-char (point-max))
  7662. (insert "From: " (let ((user-mail-address email)) (message-make-from))
  7663. "\n"))))
  7664. (defun message-options-get (symbol)
  7665. (cdr (assq symbol message-options)))
  7666. (defun message-options-set (symbol value)
  7667. (let ((the-cons (assq symbol message-options)))
  7668. (if the-cons
  7669. (if value
  7670. (setcdr the-cons value)
  7671. (setq message-options (delq the-cons message-options)))
  7672. (and value
  7673. (push (cons symbol value) message-options))))
  7674. value)
  7675. (defun message-options-set-recipient ()
  7676. (save-restriction
  7677. (message-narrow-to-headers-or-head)
  7678. (message-options-set 'message-sender
  7679. (mail-strip-quoted-names
  7680. (message-fetch-field "from")))
  7681. (message-options-set 'message-recipients
  7682. (mail-strip-quoted-names
  7683. (let ((to (message-fetch-field "to"))
  7684. (cc (message-fetch-field "cc"))
  7685. (bcc (message-fetch-field "bcc")))
  7686. (concat
  7687. (or to "")
  7688. (if (and to cc) ", ")
  7689. (or cc "")
  7690. (if (and (or to cc) bcc) ", ")
  7691. (or bcc "")))))))
  7692. (defun message-hide-headers ()
  7693. "Hide headers based on the `message-hidden-headers' variable."
  7694. (let ((regexps (if (stringp message-hidden-headers)
  7695. (list message-hidden-headers)
  7696. message-hidden-headers))
  7697. (inhibit-point-motion-hooks t)
  7698. (after-change-functions nil)
  7699. (end-of-headers (point-min)))
  7700. (when regexps
  7701. (save-excursion
  7702. (save-restriction
  7703. (message-narrow-to-headers)
  7704. (goto-char (point-min))
  7705. (while (not (eobp))
  7706. (if (not (message-hide-header-p regexps))
  7707. (message-next-header)
  7708. (let ((begin (point))
  7709. header header-len)
  7710. (message-next-header)
  7711. (setq header (buffer-substring begin (point))
  7712. header-len (- (point) begin))
  7713. (delete-region begin (point))
  7714. (goto-char end-of-headers)
  7715. (insert header)
  7716. (setq end-of-headers
  7717. (+ end-of-headers header-len))))))))
  7718. (narrow-to-region end-of-headers (point-max))))
  7719. (defun message-hide-header-p (regexps)
  7720. (let ((result nil)
  7721. (reverse nil))
  7722. (when (eq (car regexps) 'not)
  7723. (setq reverse t)
  7724. (pop regexps))
  7725. (dolist (regexp regexps)
  7726. (setq result (or result (looking-at regexp))))
  7727. (if reverse
  7728. (not result)
  7729. result)))
  7730. (declare-function ecomplete-add-item "ecomplete" (type key text))
  7731. (declare-function ecomplete-save "ecomplete" ())
  7732. (defun message-put-addresses-in-ecomplete ()
  7733. (require 'ecomplete)
  7734. (dolist (header '("to" "cc" "from" "reply-to"))
  7735. (let ((value (message-field-value header)))
  7736. (dolist (string (mail-header-parse-addresses value 'raw))
  7737. (setq string
  7738. (gnus-replace-in-string
  7739. (gnus-replace-in-string string "^ +\\| +$" "") "\n" ""))
  7740. (ecomplete-add-item 'mail (car (mail-header-parse-address string))
  7741. string))))
  7742. (ecomplete-save))
  7743. (autoload 'ecomplete-display-matches "ecomplete")
  7744. (defun message-display-abbrev (&optional choose)
  7745. "Display the next possible abbrev for the text before point."
  7746. (interactive (list t))
  7747. (when (and (memq (char-after (point-at-bol)) '(?C ?T ?\t ? ))
  7748. (message-point-in-header-p)
  7749. (save-excursion
  7750. (beginning-of-line)
  7751. (while (and (memq (char-after) '(?\t ? ))
  7752. (zerop (forward-line -1))))
  7753. (looking-at "To:\\|Cc:")))
  7754. (let* ((end (point))
  7755. (start (save-excursion
  7756. (and (re-search-backward "[\n\t ]" nil t)
  7757. (1+ (point)))))
  7758. (word (when start (buffer-substring start end)))
  7759. (match (when (and word
  7760. (not (zerop (length word))))
  7761. (ecomplete-display-matches 'mail word choose))))
  7762. (when (and choose match)
  7763. (delete-region start end)
  7764. (insert match)))))
  7765. ;; To send pre-formatted letters like the example below, you can use
  7766. ;; `message-send-form-letter':
  7767. ;; --8<---------------cut here---------------start------------->8---
  7768. ;; To: alice@invalid.invalid
  7769. ;; Subject: Verification of your contact information
  7770. ;; From: Contact verification <admin@foo.invalid>
  7771. ;; --text follows this line--
  7772. ;; Hi Alice,
  7773. ;; please verify that your contact information is still valid:
  7774. ;; Alice A, A avenue 11, 1111 A town, Austria
  7775. ;; ----------next form letter message follows this line----------
  7776. ;; To: bob@invalid.invalid
  7777. ;; Subject: Verification of your contact information
  7778. ;; From: Contact verification <admin@foo.invalid>
  7779. ;; --text follows this line--
  7780. ;; Hi Bob,
  7781. ;; please verify that your contact information is still valid:
  7782. ;; Bob, B street 22, 22222 Be town, Belgium
  7783. ;; ----------next form letter message follows this line----------
  7784. ;; To: charlie@invalid.invalid
  7785. ;; Subject: Verification of your contact information
  7786. ;; From: Contact verification <admin@foo.invalid>
  7787. ;; --text follows this line--
  7788. ;; Hi Charlie,
  7789. ;; please verify that your contact information is still valid:
  7790. ;; Charlie Chaplin, C plaza 33, 33333 C town, Chile
  7791. ;; --8<---------------cut here---------------end--------------->8---
  7792. ;; FIXME: What is the most common term (circular letter, form letter, serial
  7793. ;; letter, standard letter) for such kind of letter? See also
  7794. ;; <http://en.wikipedia.org/wiki/Form_letter>
  7795. ;; FIXME: Maybe extent message-mode's font-lock support to recognize
  7796. ;; `message-form-letter-separator', i.e. highlight each message like a single
  7797. ;; message.
  7798. (defcustom message-form-letter-separator
  7799. "\n----------next form letter message follows this line----------\n"
  7800. "Separator for `message-send-form-letter'."
  7801. ;; :group 'message-form-letter
  7802. :group 'message-various
  7803. :version "23.1" ;; No Gnus
  7804. :type 'string)
  7805. (defcustom message-send-form-letter-delay 1
  7806. "Delay in seconds when sending a message with `message-send-form-letter'.
  7807. Only used when `message-send-form-letter' is called with non-nil
  7808. argument `force'."
  7809. ;; :group 'message-form-letter
  7810. :group 'message-various
  7811. :version "23.1" ;; No Gnus
  7812. :type 'integer)
  7813. (defun message-send-form-letter (&optional force)
  7814. "Sent all form letter messages from current buffer.
  7815. Unless FORCE, prompt before sending.
  7816. The messages are separated by `message-form-letter-separator'.
  7817. Header and body are separated by `mail-header-separator'."
  7818. (interactive "P")
  7819. (let ((sent 0) (skipped 0)
  7820. start end text
  7821. buff
  7822. to done)
  7823. (goto-char (point-min))
  7824. (while (not done)
  7825. (setq start (point)
  7826. end (if (search-forward message-form-letter-separator nil t)
  7827. (- (point) (length message-form-letter-separator) -1)
  7828. (setq done t)
  7829. (point-max)))
  7830. (setq text
  7831. (buffer-substring-no-properties start end))
  7832. (setq buff (generate-new-buffer "*mail - form letter*"))
  7833. (with-current-buffer buff
  7834. (insert text)
  7835. (message-mode)
  7836. (setq to (message-fetch-field "To"))
  7837. (switch-to-buffer buff)
  7838. (when force
  7839. (sit-for message-send-form-letter-delay))
  7840. (if (or force
  7841. (y-or-n-p (format "Send message to `%s'? " to)))
  7842. (progn
  7843. (setq sent (1+ sent))
  7844. (message-send-and-exit))
  7845. (message "Message to `%s' skipped." to)
  7846. (setq skipped (1+ skipped)))
  7847. (when (buffer-live-p buff)
  7848. (kill-buffer buff))))
  7849. (message "%s message(s) sent, %s skipped." sent skipped)))
  7850. (defun message-replace-header (header new-value &optional after force)
  7851. "Remove HEADER and insert the NEW-VALUE.
  7852. If AFTER, insert after this header. If FORCE, insert new field
  7853. even if NEW-VALUE is empty."
  7854. ;; Similar to `nnheader-replace-header' but for message buffers.
  7855. (save-excursion
  7856. (save-restriction
  7857. (message-narrow-to-headers)
  7858. (message-remove-header header))
  7859. (when (or force (> (length new-value) 0))
  7860. (if after
  7861. (message-position-on-field header after)
  7862. (message-position-on-field header))
  7863. (insert new-value))))
  7864. (defcustom message-recipients-without-full-name
  7865. (list "ding@gnus.org"
  7866. "bugs@gnus.org"
  7867. "emacs-devel@gnu.org"
  7868. "emacs-pretest-bug@gnu.org"
  7869. "bug-gnu-emacs@gnu.org")
  7870. "Mail addresses that have no full name.
  7871. Used in `message-simplify-recipients'."
  7872. ;; Maybe the addresses could be extracted from
  7873. ;; `gnus-parameter-to-list-alist'?
  7874. :type '(choice (const :tag "None" nil)
  7875. (repeat string))
  7876. :version "23.1" ;; No Gnus
  7877. :group 'message-headers)
  7878. (defun message-simplify-recipients ()
  7879. (interactive)
  7880. (dolist (hdr '("Cc" "To"))
  7881. (message-replace-header
  7882. hdr
  7883. (mapconcat
  7884. (lambda (addrcomp)
  7885. (if (and message-recipients-without-full-name
  7886. (string-match
  7887. (regexp-opt message-recipients-without-full-name)
  7888. (cadr addrcomp)))
  7889. (cadr addrcomp)
  7890. (if (car addrcomp)
  7891. (message-make-from (car addrcomp) (cadr addrcomp))
  7892. (cadr addrcomp))))
  7893. (when (message-fetch-field hdr)
  7894. (mail-extract-address-components
  7895. (message-fetch-field hdr) t))
  7896. ", "))))
  7897. ;;; multipart/related and HTML support.
  7898. (defun message-make-html-message-with-image-files (files)
  7899. "Make a message containing the current dired-marked image files."
  7900. (interactive (list (dired-get-marked-files nil current-prefix-arg)))
  7901. (message-mail)
  7902. (message-goto-body)
  7903. (insert "<#part type=text/html>\n\n")
  7904. (dolist (file files)
  7905. (insert (format "<img src=%S>\n\n" file)))
  7906. (message-toggle-image-thumbnails)
  7907. (message-goto-to))
  7908. (defun message-toggle-image-thumbnails ()
  7909. "For any included image files, insert a thumbnail of that image."
  7910. (interactive)
  7911. (let ((overlays (overlays-in (point-min) (point-max)))
  7912. (displayed nil))
  7913. (while overlays
  7914. (let ((overlay (car overlays)))
  7915. (when (overlay-get overlay 'put-image)
  7916. (delete-overlay overlay)
  7917. (setq displayed t)))
  7918. (setq overlays (cdr overlays)))
  7919. (unless displayed
  7920. (save-excursion
  7921. (goto-char (point-min))
  7922. (while (re-search-forward "<img.*src=\"\\([^\"]+\\)" nil t)
  7923. (let ((file (match-string 1))
  7924. (edges (message-window-inside-pixel-edges
  7925. (get-buffer-window (current-buffer)))))
  7926. (put-image
  7927. (create-image
  7928. file 'imagemagick nil
  7929. :max-width (truncate
  7930. (* 0.7 (- (nth 2 edges) (nth 0 edges))))
  7931. :max-height (truncate
  7932. (* 0.5 (- (nth 3 edges) (nth 1 edges)))))
  7933. (match-beginning 0)
  7934. " ")))))))
  7935. (when (featurep 'xemacs)
  7936. (require 'messagexmas)
  7937. (message-xmas-redefine))
  7938. (provide 'message)
  7939. (run-hooks 'message-load-hook)
  7940. ;; Local Variables:
  7941. ;; coding: utf-8
  7942. ;; End:
  7943. ;;; message.el ends here