message.el 292 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390
  1. ;;; message.el --- composing mail and news messages
  2. ;; Copyright (C) 1996-2012 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. ;; For Emacs <22.2 and XEmacs.
  22. (eval-and-compile
  23. (unless (fboundp 'declare-function) (defmacro declare-function (&rest r))))
  24. (eval-when-compile
  25. (require 'cl))
  26. (require 'mailheader)
  27. (require 'gmm-utils)
  28. (require 'mail-utils)
  29. ;; Only for the trivial macros mail-header-from, mail-header-date
  30. ;; mail-header-references, mail-header-subject, mail-header-id
  31. (eval-when-compile (require 'nnheader))
  32. ;; This is apparently necessary even though things are autoloaded.
  33. ;; Because we dynamically bind mail-abbrev-mode-regexp, we'd better
  34. ;; require mailabbrev here.
  35. (if (featurep 'xemacs)
  36. (require 'mail-abbrevs)
  37. (require 'mailabbrev))
  38. (require 'mail-parse)
  39. (require 'mml)
  40. (require 'rfc822)
  41. (require 'format-spec)
  42. (autoload 'mailclient-send-it "mailclient") ;; Emacs 22 or contrib/
  43. (defvar gnus-message-group-art)
  44. (defvar gnus-list-identifiers) ; gnus-sum is required where necessary
  45. (defvar rmail-enable-mime-composing)
  46. (defgroup message '((user-mail-address custom-variable)
  47. (user-full-name custom-variable))
  48. "Mail and news message composing."
  49. :link '(custom-manual "(message)Top")
  50. :group 'mail
  51. :group 'news)
  52. (put 'user-mail-address 'custom-type 'string)
  53. (put 'user-full-name 'custom-type 'string)
  54. (defgroup message-various nil
  55. "Various Message Variables."
  56. :link '(custom-manual "(message)Various Message Variables")
  57. :group 'message)
  58. (defgroup message-buffers nil
  59. "Message Buffers."
  60. :link '(custom-manual "(message)Message Buffers")
  61. :group 'message)
  62. (defgroup message-sending nil
  63. "Message Sending."
  64. :link '(custom-manual "(message)Sending Variables")
  65. :group 'message)
  66. (defgroup message-interface nil
  67. "Message Interface."
  68. :link '(custom-manual "(message)Interface")
  69. :group 'message)
  70. (defgroup message-forwarding nil
  71. "Message Forwarding."
  72. :link '(custom-manual "(message)Forwarding")
  73. :group 'message-interface)
  74. (defgroup message-insertion nil
  75. "Message Insertion."
  76. :link '(custom-manual "(message)Insertion")
  77. :group 'message)
  78. (defgroup message-headers nil
  79. "Message Headers."
  80. :link '(custom-manual "(message)Message Headers")
  81. :group 'message)
  82. (defgroup message-news nil
  83. "Composing News Messages."
  84. :group 'message)
  85. (defgroup message-mail nil
  86. "Composing Mail Messages."
  87. :group 'message)
  88. (defgroup message-faces nil
  89. "Faces used for message composing."
  90. :group 'message
  91. :group 'faces)
  92. (defcustom message-directory "~/Mail/"
  93. "*Directory from which all other mail file variables are derived."
  94. :group 'message-various
  95. :type 'directory)
  96. (defcustom message-max-buffers 10
  97. "*How many buffers to keep before starting to kill them off."
  98. :group 'message-buffers
  99. :type 'integer)
  100. (defcustom message-send-rename-function nil
  101. "Function called to rename the buffer after sending it."
  102. :group 'message-buffers
  103. :type '(choice function (const nil)))
  104. (defcustom message-fcc-handler-function 'message-output
  105. "*A function called to save outgoing articles.
  106. This function will be called with the name of the file to store the
  107. article in. The default function is `message-output' which saves in Unix
  108. mailbox format."
  109. :type '(radio (function-item message-output)
  110. (function :tag "Other"))
  111. :group 'message-sending)
  112. (defcustom message-fcc-externalize-attachments nil
  113. "If non-nil, attachments are included as external parts in Fcc copies."
  114. :version "22.1"
  115. :type 'boolean
  116. :group 'message-sending)
  117. (defcustom message-courtesy-message
  118. "The following message is a courtesy copy of an article\nthat has been posted to %s as well.\n\n"
  119. "*This is inserted at the start of a mailed copy of a posted message.
  120. If the string contains the format spec \"%s\", the Newsgroups
  121. the article has been posted to will be inserted there.
  122. If this variable is nil, no such courtesy message will be added."
  123. :group 'message-sending
  124. :type '(radio string (const nil)))
  125. (defcustom message-ignored-bounced-headers
  126. "^\\(Received\\|Return-Path\\|Delivered-To\\):"
  127. "*Regexp that matches headers to be removed in resent bounced mail."
  128. :group 'message-interface
  129. :type 'regexp)
  130. (defcustom message-from-style mail-from-style
  131. "Specifies how \"From\" headers look.
  132. If nil, they contain just the return address like:
  133. king@grassland.com
  134. If `parens', they look like:
  135. king@grassland.com (Elvis Parsley)
  136. If `angles', they look like:
  137. Elvis Parsley <king@grassland.com>
  138. Otherwise, most addresses look like `angles', but they look like
  139. `parens' if `angles' would need quoting and `parens' would not."
  140. :version "23.2"
  141. :type '(choice (const :tag "simple" nil)
  142. (const parens)
  143. (const angles)
  144. (const default))
  145. :group 'message-headers)
  146. (defcustom message-insert-canlock t
  147. "Whether to insert a Cancel-Lock header in news postings."
  148. :version "22.1"
  149. :group 'message-headers
  150. :type 'boolean)
  151. (defcustom message-syntax-checks
  152. (if message-insert-canlock '((sender . disabled)) nil)
  153. ;; Guess this one shouldn't be easy to customize...
  154. "*Controls what syntax checks should not be performed on outgoing posts.
  155. To disable checking of long signatures, for instance, add
  156. `(signature . disabled)' to this list.
  157. Don't touch this variable unless you really know what you're doing.
  158. Checks include `approved', `bogus-recipient', `continuation-headers',
  159. `control-chars', `empty', `existing-newsgroups', `from', `illegible-text',
  160. `invisible-text', `long-header-lines', `long-lines', `message-id',
  161. `multiple-headers', `new-text', `newsgroups', `quoting-style',
  162. `repeated-newsgroups', `reply-to', `sender', `sendsys', `shoot',
  163. `shorten-followup-to', `signature', `size', `subject', `subject-cmsg'
  164. and `valid-newsgroups'."
  165. :group 'message-news
  166. :type '(repeat sexp)) ; Fixme: improve this
  167. (defcustom message-required-headers '((optional . References)
  168. From)
  169. "*Headers to be generated or prompted for when sending a message.
  170. Also see `message-required-news-headers' and
  171. `message-required-mail-headers'."
  172. :version "22.1"
  173. :group 'message-news
  174. :group 'message-headers
  175. :link '(custom-manual "(message)Message Headers")
  176. :type '(repeat sexp))
  177. (defcustom message-draft-headers '(References From Date)
  178. "*Headers to be generated when saving a draft message."
  179. :version "22.1"
  180. :group 'message-news
  181. :group 'message-headers
  182. :link '(custom-manual "(message)Message Headers")
  183. :type '(repeat sexp))
  184. (defcustom message-required-news-headers
  185. '(From Newsgroups Subject Date Message-ID
  186. (optional . Organization)
  187. (optional . User-Agent))
  188. "*Headers to be generated or prompted for when posting an article.
  189. RFC977 and RFC1036 require From, Date, Newsgroups, Subject,
  190. Message-ID. Organization, Lines, In-Reply-To, Expires, and
  191. User-Agent are optional. If you don't want message to insert some
  192. header, remove it from this list."
  193. :group 'message-news
  194. :group 'message-headers
  195. :link '(custom-manual "(message)Message Headers")
  196. :type '(repeat sexp))
  197. (defcustom message-required-mail-headers
  198. '(From Subject Date (optional . In-Reply-To) Message-ID
  199. (optional . User-Agent))
  200. "*Headers to be generated or prompted for when mailing a message.
  201. It is recommended that From, Date, To, Subject and Message-ID be
  202. included. Organization and User-Agent are optional."
  203. :group 'message-mail
  204. :group 'message-headers
  205. :link '(custom-manual "(message)Message Headers")
  206. :type '(repeat sexp))
  207. (defcustom message-prune-recipient-rules nil
  208. "Rules for how to prune the list of recipients when doing wide replies.
  209. This is a list of regexps and regexp matches."
  210. :version "24.1"
  211. :group 'message-mail
  212. :group 'message-headers
  213. :link '(custom-manual "(message)Wide Reply")
  214. :type '(repeat regexp))
  215. (defcustom message-deletable-headers '(Message-ID Date Lines)
  216. "Headers to be deleted if they already exist and were generated by message previously."
  217. :group 'message-headers
  218. :link '(custom-manual "(message)Message Headers")
  219. :type 'sexp)
  220. (defcustom message-ignored-news-headers
  221. "^NNTP-Posting-Host:\\|^Xref:\\|^[BGF]cc:\\|^Resent-Fcc:\\|^X-Draft-From:\\|^X-Gnus-Agent-Meta-Information:"
  222. "*Regexp of headers to be removed unconditionally before posting."
  223. :group 'message-news
  224. :group 'message-headers
  225. :link '(custom-manual "(message)Message Headers")
  226. :type '(repeat :value-to-internal (lambda (widget value)
  227. (custom-split-regexp-maybe value))
  228. :match (lambda (widget value)
  229. (or (stringp value)
  230. (widget-editable-list-match widget value)))
  231. regexp))
  232. (defcustom message-ignored-mail-headers
  233. "^\\([GF]cc\\|Resent-Fcc\\|Xref\\|X-Draft-From\\|X-Gnus-Agent-Meta-Information\\):"
  234. "*Regexp of headers to be removed unconditionally before mailing."
  235. :group 'message-mail
  236. :group 'message-headers
  237. :link '(custom-manual "(message)Mail Headers")
  238. :type 'regexp)
  239. (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:"
  240. "*Header lines matching this regexp will be deleted before posting.
  241. It's best to delete old Path and Date headers before posting to avoid
  242. any confusion."
  243. :group 'message-interface
  244. :link '(custom-manual "(message)Superseding")
  245. :type '(repeat :value-to-internal (lambda (widget value)
  246. (custom-split-regexp-maybe value))
  247. :match (lambda (widget value)
  248. (or (stringp value)
  249. (widget-editable-list-match widget value)))
  250. regexp))
  251. (defcustom message-subject-re-regexp
  252. "^[ \t]*\\([Rr][Ee]\\(\\[[0-9]*\\]\\)*:[ \t]*\\)*[ \t]*"
  253. "*Regexp matching \"Re: \" in the subject line."
  254. :group 'message-various
  255. :link '(custom-manual "(message)Message Headers")
  256. :type 'regexp)
  257. ;;; Start of variables adopted from `message-utils.el'.
  258. (defcustom message-subject-trailing-was-query t
  259. "*What to do with trailing \"(was: <old subject>)\" in subject lines.
  260. If nil, leave the subject unchanged. If it is the symbol `ask', query
  261. the user what do do. In this case, the subject is matched against
  262. `message-subject-trailing-was-ask-regexp'. If
  263. `message-subject-trailing-was-query' is t, always strip the trailing
  264. old subject. In this case, `message-subject-trailing-was-regexp' is
  265. used."
  266. :version "24.1"
  267. :type '(choice (const :tag "never" nil)
  268. (const :tag "always strip" t)
  269. (const ask))
  270. :link '(custom-manual "(message)Message Headers")
  271. :group 'message-various)
  272. (defcustom message-subject-trailing-was-ask-regexp
  273. "[ \t]*\\([[(]+[Ww][Aa][Ss]:?[ \t]*.*[])]+\\)"
  274. "*Regexp matching \"(was: <old subject>)\" in the subject line.
  275. The function `message-strip-subject-trailing-was' uses this regexp if
  276. `message-subject-trailing-was-query' is set to the symbol `ask'. If
  277. the variable is t instead of `ask', use
  278. `message-subject-trailing-was-regexp' instead.
  279. It is okay to create some false positives here, as the user is asked."
  280. :version "22.1"
  281. :group 'message-various
  282. :link '(custom-manual "(message)Message Headers")
  283. :type 'regexp)
  284. (defcustom message-subject-trailing-was-regexp
  285. "[ \t]*\\((*[Ww][Aa][Ss]:[ \t]*.*)\\)"
  286. "*Regexp matching \"(was: <old subject>)\" in the subject line.
  287. If `message-subject-trailing-was-query' is set to t, the subject is
  288. matched against `message-subject-trailing-was-regexp' in
  289. `message-strip-subject-trailing-was'. You should use a regexp creating very
  290. few false positives here."
  291. :version "22.1"
  292. :group 'message-various
  293. :link '(custom-manual "(message)Message Headers")
  294. :type 'regexp)
  295. ;;; marking inserted text
  296. (defcustom message-mark-insert-begin
  297. "--8<---------------cut here---------------start------------->8---\n"
  298. "How to mark the beginning of some inserted text."
  299. :version "22.1"
  300. :type 'string
  301. :link '(custom-manual "(message)Insertion Variables")
  302. :group 'message-various)
  303. (defcustom message-mark-insert-end
  304. "--8<---------------cut here---------------end--------------->8---\n"
  305. "How to mark the end of some inserted text."
  306. :version "22.1"
  307. :type 'string
  308. :link '(custom-manual "(message)Insertion Variables")
  309. :group 'message-various)
  310. (defcustom message-archive-header "X-No-Archive: Yes\n"
  311. "Header to insert when you don't want your article to be archived.
  312. Archives \(such as groups.google.com\) respect this header."
  313. :version "22.1"
  314. :type 'string
  315. :link '(custom-manual "(message)Header Commands")
  316. :group 'message-various)
  317. (defcustom message-archive-note
  318. "X-No-Archive: Yes - save http://groups.google.com/"
  319. "Note to insert why you wouldn't want this posting archived.
  320. If nil, don't insert any text in the body."
  321. :version "22.1"
  322. :type '(radio string (const nil))
  323. :link '(custom-manual "(message)Header Commands")
  324. :group 'message-various)
  325. ;;; Crossposts and Followups
  326. ;; inspired by JoH-followup-to by Jochem Huhman <joh at gmx.de>
  327. ;; new suggestions by R. Weikusat <rw at another.de>
  328. (defvar message-cross-post-old-target nil
  329. "Old target for cross-posts or follow-ups.")
  330. (make-variable-buffer-local 'message-cross-post-old-target)
  331. (defcustom message-cross-post-default t
  332. "When non-nil `message-cross-post-followup-to' will perform a crosspost.
  333. If nil, `message-cross-post-followup-to' will only do a followup. Note that
  334. you can explicitly override this setting by calling
  335. `message-cross-post-followup-to' with a prefix."
  336. :version "22.1"
  337. :type 'boolean
  338. :group 'message-various)
  339. (defcustom message-cross-post-note "Crosspost & Followup-To: "
  340. "Note to insert before signature to notify of cross-post and follow-up."
  341. :version "22.1"
  342. :type 'string
  343. :group 'message-various)
  344. (defcustom message-followup-to-note "Followup-To: "
  345. "Note to insert before signature to notify of follow-up only."
  346. :version "22.1"
  347. :type 'string
  348. :group 'message-various)
  349. (defcustom message-cross-post-note-function 'message-cross-post-insert-note
  350. "Function to use to insert note about Crosspost or Followup-To.
  351. The function will be called with four arguments. The function should not only
  352. insert a note, but also ensure old notes are deleted. See the documentation
  353. for `message-cross-post-insert-note'."
  354. :version "22.1"
  355. :type 'function
  356. :group 'message-various)
  357. ;;; End of variables adopted from `message-utils.el'.
  358. (defcustom message-signature-separator "^-- $"
  359. "Regexp matching the signature separator.
  360. This variable is used to strip off the signature from quoted text
  361. when `message-cite-function' is
  362. `message-cite-original-without-signature'. Most useful values
  363. are \"^-- $\" (strict) and \"^-- *$\" (loose; allow missing
  364. whitespace)."
  365. :type '(choice (const :tag "strict" "^-- $")
  366. (const :tag "loose" "^-- *$")
  367. regexp)
  368. :version "22.3" ;; Gnus 5.10.12 (changed default)
  369. :link '(custom-manual "(message)Various Message Variables")
  370. :group 'message-various)
  371. (defcustom message-elide-ellipsis "\n[...]\n\n"
  372. "*The string which is inserted for elided text.
  373. This is a format-spec string, and you can use %l to say how many
  374. lines were removed, and %c to say how many characters were
  375. removed."
  376. :type 'string
  377. :link '(custom-manual "(message)Various Commands")
  378. :group 'message-various)
  379. (defcustom message-interactive mail-interactive
  380. "Non-nil means when sending a message wait for and display errors.
  381. A value of nil means let mailer mail back a message to report errors."
  382. :version "23.2"
  383. :group 'message-sending
  384. :group 'message-mail
  385. :link '(custom-manual "(message)Sending Variables")
  386. :type 'boolean)
  387. (defcustom message-confirm-send nil
  388. "When non-nil, ask for confirmation when sending a message."
  389. :group 'message-sending
  390. :group 'message-mail
  391. :version "23.1" ;; No Gnus
  392. :link '(custom-manual "(message)Sending Variables")
  393. :type 'boolean)
  394. (defcustom message-generate-new-buffers 'unsent
  395. "*Say whether to create a new message buffer to compose a message.
  396. Valid values include:
  397. nil
  398. Generate the buffer name in the Message way (e.g., *mail*, *news*,
  399. *mail to whom*, *news on group*, etc.) and continue editing in the
  400. existing buffer of that name. If there is no such buffer, it will
  401. be newly created.
  402. `unique' or t
  403. Create the new buffer with the name generated in the Message way.
  404. `unsent'
  405. Similar to `unique' but the buffer name begins with \"*unsent \".
  406. `standard'
  407. Similar to nil but the buffer name is simpler like *mail message*.
  408. function
  409. If this is a function, call that function with three parameters:
  410. The type, the To address and the group name (any of these may be nil).
  411. The function should return the new buffer name."
  412. :version "24.1"
  413. :group 'message-buffers
  414. :link '(custom-manual "(message)Message Buffers")
  415. :type '(choice (const nil)
  416. (sexp :tag "unique" :format "unique\n" :value unique
  417. :match (lambda (widget value) (memq value '(unique t))))
  418. (const unsent)
  419. (const standard)
  420. (function :format "\n %{%t%}: %v")))
  421. (defcustom message-kill-buffer-on-exit nil
  422. "*Non-nil means that the message buffer will be killed after sending a message."
  423. :group 'message-buffers
  424. :link '(custom-manual "(message)Message Buffers")
  425. :type 'boolean)
  426. (defcustom message-kill-buffer-query t
  427. "*Non-nil means that killing a modified message buffer has to be confirmed.
  428. This is used by `message-kill-buffer'."
  429. :version "23.1" ;; No Gnus
  430. :group 'message-buffers
  431. :type 'boolean)
  432. (defcustom message-user-organization
  433. (or (getenv "ORGANIZATION") t)
  434. "String to be used as an Organization header.
  435. If t, use `message-user-organization-file'."
  436. :group 'message-headers
  437. :type '(choice string
  438. (const :tag "consult file" t)))
  439. (defcustom message-user-organization-file
  440. (let (orgfile)
  441. (dolist (f (list "/etc/organization"
  442. "/etc/news/organization"
  443. "/usr/lib/news/organization"))
  444. (when (file-readable-p f)
  445. (setq orgfile f)))
  446. orgfile)
  447. "*Local news organization file."
  448. :type 'file
  449. :link '(custom-manual "(message)News Headers")
  450. :group 'message-headers)
  451. (defcustom message-make-forward-subject-function
  452. #'message-forward-subject-name-subject
  453. "*List of functions called to generate subject headers for forwarded messages.
  454. The subject generated by the previous function is passed into each
  455. successive function.
  456. The provided functions are:
  457. * `message-forward-subject-author-subject' Source of article (author or
  458. newsgroup), in brackets followed by the subject
  459. * `message-forward-subject-name-subject' Source of article (name of author
  460. or newsgroup), in brackets followed by the subject
  461. * `message-forward-subject-fwd' Subject of article with 'Fwd:' prepended
  462. to it."
  463. :group 'message-forwarding
  464. :link '(custom-manual "(message)Forwarding")
  465. :type '(radio (function-item message-forward-subject-author-subject)
  466. (function-item message-forward-subject-fwd)
  467. (function-item message-forward-subject-name-subject)
  468. (repeat :tag "List of functions" function)))
  469. (defcustom message-forward-as-mime t
  470. "*Non-nil means forward messages as an inline/rfc822 MIME section.
  471. Otherwise, directly inline the old message in the forwarded message."
  472. :version "21.1"
  473. :group 'message-forwarding
  474. :link '(custom-manual "(message)Forwarding")
  475. :type 'boolean)
  476. (defcustom message-forward-show-mml 'best
  477. "*Non-nil means show forwarded messages as MML (decoded from MIME).
  478. Otherwise, forwarded messages are unchanged.
  479. Can also be the symbol `best' to indicate that MML should be
  480. used, except when it is a bad idea to use MML. One example where
  481. it is a bad idea is when forwarding a signed or encrypted
  482. message, because converting MIME to MML would invalidate the
  483. digital signature."
  484. :version "21.1"
  485. :group 'message-forwarding
  486. :type '(choice (const :tag "use MML" t)
  487. (const :tag "don't use MML " nil)
  488. (const :tag "use MML when appropriate" best)))
  489. (defcustom message-forward-before-signature t
  490. "*Non-nil means put forwarded message before signature, else after."
  491. :group 'message-forwarding
  492. :type 'boolean)
  493. (defcustom message-wash-forwarded-subjects nil
  494. "*Non-nil means try to remove as much cruft as possible from the subject.
  495. Done before generating the new subject of a forward."
  496. :group 'message-forwarding
  497. :link '(custom-manual "(message)Forwarding")
  498. :type 'boolean)
  499. (defcustom message-ignored-resent-headers
  500. ;; `Delivered-To' needs to be removed because some mailers use it to
  501. ;; detect loops, so if you resend a message to an address that ultimately
  502. ;; comes back to you (e.g. a mailing-list to which you subscribe, in which
  503. ;; case you may be removed from the list on the grounds that mail to you
  504. ;; bounced with a "mailing loop" error).
  505. "^Return-receipt\\|^X-Gnus\\|^Gnus-Warning:\\|^>?From \\|^Delivered-To:"
  506. "*All headers that match this regexp will be deleted when resending a message."
  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. :version "21.1"
  518. :group 'message-forwarding
  519. :type '(repeat :value-to-internal (lambda (widget value)
  520. (custom-split-regexp-maybe value))
  521. :match (lambda (widget value)
  522. (or (stringp value)
  523. (widget-editable-list-match widget value)))
  524. regexp))
  525. (defcustom message-ignored-cited-headers "."
  526. "*Delete these headers from the messages you yank."
  527. :group 'message-insertion
  528. :link '(custom-manual "(message)Insertion Variables")
  529. :type 'regexp)
  530. (defcustom message-cite-prefix-regexp mail-citation-prefix-regexp
  531. "*Regexp matching the longest possible citation prefix on a line."
  532. :version "24.1"
  533. :group 'message-insertion
  534. :link '(custom-manual "(message)Insertion Variables")
  535. :type 'regexp
  536. :set (lambda (symbol value)
  537. (prog1
  538. (custom-set-default symbol value)
  539. (if (boundp 'gnus-message-cite-prefix-regexp)
  540. (setq gnus-message-cite-prefix-regexp
  541. (concat "^\\(?:" value "\\)"))))))
  542. (defcustom message-cancel-message "I am canceling my own article.\n"
  543. "Message to be inserted in the cancel message."
  544. :group 'message-interface
  545. :link '(custom-manual "(message)Canceling News")
  546. :type 'string)
  547. (defun message-send-mail-function ()
  548. "Return suitable value for the variable `message-send-mail-function'."
  549. (cond ((and (require 'sendmail)
  550. (boundp 'sendmail-program)
  551. sendmail-program
  552. (executable-find sendmail-program))
  553. 'message-send-mail-with-sendmail)
  554. ((and (locate-library "smtpmail")
  555. (boundp 'smtpmail-default-smtp-server)
  556. smtpmail-default-smtp-server)
  557. 'message-smtpmail-send-it)
  558. ((locate-library "mailclient")
  559. 'message-send-mail-with-mailclient)
  560. (t
  561. (error "Don't know how to send mail. Please customize `message-send-mail-function'"))))
  562. (defun message-default-send-mail-function ()
  563. (cond ((eq send-mail-function 'smtpmail-send-it) 'message-smtpmail-send-it)
  564. ((eq send-mail-function 'feedmail-send-it) 'feedmail-send-it)
  565. ((eq send-mail-function 'sendmail-query-once) 'sendmail-query-once)
  566. ((eq send-mail-function 'mailclient-send-it)
  567. 'message-send-mail-with-mailclient)
  568. (t (message-send-mail-function))))
  569. ;; Useful to set in site-init.el
  570. (defcustom message-send-mail-function (message-default-send-mail-function)
  571. "Function to call to send the current buffer as mail.
  572. The headers should be delimited by a line whose contents match the
  573. variable `mail-header-separator'.
  574. Valid values include `message-send-mail-with-sendmail'
  575. `message-send-mail-with-mh', `message-send-mail-with-qmail',
  576. `message-smtpmail-send-it', `smtpmail-send-it',
  577. `feedmail-send-it' and `message-send-mail-with-mailclient'. The
  578. default is system dependent and determined by the function
  579. `message-send-mail-function'.
  580. See also `send-mail-function'."
  581. :type '(radio (function-item message-send-mail-with-sendmail)
  582. (function-item message-send-mail-with-mh)
  583. (function-item message-send-mail-with-qmail)
  584. (function-item message-smtpmail-send-it)
  585. (function-item smtpmail-send-it)
  586. (function-item feedmail-send-it)
  587. (function-item message-send-mail-with-mailclient
  588. :tag "Use Mailclient package")
  589. (function :tag "Other"))
  590. :group 'message-sending
  591. :version "23.2"
  592. :initialize 'custom-initialize-default
  593. :link '(custom-manual "(message)Mail Variables")
  594. :group 'message-mail)
  595. (defcustom message-send-news-function 'message-send-news
  596. "Function to call to send the current buffer as news.
  597. The headers should be delimited by a line whose contents match the
  598. variable `mail-header-separator'."
  599. :group 'message-sending
  600. :group 'message-news
  601. :link '(custom-manual "(message)News Variables")
  602. :type 'function)
  603. (defcustom message-reply-to-function nil
  604. "If non-nil, function that should return a list of headers.
  605. This function should pick out addresses from the To, Cc, and From headers
  606. and respond with new To and Cc headers."
  607. :group 'message-interface
  608. :link '(custom-manual "(message)Reply")
  609. :type '(choice function (const nil)))
  610. (defcustom message-wide-reply-to-function nil
  611. "If non-nil, function that should return a list of headers.
  612. This function should pick out addresses from the To, Cc, and From headers
  613. and respond with new To and Cc headers."
  614. :group 'message-interface
  615. :link '(custom-manual "(message)Wide Reply")
  616. :type '(choice function (const nil)))
  617. (defcustom message-followup-to-function nil
  618. "If non-nil, function that should return a list of headers.
  619. This function should pick out addresses from the To, Cc, and From headers
  620. and respond with new To and Cc headers."
  621. :group 'message-interface
  622. :link '(custom-manual "(message)Followup")
  623. :type '(choice function (const nil)))
  624. (defcustom message-extra-wide-headers nil
  625. "If non-nil, a list of additional address headers.
  626. These are used when composing a wide reply."
  627. :group 'message-sending
  628. :type '(repeat string))
  629. (defcustom message-use-followup-to 'ask
  630. "*Specifies what to do with Followup-To header.
  631. If nil, always ignore the header. If it is t, use its value, but
  632. query before using the \"poster\" value. If it is the symbol `ask',
  633. always query the user whether to use the value. If it is the symbol
  634. `use', always use the value."
  635. :group 'message-interface
  636. :link '(custom-manual "(message)Followup")
  637. :type '(choice (const :tag "ignore" nil)
  638. (const :tag "use & query" t)
  639. (const use)
  640. (const ask)))
  641. (defcustom message-use-mail-followup-to 'use
  642. "*Specifies what to do with Mail-Followup-To header.
  643. If nil, always ignore the header. If it is the symbol `ask', always
  644. query the user whether to use the value. If it is the symbol `use',
  645. always use the value."
  646. :version "22.1"
  647. :group 'message-interface
  648. :link '(custom-manual "(message)Mailing Lists")
  649. :type '(choice (const :tag "ignore" nil)
  650. (const use)
  651. (const ask)))
  652. (defcustom message-subscribed-address-functions nil
  653. "*Specifies functions for determining list subscription.
  654. If nil, do not attempt to determine list subscription with functions.
  655. If non-nil, this variable contains a list of functions which return
  656. regular expressions to match lists. These functions can be used in
  657. conjunction with `message-subscribed-regexps' and
  658. `message-subscribed-addresses'."
  659. :version "22.1"
  660. :group 'message-interface
  661. :link '(custom-manual "(message)Mailing Lists")
  662. :type '(repeat sexp))
  663. (defcustom message-subscribed-address-file nil
  664. "*A file containing addresses the user is subscribed to.
  665. If nil, do not look at any files to determine list subscriptions. If
  666. non-nil, each line of this file should be a mailing list address."
  667. :version "22.1"
  668. :group 'message-interface
  669. :link '(custom-manual "(message)Mailing Lists")
  670. :type '(radio file (const nil)))
  671. (defcustom message-subscribed-addresses nil
  672. "*Specifies a list of addresses the user is subscribed to.
  673. If nil, do not use any predefined list subscriptions. This list of
  674. addresses can be used in conjunction with
  675. `message-subscribed-address-functions' and `message-subscribed-regexps'."
  676. :version "22.1"
  677. :group 'message-interface
  678. :link '(custom-manual "(message)Mailing Lists")
  679. :type '(repeat string))
  680. (defcustom message-subscribed-regexps nil
  681. "*Specifies a list of addresses the user is subscribed to.
  682. If nil, do not use any predefined list subscriptions. This list of
  683. regular expressions can be used in conjunction with
  684. `message-subscribed-address-functions' and `message-subscribed-addresses'."
  685. :version "22.1"
  686. :group 'message-interface
  687. :link '(custom-manual "(message)Mailing Lists")
  688. :type '(repeat regexp))
  689. (defcustom message-allow-no-recipients 'ask
  690. "Specifies what to do when there are no recipients other than Gcc/Fcc.
  691. If it is the symbol `always', the posting is allowed. If it is the
  692. symbol `never', the posting is not allowed. If it is the symbol
  693. `ask', you are prompted."
  694. :version "22.1"
  695. :group 'message-interface
  696. :link '(custom-manual "(message)Message Headers")
  697. :type '(choice (const always)
  698. (const never)
  699. (const ask)))
  700. (defcustom message-sendmail-f-is-evil nil
  701. "*Non-nil means don't add \"-f username\" to the sendmail command line.
  702. Doing so would be even more evil than leaving it out."
  703. :group 'message-sending
  704. :link '(custom-manual "(message)Mail Variables")
  705. :type 'boolean)
  706. (defcustom message-sendmail-envelope-from
  707. ;; `mail-envelope-from' is unavailable unless sendmail.el is loaded.
  708. (if (boundp 'mail-envelope-from) mail-envelope-from)
  709. "*Envelope-from when sending mail with sendmail.
  710. If this is nil, use `user-mail-address'. If it is the symbol
  711. `header', use the From: header of the message."
  712. :version "23.2"
  713. :type '(choice (string :tag "From name")
  714. (const :tag "Use From: header from message" header)
  715. (const :tag "Use `user-mail-address'" nil))
  716. :link '(custom-manual "(message)Mail Variables")
  717. :group 'message-sending)
  718. (defcustom message-sendmail-extra-arguments nil
  719. "Additional arguments to `sendmail-program'."
  720. ;; E.g. '("-a" "account") for msmtp
  721. :version "23.1" ;; No Gnus
  722. :type '(repeat string)
  723. ;; :link '(custom-manual "(message)Mail Variables")
  724. :group 'message-sending)
  725. ;; qmail-related stuff
  726. (defcustom message-qmail-inject-program "/var/qmail/bin/qmail-inject"
  727. "Location of the qmail-inject program."
  728. :group 'message-sending
  729. :link '(custom-manual "(message)Mail Variables")
  730. :type 'file)
  731. (defcustom message-qmail-inject-args nil
  732. "Arguments passed to qmail-inject programs.
  733. This should be a list of strings, one string for each argument.
  734. It may also be a function.
  735. For e.g., if you wish to set the envelope sender address so that bounces
  736. go to the right place or to deal with listserv's usage of that address, you
  737. might set this variable to '(\"-f\" \"you@some.where\")."
  738. :group 'message-sending
  739. :link '(custom-manual "(message)Mail Variables")
  740. :type '(choice (function)
  741. (repeat string)))
  742. (defvar gnus-post-method)
  743. (defvar gnus-select-method)
  744. (defcustom message-post-method
  745. (cond ((and (boundp 'gnus-post-method)
  746. (listp gnus-post-method)
  747. gnus-post-method)
  748. gnus-post-method)
  749. ((boundp 'gnus-select-method)
  750. gnus-select-method)
  751. (t '(nnspool "")))
  752. "*Method used to post news.
  753. Note that when posting from inside Gnus, for instance, this
  754. variable isn't used."
  755. :group 'message-news
  756. :group 'message-sending
  757. ;; This should be the `gnus-select-method' widget, but that might
  758. ;; create a dependence to `gnus.el'.
  759. :type 'sexp)
  760. (defcustom message-generate-headers-first nil
  761. "Which headers should be generated before starting to compose a message.
  762. If t, generate all required headers. This can also be a list of headers to
  763. generate. The variables `message-required-news-headers' and
  764. `message-required-mail-headers' specify which headers to generate.
  765. Note that the variable `message-deletable-headers' specifies headers which
  766. are to be deleted and then re-generated before sending, so this variable
  767. will not have a visible effect for those headers."
  768. :group 'message-headers
  769. :link '(custom-manual "(message)Message Headers")
  770. :type '(choice (const :tag "None" nil)
  771. (const :tag "All" t)
  772. (repeat (sexp :tag "Header"))))
  773. (defcustom message-fill-column 72
  774. "Column beyond which automatic line-wrapping should happen.
  775. Local value for message buffers. If non-nil, also turn on
  776. auto-fill in message buffers."
  777. :group 'message-various
  778. ;; :link '(custom-manual "(message)Message Headers")
  779. :type '(choice (const :tag "Don't turn on auto fill" nil)
  780. (integer)))
  781. (defcustom message-setup-hook nil
  782. "Normal hook, run each time a new outgoing message is initialized.
  783. The function `message-setup' runs this hook."
  784. :group 'message-various
  785. :link '(custom-manual "(message)Various Message Variables")
  786. :type 'hook)
  787. (defcustom message-cancel-hook nil
  788. "Hook run when canceling articles."
  789. :group 'message-various
  790. :link '(custom-manual "(message)Various Message Variables")
  791. :type 'hook)
  792. (defcustom message-signature-setup-hook nil
  793. "Normal hook, run each time a new outgoing message is initialized.
  794. It is run after the headers have been inserted and before
  795. the signature is inserted."
  796. :group 'message-various
  797. :link '(custom-manual "(message)Various Message Variables")
  798. :type 'hook)
  799. (defcustom message-mode-hook nil
  800. "Hook run in message mode buffers."
  801. :group 'message-various
  802. :type 'hook)
  803. (defcustom message-header-hook nil
  804. "Hook run in a message mode buffer narrowed to the headers."
  805. :group 'message-various
  806. :type 'hook)
  807. (defcustom message-header-setup-hook nil
  808. "Hook called narrowed to the headers when setting up a message buffer."
  809. :group 'message-various
  810. :link '(custom-manual "(message)Various Message Variables")
  811. :type 'hook)
  812. (defcustom message-minibuffer-local-map
  813. (let ((map (make-sparse-keymap 'message-minibuffer-local-map)))
  814. (set-keymap-parent map minibuffer-local-map)
  815. map)
  816. "Keymap for `message-read-from-minibuffer'."
  817. :version "22.1"
  818. :group 'message-various)
  819. (defcustom message-citation-line-function 'message-insert-citation-line
  820. "*Function called to insert the \"Whomever writes:\" line.
  821. Predefined functions include `message-insert-citation-line' and
  822. `message-insert-formatted-citation-line' (see the variable
  823. `message-citation-line-format').
  824. Note that Gnus provides a feature where the reader can click on
  825. `writes:' to hide the cited text. If you change this line too much,
  826. people who read your message will have to change their Gnus
  827. configuration. See the variable `gnus-cite-attribution-suffix'."
  828. :type '(choice
  829. (function-item :tag "plain" message-insert-citation-line)
  830. (function-item :tag "formatted" message-insert-formatted-citation-line)
  831. (function :tag "Other"))
  832. :link '(custom-manual "(message)Insertion Variables")
  833. :group 'message-insertion)
  834. (defcustom message-citation-line-format "On %a, %b %d %Y, %N wrote:\n"
  835. "Format of the \"Whomever writes:\" line.
  836. The string is formatted using `format-spec'. The following
  837. constructs are replaced:
  838. %f The full From, e.g. \"John Doe <john.doe@example.invalid>\".
  839. %n The mail address, e.g. \"john.doe@example.invalid\".
  840. %N The real name if present, e.g.: \"John Doe\", else fall
  841. back to the mail address.
  842. %F The first name if present, e.g.: \"John\".
  843. %L The last name if present, e.g.: \"Doe\".
  844. All other format specifiers are passed to `format-time-string'
  845. which is called using the date from the article your replying to.
  846. Extracting the first (%F) and last name (%L) is done
  847. heuristically, so you should always check it yourself.
  848. Please also read the note in the documentation of
  849. `message-citation-line-function'."
  850. :type '(choice (const :tag "Plain" "%f writes:")
  851. (const :tag "Include date" "On %a, %b %d %Y, %n wrote:")
  852. string)
  853. :link '(custom-manual "(message)Insertion Variables")
  854. :version "23.1" ;; No Gnus
  855. :group 'message-insertion)
  856. (defcustom message-yank-prefix mail-yank-prefix
  857. "*Prefix inserted on the lines of yanked messages.
  858. Fix `message-cite-prefix-regexp' if it is set to an abnormal value.
  859. See also `message-yank-cited-prefix' and `message-yank-empty-prefix'."
  860. :version "23.2"
  861. :type 'string
  862. :link '(custom-manual "(message)Insertion Variables")
  863. :group 'message-insertion)
  864. (defcustom message-yank-cited-prefix ">"
  865. "*Prefix inserted on cited lines of yanked messages.
  866. Fix `message-cite-prefix-regexp' if it is set to an abnormal value.
  867. See also `message-yank-prefix' and `message-yank-empty-prefix'."
  868. :version "22.1"
  869. :type 'string
  870. :link '(custom-manual "(message)Insertion Variables")
  871. :group 'message-insertion)
  872. (defcustom message-yank-empty-prefix ">"
  873. "*Prefix inserted on empty lines of yanked messages.
  874. See also `message-yank-prefix' and `message-yank-cited-prefix'."
  875. :version "22.1"
  876. :type 'string
  877. :link '(custom-manual "(message)Insertion Variables")
  878. :group 'message-insertion)
  879. (defcustom message-indentation-spaces mail-indentation-spaces
  880. "*Number of spaces to insert at the beginning of each cited line.
  881. Used by `message-yank-original' via `message-yank-cite'."
  882. :version "23.2"
  883. :group 'message-insertion
  884. :link '(custom-manual "(message)Insertion Variables")
  885. :type 'integer)
  886. (defcustom message-cite-function 'message-cite-original-without-signature
  887. "*Function for citing an original message.
  888. Predefined functions include `message-cite-original' and
  889. `message-cite-original-without-signature'.
  890. Note that these functions use `mail-citation-hook' if that is non-nil."
  891. :type '(radio (function-item message-cite-original)
  892. (function-item message-cite-original-without-signature)
  893. (function-item sc-cite-original)
  894. (function :tag "Other"))
  895. :link '(custom-manual "(message)Insertion Variables")
  896. :version "22.3" ;; Gnus 5.10.12 (changed default)
  897. :group 'message-insertion)
  898. (defcustom message-indent-citation-function 'message-indent-citation
  899. "*Function for modifying a citation just inserted in the mail buffer.
  900. This can also be a list of functions. Each function can find the
  901. citation between (point) and (mark t). And each function should leave
  902. point and mark around the citation text as modified."
  903. :type 'function
  904. :link '(custom-manual "(message)Insertion Variables")
  905. :group 'message-insertion)
  906. (defcustom message-signature mail-signature
  907. "*String to be inserted at the end of the message buffer.
  908. If t, the `message-signature-file' file will be inserted instead.
  909. If a function, the result from the function will be used instead.
  910. If a form, the result from the form will be used instead."
  911. :version "23.2"
  912. :type 'sexp
  913. :link '(custom-manual "(message)Insertion Variables")
  914. :group 'message-insertion)
  915. (defcustom message-signature-file mail-signature-file
  916. "*Name of file containing the text inserted at end of message buffer.
  917. Ignored if the named file doesn't exist.
  918. If nil, don't insert a signature.
  919. If a path is specified, the value of `message-signature-directory' is ignored,
  920. even if set."
  921. :version "23.2"
  922. :type '(choice file (const :tags "None" nil))
  923. :link '(custom-manual "(message)Insertion Variables")
  924. :group 'message-insertion)
  925. (defcustom message-signature-directory nil
  926. "*Name of directory containing signature files.
  927. Comes in handy if you have many such files, handled via posting styles for
  928. instance.
  929. If nil, `message-signature-file' is expected to specify the directory if
  930. needed."
  931. :type '(choice string (const :tags "None" nil))
  932. :link '(custom-manual "(message)Insertion Variables")
  933. :group 'message-insertion)
  934. (defcustom message-signature-insert-empty-line t
  935. "*If non-nil, insert an empty line before the signature separator."
  936. :version "22.1"
  937. :type 'boolean
  938. :link '(custom-manual "(message)Insertion Variables")
  939. :group 'message-insertion)
  940. (defcustom message-cite-reply-position 'traditional
  941. "*Where the reply should be positioned.
  942. If `traditional', reply inline.
  943. If `above', reply above quoted text.
  944. If `below', reply below quoted text.
  945. Note: Many newsgroups frown upon nontraditional reply styles. You
  946. probably want to set this variable only for specific groups,
  947. e.g. using `gnus-posting-styles':
  948. (eval (set (make-local-variable 'message-cite-reply-position) 'above))"
  949. :version "24.1"
  950. :type '(choice (const :tag "Reply inline" 'traditional)
  951. (const :tag "Reply above" 'above)
  952. (const :tag "Reply below" 'below))
  953. :group 'message-insertion)
  954. (defcustom message-cite-style nil
  955. "*The overall style to be used when yanking cited text.
  956. Value is either `nil' (no variable overrides) or a let-style list
  957. of pairs (VARIABLE VALUE) that will be bound in
  958. `message-yank-original' to do the quoting.
  959. Presets to impersonate popular mail agents are found in the
  960. message-cite-style-* variables. This variable is intended for
  961. use in `gnus-posting-styles', such as:
  962. ((posting-from-work-p) (eval (set (make-local-variable 'message-cite-style) message-cite-style-outlook)))"
  963. :version "24.1"
  964. :group 'message-insertion
  965. :type '(choice (const :tag "Do not override variables" :value nil)
  966. (const :tag "MS Outlook" :value message-cite-style-outlook)
  967. (const :tag "Mozilla Thunderbird" :value message-cite-style-thunderbird)
  968. (const :tag "Gmail" :value message-cite-style-gmail)
  969. (variable :tag "User-specified")))
  970. (defconst message-cite-style-outlook
  971. '((message-cite-function 'message-cite-original)
  972. (message-citation-line-function 'message-insert-formatted-citation-line)
  973. (message-cite-reply-position 'above)
  974. (message-yank-prefix "")
  975. (message-yank-cited-prefix "")
  976. (message-yank-empty-prefix "")
  977. (message-citation-line-format "\n\n-----------------------\nOn %a, %b %d %Y, %N wrote:\n"))
  978. "Message citation style used by MS Outlook. Use with message-cite-style.")
  979. (defconst message-cite-style-thunderbird
  980. '((message-cite-function 'message-cite-original)
  981. (message-citation-line-function 'message-insert-formatted-citation-line)
  982. (message-cite-reply-position 'above)
  983. (message-yank-prefix "> ")
  984. (message-yank-cited-prefix ">")
  985. (message-yank-empty-prefix ">")
  986. (message-citation-line-format "On %D %R %p, %N wrote:"))
  987. "Message citation style used by Mozilla Thunderbird. Use with message-cite-style.")
  988. (defconst message-cite-style-gmail
  989. '((message-cite-function 'message-cite-original)
  990. (message-citation-line-function 'message-insert-formatted-citation-line)
  991. (message-cite-reply-position 'above)
  992. (message-yank-prefix " ")
  993. (message-yank-cited-prefix " ")
  994. (message-yank-empty-prefix " ")
  995. (message-citation-line-format "On %e %B %Y %R, %f wrote:\n"))
  996. "Message citation style used by Gmail. Use with message-cite-style.")
  997. (defcustom message-distribution-function nil
  998. "*Function called to return a Distribution header."
  999. :group 'message-news
  1000. :group 'message-headers
  1001. :link '(custom-manual "(message)News Headers")
  1002. :type '(choice function (const nil)))
  1003. (defcustom message-expires 14
  1004. "Number of days before your article expires."
  1005. :group 'message-news
  1006. :group 'message-headers
  1007. :link '(custom-manual "(message)News Headers")
  1008. :type 'integer)
  1009. (defcustom message-user-path nil
  1010. "If nil, use the NNTP server name in the Path header.
  1011. If stringp, use this; if non-nil, use no host name (user name only)."
  1012. :group 'message-news
  1013. :group 'message-headers
  1014. :link '(custom-manual "(message)News Headers")
  1015. :type '(choice (const :tag "nntp" nil)
  1016. (string :tag "name")
  1017. (sexp :tag "none" :format "%t" t)))
  1018. ;; This can be the name of a buffer, or a cons cell (FUNCTION . ARGS)
  1019. ;; for yanking the original buffer.
  1020. (defvar message-reply-buffer nil)
  1021. (defvar message-reply-headers nil
  1022. "The headers of the current replied article.
  1023. It is a vector of the following headers:
  1024. \[number subject from date id references chars lines xref extra].")
  1025. (defvar message-newsreader nil)
  1026. (defvar message-mailer nil)
  1027. (defvar message-sent-message-via nil)
  1028. (defvar message-checksum nil)
  1029. (defvar message-send-actions nil
  1030. "A list of actions to be performed upon successful sending of a message.")
  1031. (defvar message-return-action nil
  1032. "Action to return to the caller after sending or postponing a message.")
  1033. (defvar message-exit-actions nil
  1034. "A list of actions to be performed upon exiting after sending a message.")
  1035. (defvar message-kill-actions nil
  1036. "A list of actions to be performed before killing a message buffer.")
  1037. (defvar message-postpone-actions nil
  1038. "A list of actions to be performed after postponing a message.")
  1039. (define-widget 'message-header-lines 'text
  1040. "All header lines must be LFD terminated."
  1041. :format "%{%t%}:%n%v"
  1042. :valid-regexp "^\\'"
  1043. :error "All header lines must be newline terminated")
  1044. (defcustom message-default-headers ""
  1045. "Header lines to be inserted in outgoing messages.
  1046. This can be set to a string containing or a function returning
  1047. header lines to be inserted before you edit the message, so you
  1048. can edit or delete these lines. If set to a function, it is
  1049. called and its result is inserted."
  1050. :version "23.2"
  1051. :group 'message-headers
  1052. :link '(custom-manual "(message)Message Headers")
  1053. :type '(choice
  1054. (message-header-lines :tag "String")
  1055. (function :tag "Function")))
  1056. (defcustom message-default-mail-headers
  1057. ;; Ease the transition from mail-mode to message-mode. See bugs#4431, 5555.
  1058. (concat (if (and (boundp 'mail-default-reply-to)
  1059. (stringp mail-default-reply-to))
  1060. (format "Reply-to: %s\n" mail-default-reply-to))
  1061. (if (and (boundp 'mail-self-blind)
  1062. mail-self-blind)
  1063. (format "BCC: %s\n" user-mail-address))
  1064. (if (and (boundp 'mail-archive-file-name)
  1065. (stringp mail-archive-file-name))
  1066. (format "FCC: %s\n" mail-archive-file-name))
  1067. ;; Use the value of `mail-default-headers' if available.
  1068. ;; Note: as for XEmacs 21.4 and 21.5, it is unavailable
  1069. ;; unless sendmail.el is loaded.
  1070. (if (boundp 'mail-default-headers)
  1071. mail-default-headers))
  1072. "*A string of header lines to be inserted in outgoing mails."
  1073. :version "23.2"
  1074. :group 'message-headers
  1075. :group 'message-mail
  1076. :link '(custom-manual "(message)Mail Headers")
  1077. :type 'message-header-lines)
  1078. (defcustom message-default-news-headers ""
  1079. "*A string of header lines to be inserted in outgoing news articles."
  1080. :group 'message-headers
  1081. :group 'message-news
  1082. :link '(custom-manual "(message)News Headers")
  1083. :type 'message-header-lines)
  1084. ;; Note: could use /usr/ucb/mail instead of sendmail;
  1085. ;; options -t, and -v if not interactive.
  1086. (defcustom message-mailer-swallows-blank-line
  1087. (if (and (string-match "sparc-sun-sunos\\(\\'\\|[^5]\\)"
  1088. system-configuration)
  1089. (file-readable-p "/etc/sendmail.cf")
  1090. (with-temp-buffer
  1091. (insert-file-contents "/etc/sendmail.cf")
  1092. (goto-char (point-min))
  1093. (let ((case-fold-search nil))
  1094. (re-search-forward "^OR\\>" nil t))))
  1095. ;; According to RFC822, "The field-name must be composed of printable
  1096. ;; ASCII characters (i. e., characters that have decimal values between
  1097. ;; 33 and 126, except colon)", i. e., any chars except ctl chars,
  1098. ;; space, or colon.
  1099. '(looking-at "[ \t]\\|[][!\"#$%&'()*+,-./0-9;<=>?@A-Z\\\\^_`a-z{|}~]+:"))
  1100. "*Set this non-nil if the system's mailer runs the header and body together.
  1101. \(This problem exists on Sunos 4 when sendmail is run in remote mode.)
  1102. The value should be an expression to test whether the problem will
  1103. actually occur."
  1104. :group 'message-sending
  1105. :link '(custom-manual "(message)Mail Variables")
  1106. :type 'sexp)
  1107. ;;;###autoload
  1108. (define-mail-user-agent 'message-user-agent
  1109. 'message-mail 'message-send-and-exit
  1110. 'message-kill-buffer 'message-send-hook)
  1111. (defvar message-mh-deletable-headers '(Message-ID Date Lines Sender)
  1112. "If non-nil, delete the deletable headers before feeding to mh.")
  1113. (defvar message-send-method-alist
  1114. '((news message-news-p message-send-via-news)
  1115. (mail message-mail-p message-send-via-mail))
  1116. "Alist of ways to send outgoing messages.
  1117. Each element has the form
  1118. \(TYPE PREDICATE FUNCTION)
  1119. where TYPE is a symbol that names the method; PREDICATE is a function
  1120. called without any parameters to determine whether the message is
  1121. a message of type TYPE; and FUNCTION is a function to be called if
  1122. PREDICATE returns non-nil. FUNCTION is called with one parameter --
  1123. the prefix.")
  1124. (defcustom message-mail-alias-type 'abbrev
  1125. "*What alias expansion type to use in Message buffers.
  1126. The default is `abbrev', which uses mailabbrev. `ecomplete' uses
  1127. an electric completion mode. nil switches mail aliases off.
  1128. This can also be a list of values."
  1129. :group 'message
  1130. :link '(custom-manual "(message)Mail Aliases")
  1131. :type '(choice (const :tag "Use Mailabbrev" abbrev)
  1132. (const :tag "Use ecomplete" ecomplete)
  1133. (const :tag "No expansion" nil)))
  1134. (defcustom message-self-insert-commands '(self-insert-command)
  1135. "List of `self-insert-command's used to trigger ecomplete.
  1136. When one of those commands is invoked to enter a character in To or Cc
  1137. header, ecomplete will suggest the candidates of recipients (see also
  1138. `message-mail-alias-type'). If you use some tool to enter non-ASCII
  1139. text and it replaces `self-insert-command' with the other command, e.g.
  1140. `egg-self-insert-command', you may want to add it to this list."
  1141. :group 'message-various
  1142. :type '(repeat function))
  1143. (defcustom message-auto-save-directory
  1144. (if (file-writable-p message-directory)
  1145. (file-name-as-directory (expand-file-name "drafts" message-directory))
  1146. "~/")
  1147. "*Directory where Message auto-saves buffers if Gnus isn't running.
  1148. If nil, Message won't auto-save."
  1149. :group 'message-buffers
  1150. :link '(custom-manual "(message)Various Message Variables")
  1151. :type '(choice directory (const :tag "Don't auto-save" nil)))
  1152. (defcustom message-default-charset
  1153. (and (not (mm-multibyte-p)) 'iso-8859-1)
  1154. "Default charset used in non-MULE Emacsen.
  1155. If nil, you might be asked to input the charset."
  1156. :version "21.1"
  1157. :group 'message
  1158. :link '(custom-manual "(message)Various Message Variables")
  1159. :type 'symbol)
  1160. (defcustom message-dont-reply-to-names
  1161. (and (boundp 'rmail-dont-reply-to-names) rmail-dont-reply-to-names)
  1162. "*Addresses to prune when doing wide replies.
  1163. This can be a regexp or a list of regexps. Also, a value of nil means
  1164. exclude your own user name only."
  1165. :version "21.1"
  1166. :group 'message
  1167. :link '(custom-manual "(message)Wide Reply")
  1168. :type '(choice (const :tag "Yourself" nil)
  1169. regexp
  1170. (repeat :tag "Regexp List" regexp)))
  1171. (defsubst message-dont-reply-to-names ()
  1172. (gmm-regexp-concat message-dont-reply-to-names))
  1173. (defvar message-shoot-gnksa-feet nil
  1174. "*A list of GNKSA feet you are allowed to shoot.
  1175. Gnus gives you all the opportunity you could possibly want for
  1176. shooting yourself in the foot. Also, Gnus allows you to shoot the
  1177. feet of Good Net-Keeping Seal of Approval. The following are foot
  1178. candidates:
  1179. `empty-article' Allow you to post an empty article;
  1180. `quoted-text-only' Allow you to post quoted text only;
  1181. `multiple-copies' Allow you to post multiple copies;
  1182. `cancel-messages' Allow you to cancel or supersede messages from
  1183. your other email addresses;
  1184. `canlock-verify' Allow you to cancel messages without verifying canlock.")
  1185. (defsubst message-gnksa-enable-p (feature)
  1186. (or (not (listp message-shoot-gnksa-feet))
  1187. (memq feature message-shoot-gnksa-feet)))
  1188. (defcustom message-hidden-headers '("^References:" "^Face:" "^X-Face:"
  1189. "^X-Draft-From:")
  1190. "Regexp of headers to be hidden when composing new messages.
  1191. This can also be a list of regexps to match headers. Or a list
  1192. starting with `not' and followed by regexps."
  1193. :version "22.1"
  1194. :group 'message
  1195. :link '(custom-manual "(message)Message Headers")
  1196. :type '(choice
  1197. :format "%{%t%}: %[Value Type%] %v"
  1198. (regexp :menu-tag "regexp" :format "regexp\n%t: %v")
  1199. (repeat :menu-tag "(regexp ...)" :format "(regexp ...)\n%v%i"
  1200. (regexp :format "%t: %v"))
  1201. (cons :menu-tag "(not regexp ...)" :format "(not regexp ...)\n%v"
  1202. (const not)
  1203. (repeat :format "%v%i"
  1204. (regexp :format "%t: %v")))))
  1205. (defcustom message-cite-articles-with-x-no-archive t
  1206. "If non-nil, cite text from articles that has X-No-Archive set."
  1207. :group 'message
  1208. :type 'boolean)
  1209. ;;; Internal variables.
  1210. ;;; Well, not really internal.
  1211. (defvar message-mode-syntax-table
  1212. (let ((table (copy-syntax-table text-mode-syntax-table)))
  1213. (modify-syntax-entry ?% ". " table)
  1214. (modify-syntax-entry ?> ". " table)
  1215. (modify-syntax-entry ?< ". " table)
  1216. table)
  1217. "Syntax table used while in Message mode.")
  1218. (defface message-header-to
  1219. '((((class color)
  1220. (background dark))
  1221. (:foreground "DarkOliveGreen1" :bold t))
  1222. (((class color)
  1223. (background light))
  1224. (:foreground "MidnightBlue" :bold t))
  1225. (t
  1226. (:bold t :italic t)))
  1227. "Face used for displaying From headers."
  1228. :group 'message-faces)
  1229. ;; backward-compatibility alias
  1230. (put 'message-header-to-face 'face-alias 'message-header-to)
  1231. (put 'message-header-to-face 'obsolete-face "22.1")
  1232. (defface message-header-cc
  1233. '((((class color)
  1234. (background dark))
  1235. (:foreground "chartreuse1" :bold t))
  1236. (((class color)
  1237. (background light))
  1238. (:foreground "MidnightBlue"))
  1239. (t
  1240. (:bold t)))
  1241. "Face used for displaying Cc headers."
  1242. :group 'message-faces)
  1243. ;; backward-compatibility alias
  1244. (put 'message-header-cc-face 'face-alias 'message-header-cc)
  1245. (put 'message-header-cc-face 'obsolete-face "22.1")
  1246. (defface message-header-subject
  1247. '((((class color)
  1248. (background dark))
  1249. (:foreground "OliveDrab1"))
  1250. (((class color)
  1251. (background light))
  1252. (:foreground "navy blue" :bold t))
  1253. (t
  1254. (:bold t)))
  1255. "Face used for displaying subject headers."
  1256. :group 'message-faces)
  1257. ;; backward-compatibility alias
  1258. (put 'message-header-subject-face 'face-alias 'message-header-subject)
  1259. (put 'message-header-subject-face 'obsolete-face "22.1")
  1260. (defface message-header-newsgroups
  1261. '((((class color)
  1262. (background dark))
  1263. (:foreground "yellow" :bold t :italic t))
  1264. (((class color)
  1265. (background light))
  1266. (:foreground "blue4" :bold t :italic t))
  1267. (t
  1268. (:bold t :italic t)))
  1269. "Face used for displaying newsgroups headers."
  1270. :group 'message-faces)
  1271. ;; backward-compatibility alias
  1272. (put 'message-header-newsgroups-face 'face-alias 'message-header-newsgroups)
  1273. (put 'message-header-newsgroups-face 'obsolete-face "22.1")
  1274. (defface message-header-other
  1275. '((((class color)
  1276. (background dark))
  1277. (:foreground "VioletRed1"))
  1278. (((class color)
  1279. (background light))
  1280. (:foreground "steel blue"))
  1281. (t
  1282. (:bold t :italic t)))
  1283. "Face used for displaying newsgroups headers."
  1284. :group 'message-faces)
  1285. ;; backward-compatibility alias
  1286. (put 'message-header-other-face 'face-alias 'message-header-other)
  1287. (put 'message-header-other-face 'obsolete-face "22.1")
  1288. (defface message-header-name
  1289. '((((class color)
  1290. (background dark))
  1291. (:foreground "green"))
  1292. (((class color)
  1293. (background light))
  1294. (:foreground "cornflower blue"))
  1295. (t
  1296. (:bold t)))
  1297. "Face used for displaying header names."
  1298. :group 'message-faces)
  1299. ;; backward-compatibility alias
  1300. (put 'message-header-name-face 'face-alias 'message-header-name)
  1301. (put 'message-header-name-face 'obsolete-face "22.1")
  1302. (defface message-header-xheader
  1303. '((((class color)
  1304. (background dark))
  1305. (:foreground "DeepSkyBlue1"))
  1306. (((class color)
  1307. (background light))
  1308. (:foreground "blue"))
  1309. (t
  1310. (:bold t)))
  1311. "Face used for displaying X-Header headers."
  1312. :group 'message-faces)
  1313. ;; backward-compatibility alias
  1314. (put 'message-header-xheader-face 'face-alias 'message-header-xheader)
  1315. (put 'message-header-xheader-face 'obsolete-face "22.1")
  1316. (defface message-separator
  1317. '((((class color)
  1318. (background dark))
  1319. (:foreground "LightSkyBlue1"))
  1320. (((class color)
  1321. (background light))
  1322. (:foreground "brown"))
  1323. (t
  1324. (:bold t)))
  1325. "Face used for displaying the separator."
  1326. :group 'message-faces)
  1327. ;; backward-compatibility alias
  1328. (put 'message-separator-face 'face-alias 'message-separator)
  1329. (put 'message-separator-face 'obsolete-face "22.1")
  1330. (defface message-cited-text
  1331. '((((class color)
  1332. (background dark))
  1333. (:foreground "LightPink1"))
  1334. (((class color)
  1335. (background light))
  1336. (:foreground "red"))
  1337. (t
  1338. (:bold t)))
  1339. "Face used for displaying cited text names."
  1340. :group 'message-faces)
  1341. ;; backward-compatibility alias
  1342. (put 'message-cited-text-face 'face-alias 'message-cited-text)
  1343. (put 'message-cited-text-face 'obsolete-face "22.1")
  1344. (defface message-mml
  1345. '((((class color)
  1346. (background dark))
  1347. (:foreground "MediumSpringGreen"))
  1348. (((class color)
  1349. (background light))
  1350. (:foreground "ForestGreen"))
  1351. (t
  1352. (:bold t)))
  1353. "Face used for displaying MML."
  1354. :group 'message-faces)
  1355. ;; backward-compatibility alias
  1356. (put 'message-mml-face 'face-alias 'message-mml)
  1357. (put 'message-mml-face 'obsolete-face "22.1")
  1358. (defun message-font-lock-make-header-matcher (regexp)
  1359. (let ((form
  1360. `(lambda (limit)
  1361. (let ((start (point)))
  1362. (save-restriction
  1363. (widen)
  1364. (goto-char (point-min))
  1365. (if (re-search-forward
  1366. (concat "^" (regexp-quote mail-header-separator) "$")
  1367. nil t)
  1368. (setq limit (min limit (match-beginning 0))))
  1369. (goto-char start))
  1370. (and (< start limit)
  1371. (re-search-forward ,regexp limit t))))))
  1372. (if (featurep 'bytecomp)
  1373. (byte-compile form)
  1374. form)))
  1375. (defvar message-font-lock-keywords
  1376. (let ((content "[ \t]*\\(.+\\(\n[ \t].*\\)*\\)\n?"))
  1377. `((,(message-font-lock-make-header-matcher
  1378. (concat "^\\([Tt]o:\\)" content))
  1379. (1 'message-header-name)
  1380. (2 'message-header-to nil t))
  1381. (,(message-font-lock-make-header-matcher
  1382. (concat "^\\(^[GBF]?[Cc][Cc]:\\|^[Rr]eply-[Tt]o:\\)" content))
  1383. (1 'message-header-name)
  1384. (2 'message-header-cc nil t))
  1385. (,(message-font-lock-make-header-matcher
  1386. (concat "^\\([Ss]ubject:\\)" content))
  1387. (1 'message-header-name)
  1388. (2 'message-header-subject nil t))
  1389. (,(message-font-lock-make-header-matcher
  1390. (concat "^\\([Nn]ewsgroups:\\|Followup-[Tt]o:\\)" content))
  1391. (1 'message-header-name)
  1392. (2 'message-header-newsgroups nil t))
  1393. (,(message-font-lock-make-header-matcher
  1394. (concat "^\\(X-[A-Za-z0-9-]+:\\|In-Reply-To:\\)" content))
  1395. (1 'message-header-name)
  1396. (2 'message-header-xheader))
  1397. (,(message-font-lock-make-header-matcher
  1398. (concat "^\\([A-Z][^: \n\t]+:\\)" content))
  1399. (1 'message-header-name)
  1400. (2 'message-header-other nil t))
  1401. ,@(if (and mail-header-separator
  1402. (not (equal mail-header-separator "")))
  1403. `((,(concat "^\\(" (regexp-quote mail-header-separator) "\\)$")
  1404. 1 'message-separator))
  1405. nil)
  1406. ((lambda (limit)
  1407. (re-search-forward (concat "^\\("
  1408. message-cite-prefix-regexp
  1409. "\\).*")
  1410. limit t))
  1411. (0 'message-cited-text))
  1412. ("<#/?\\(multipart\\|part\\|external\\|mml\\|secure\\)[^>]*>"
  1413. (0 'message-mml))))
  1414. "Additional expressions to highlight in Message mode.")
  1415. ;; XEmacs does it like this. For Emacs, we have to set the
  1416. ;; `font-lock-defaults' buffer-local variable.
  1417. (put 'message-mode 'font-lock-defaults '(message-font-lock-keywords t))
  1418. (defvar message-face-alist
  1419. '((bold . message-bold-region)
  1420. (underline . underline-region)
  1421. (default . (lambda (b e)
  1422. (message-unbold-region b e)
  1423. (ununderline-region b e))))
  1424. "Alist of mail and news faces for facemenu.
  1425. The cdr of each entry is a function for applying the face to a region.")
  1426. (defcustom message-send-hook nil
  1427. "Hook run before sending messages.
  1428. This hook is run quite early when sending."
  1429. :group 'message-various
  1430. :options '(ispell-message)
  1431. :link '(custom-manual "(message)Various Message Variables")
  1432. :type 'hook)
  1433. (defcustom message-send-mail-hook nil
  1434. "Hook run before sending mail messages.
  1435. This hook is run very late -- just before the message is sent as
  1436. mail."
  1437. :group 'message-various
  1438. :link '(custom-manual "(message)Various Message Variables")
  1439. :type 'hook)
  1440. (defcustom message-send-news-hook nil
  1441. "Hook run before sending news messages.
  1442. This hook is run very late -- just before the message is sent as
  1443. news."
  1444. :group 'message-various
  1445. :link '(custom-manual "(message)Various Message Variables")
  1446. :type 'hook)
  1447. (defcustom message-sent-hook nil
  1448. "Hook run after sending messages."
  1449. :group 'message-various
  1450. :type 'hook)
  1451. (defvar message-send-coding-system 'binary
  1452. "Coding system to encode outgoing mail.")
  1453. (defvar message-draft-coding-system
  1454. mm-auto-save-coding-system
  1455. "*Coding system to compose mail.
  1456. If you'd like to make it possible to share draft files between XEmacs
  1457. and Emacs, you may use `iso-2022-7bit' for this value at your own risk.
  1458. Note that the coding-system `iso-2022-7bit' isn't suitable to all data.")
  1459. (defcustom message-send-mail-partially-limit nil
  1460. "The limitation of messages sent as message/partial.
  1461. The lower bound of message size in characters, beyond which the message
  1462. should be sent in several parts. If it is nil, the size is unlimited."
  1463. :version "24.1"
  1464. :group 'message-buffers
  1465. :link '(custom-manual "(message)Mail Variables")
  1466. :type '(choice (const :tag "unlimited" nil)
  1467. (integer 1000000)))
  1468. (defcustom message-alternative-emails nil
  1469. "*Regexp matching alternative email addresses.
  1470. The first address in the To, Cc or From headers of the original
  1471. article matching this variable is used as the From field of
  1472. outgoing messages.
  1473. This variable has precedence over posting styles and anything that runs
  1474. off `message-setup-hook'."
  1475. :group 'message-headers
  1476. :link '(custom-manual "(message)Message Headers")
  1477. :type '(choice (const :tag "Always use primary" nil)
  1478. regexp))
  1479. (defcustom message-hierarchical-addresses nil
  1480. "A list of hierarchical mail address definitions.
  1481. Inside each entry, the first address is the \"top\" address, and
  1482. subsequent addresses are subaddresses; this is used to indicate that
  1483. mail sent to the first address will automatically be delivered to the
  1484. subaddresses. So if the first address appears in the recipient list
  1485. for a message, the subaddresses will be removed (if present) before
  1486. the mail is sent. All addresses in this structure should be
  1487. downcased."
  1488. :version "22.1"
  1489. :group 'message-headers
  1490. :type '(repeat (repeat string)))
  1491. (defcustom message-mail-user-agent nil
  1492. "Like `mail-user-agent'.
  1493. Except if it is nil, use Gnus native MUA; if it is t, use
  1494. `mail-user-agent'."
  1495. :version "22.1"
  1496. :type '(radio (const :tag "Gnus native"
  1497. :format "%t\n"
  1498. nil)
  1499. (const :tag "`mail-user-agent'"
  1500. :format "%t\n"
  1501. t)
  1502. (function-item :tag "Default Emacs mail"
  1503. :format "%t\n"
  1504. sendmail-user-agent)
  1505. (function-item :tag "Emacs interface to MH"
  1506. :format "%t\n"
  1507. mh-e-user-agent)
  1508. (function :tag "Other"))
  1509. :version "21.1"
  1510. :group 'message)
  1511. (defcustom message-wide-reply-confirm-recipients nil
  1512. "Whether to confirm a wide reply to multiple email recipients.
  1513. If this variable is nil, don't ask whether to reply to all recipients.
  1514. If this variable is non-nil, pose the question \"Reply to all
  1515. recipients?\" before a wide reply to multiple recipients. If the user
  1516. answers yes, reply to all recipients as usual. If the user answers
  1517. no, only reply back to the author."
  1518. :version "22.1"
  1519. :group 'message-headers
  1520. :link '(custom-manual "(message)Wide Reply")
  1521. :type 'boolean)
  1522. (defcustom message-user-fqdn nil
  1523. "*Domain part of Message-Ids."
  1524. :version "22.1"
  1525. :group 'message-headers
  1526. :link '(custom-manual "(message)News Headers")
  1527. :type '(radio (const :format "%v " nil)
  1528. (string :format "FQDN: %v")))
  1529. (defcustom message-use-idna (and (condition-case nil (require 'idna)
  1530. (file-error))
  1531. (mm-coding-system-p 'utf-8)
  1532. (executable-find idna-program)
  1533. (string= (idna-to-ascii "räksmörgås")
  1534. "xn--rksmrgs-5wao1o")
  1535. t)
  1536. "Whether to encode non-ASCII in domain names into ASCII according to IDNA.
  1537. GNU Libidn, and in particular the elisp package \"idna.el\" and
  1538. the external program \"idn\", must be installed for this
  1539. functionality to work."
  1540. :version "22.1"
  1541. :group 'message-headers
  1542. :link '(custom-manual "(message)IDNA")
  1543. :type '(choice (const :tag "Ask" ask)
  1544. (const :tag "Never" nil)
  1545. (const :tag "Always" t)))
  1546. (defcustom message-generate-hashcash (if (executable-find "hashcash") 'opportunistic)
  1547. "*Whether to generate X-Hashcash: headers.
  1548. If t, always generate hashcash headers. If `opportunistic',
  1549. only generate hashcash headers if it can be done without the user
  1550. waiting (i.e., only asynchronously).
  1551. You must have the \"hashcash\" binary installed, see `hashcash-path'."
  1552. :version "24.1"
  1553. :group 'message-headers
  1554. :link '(custom-manual "(message)Mail Headers")
  1555. :type '(choice (const :tag "Always" t)
  1556. (const :tag "Never" nil)
  1557. (const :tag "Opportunistic" opportunistic)))
  1558. ;;; Internal variables.
  1559. (defvar message-sending-message "Sending...")
  1560. (defvar message-buffer-list nil)
  1561. (defvar message-this-is-news nil)
  1562. (defvar message-this-is-mail nil)
  1563. (defvar message-draft-article nil)
  1564. (defvar message-mime-part nil)
  1565. (defvar message-posting-charset nil)
  1566. (defvar message-inserted-headers nil)
  1567. (defvar message-inhibit-ecomplete nil)
  1568. ;; Byte-compiler warning
  1569. (defvar gnus-active-hashtb)
  1570. (defvar gnus-read-active-file)
  1571. ;;; Regexp matching the delimiter of messages in UNIX mail format
  1572. ;;; (UNIX From lines), minus the initial ^. It should be a copy
  1573. ;;; of rmail.el's rmail-unix-mail-delimiter.
  1574. (defvar message-unix-mail-delimiter
  1575. (let ((time-zone-regexp
  1576. (concat "\\([A-Z]?[A-Z]?[A-Z][A-Z]\\( DST\\)?"
  1577. "\\|[-+]?[0-9][0-9][0-9][0-9]"
  1578. "\\|"
  1579. "\\) *")))
  1580. (concat
  1581. "From "
  1582. ;; Many things can happen to an RFC 822 mailbox before it is put into
  1583. ;; a `From' line. The leading phrase can be stripped, e.g.
  1584. ;; `Joe <@w.x:joe@y.z>' -> `<@w.x:joe@y.z>'. The <> can be stripped, e.g.
  1585. ;; `<@x.y:joe@y.z>' -> `@x.y:joe@y.z'. Everything starting with a CRLF
  1586. ;; can be removed, e.g.
  1587. ;; From: joe@y.z (Joe K
  1588. ;; User)
  1589. ;; can yield `From joe@y.z (Joe K Fri Mar 22 08:11:15 1996', and
  1590. ;; From: Joe User
  1591. ;; <joe@y.z>
  1592. ;; can yield `From Joe User Fri Mar 22 08:11:15 1996'.
  1593. ;; The mailbox can be removed or be replaced by white space, e.g.
  1594. ;; From: "Joe User"{space}{tab}
  1595. ;; <joe@y.z>
  1596. ;; can yield `From {space}{tab} Fri Mar 22 08:11:15 1996',
  1597. ;; where {space} and {tab} represent the Ascii space and tab characters.
  1598. ;; We want to match the results of any of these manglings.
  1599. ;; The following regexp rejects names whose first characters are
  1600. ;; obviously bogus, but after that anything goes.
  1601. "\\([^\0-\b\n-\r\^?].*\\)?"
  1602. ;; The time the message was sent.
  1603. "\\([^\0-\r \^?]+\\) +" ; day of the week
  1604. "\\([^\0-\r \^?]+\\) +" ; month
  1605. "\\([0-3]?[0-9]\\) +" ; day of month
  1606. "\\([0-2][0-9]:[0-5][0-9]\\(:[0-6][0-9]\\)?\\) *" ; time of day
  1607. ;; Perhaps a time zone, specified by an abbreviation, or by a
  1608. ;; numeric offset.
  1609. time-zone-regexp
  1610. ;; The year.
  1611. " \\([0-9][0-9]+\\) *"
  1612. ;; On some systems the time zone can appear after the year, too.
  1613. time-zone-regexp
  1614. ;; Old uucp cruft.
  1615. "\\(remote from .*\\)?"
  1616. "\n"))
  1617. "Regexp matching the delimiter of messages in UNIX mail format.")
  1618. (defvar message-unsent-separator
  1619. (concat "^ *---+ +Unsent message follows +---+ *$\\|"
  1620. "^ *---+ +Returned message +---+ *$\\|"
  1621. "^Start of returned message$\\|"
  1622. "^ *---+ +Original message +---+ *$\\|"
  1623. "^ *--+ +begin message +--+ *$\\|"
  1624. "^ *---+ +Original message follows +---+ *$\\|"
  1625. "^ *---+ +Undelivered message follows +---+ *$\\|"
  1626. "^------ This is a copy of the message, including all the headers. ------ *$\\|"
  1627. "^|? *---+ +Message text follows: +---+ *|?$")
  1628. "A regexp that matches the separator before the text of a failed message.")
  1629. (defvar message-field-fillers
  1630. '((To message-fill-field-address)
  1631. (Cc message-fill-field-address)
  1632. (From message-fill-field-address))
  1633. "Alist of header names/filler functions.")
  1634. (defvar message-header-format-alist
  1635. `((From)
  1636. (Newsgroups)
  1637. (To)
  1638. (Cc)
  1639. (Subject)
  1640. (In-Reply-To)
  1641. (Fcc)
  1642. (Bcc)
  1643. (Date)
  1644. (Organization)
  1645. (Distribution)
  1646. (Lines)
  1647. (Expires)
  1648. (Message-ID)
  1649. (References . message-shorten-references)
  1650. (User-Agent))
  1651. "Alist used for formatting headers.")
  1652. (defvar message-options nil
  1653. "Some saved answers when sending message.")
  1654. ;; FIXME: On XEmacs this causes problems since let-binding like:
  1655. ;; (let ((message-options message-options)) ...)
  1656. ;; as in `message-send' and `mml-preview' loses to buffer-local
  1657. ;; variable initialization.
  1658. (unless (featurep 'xemacs)
  1659. (make-variable-buffer-local 'message-options))
  1660. (defvar message-send-mail-real-function nil
  1661. "Internal send mail function.")
  1662. (defvar message-bogus-system-names "\\`localhost\\.\\|\\.local\\'"
  1663. "The regexp of bogus system names.")
  1664. (defcustom message-valid-fqdn-regexp
  1665. (concat "[a-z0-9][-.a-z0-9]+\\." ;; [hostname.subdomain.]domain.
  1666. ;; valid TLDs:
  1667. "\\([a-z][a-z]\\|" ;; two letter country TDLs
  1668. "aero\\|arpa\\|asia\\|bitnet\\|biz\\|bofh\\|"
  1669. "cat\\|com\\|coop\\|edu\\|gov\\|"
  1670. "info\\|int\\|jobs\\|"
  1671. "mil\\|mobi\\|museum\\|name\\|net\\|"
  1672. "org\\|pro\\|tel\\|travel\\|uucp\\)")
  1673. ;; http://en.wikipedia.org/wiki/List_of_Internet_top-level_domains
  1674. ;; http://en.wikipedia.org/wiki/GTLD
  1675. ;; `approved, but not yet in operation': .xxx
  1676. ;; "dead" nato bitnet uucp
  1677. "Regular expression that matches a valid FQDN."
  1678. ;; see also: gnus-button-valid-fqdn-regexp
  1679. :version "22.1"
  1680. :group 'message-headers
  1681. :type 'regexp)
  1682. (autoload 'gnus-alive-p "gnus-util")
  1683. (autoload 'gnus-delay-article "gnus-delay")
  1684. (autoload 'gnus-extract-address-components "gnus-util")
  1685. (autoload 'gnus-find-method-for-group "gnus")
  1686. (autoload 'gnus-group-decoded-name "gnus-group")
  1687. (autoload 'gnus-group-name-charset "gnus-group")
  1688. (autoload 'gnus-group-name-decode "gnus-group")
  1689. (autoload 'gnus-groups-from-server "gnus")
  1690. (autoload 'gnus-make-local-hook "gnus-util")
  1691. (autoload 'gnus-open-server "gnus-int")
  1692. (autoload 'gnus-output-to-mail "gnus-util")
  1693. (autoload 'gnus-output-to-rmail "gnus-util")
  1694. (autoload 'gnus-request-post "gnus-int")
  1695. (autoload 'gnus-select-frame-set-input-focus "gnus-util")
  1696. (autoload 'gnus-server-string "gnus")
  1697. (autoload 'idna-to-ascii "idna")
  1698. (autoload 'message-setup-toolbar "messagexmas")
  1699. (autoload 'mh-new-draft-name "mh-comp")
  1700. (autoload 'mh-send-letter "mh-comp")
  1701. (autoload 'nndraft-request-associate-buffer "nndraft")
  1702. (autoload 'nndraft-request-expire-articles "nndraft")
  1703. (autoload 'nnvirtual-find-group-art "nnvirtual")
  1704. (autoload 'rmail-dont-reply-to "mail-utils")
  1705. (autoload 'rmail-msg-is-pruned "rmail")
  1706. (autoload 'rmail-output "rmailout")
  1707. ;;;
  1708. ;;; Utility functions.
  1709. ;;;
  1710. (defmacro message-y-or-n-p (question show &rest text)
  1711. "Ask QUESTION, displaying remaining args in a temporary buffer if SHOW."
  1712. `(message-talkative-question 'y-or-n-p ,question ,show ,@text))
  1713. (defmacro message-delete-line (&optional n)
  1714. "Delete the current line (and the next N lines)."
  1715. `(delete-region (progn (beginning-of-line) (point))
  1716. (progn (forward-line ,(or n 1)) (point))))
  1717. (defun message-mark-active-p ()
  1718. "Non-nil means the mark and region are currently active in this buffer."
  1719. mark-active)
  1720. (defun message-unquote-tokens (elems)
  1721. "Remove double quotes (\") from strings in list ELEMS."
  1722. (mapcar (lambda (item)
  1723. (while (string-match "^\\(.*\\)\"\\(.*\\)$" item)
  1724. (setq item (concat (match-string 1 item)
  1725. (match-string 2 item))))
  1726. item)
  1727. elems))
  1728. (defun message-tokenize-header (header &optional separator)
  1729. "Split HEADER into a list of header elements.
  1730. SEPARATOR is a string of characters to be used as separators. \",\"
  1731. is used by default."
  1732. (if (not header)
  1733. nil
  1734. (let ((regexp (format "[%s]+" (or separator ",")))
  1735. (first t)
  1736. beg quoted elems paren)
  1737. (with-temp-buffer
  1738. (mm-enable-multibyte)
  1739. (setq beg (point-min))
  1740. (insert header)
  1741. (goto-char (point-min))
  1742. (while (not (eobp))
  1743. (if first
  1744. (setq first nil)
  1745. (forward-char 1))
  1746. (cond ((and (> (point) beg)
  1747. (or (eobp)
  1748. (and (looking-at regexp)
  1749. (not quoted)
  1750. (not paren))))
  1751. (push (buffer-substring beg (point)) elems)
  1752. (setq beg (match-end 0)))
  1753. ((eq (char-after) ?\")
  1754. (setq quoted (not quoted)))
  1755. ((and (eq (char-after) ?\()
  1756. (not quoted))
  1757. (setq paren t))
  1758. ((and (eq (char-after) ?\))
  1759. (not quoted))
  1760. (setq paren nil))))
  1761. (nreverse elems)))))
  1762. (autoload 'nnheader-insert-file-contents "nnheader")
  1763. (defun message-mail-file-mbox-p (file)
  1764. "Say whether FILE looks like a Unix mbox file."
  1765. (when (and (file-exists-p file)
  1766. (file-readable-p file)
  1767. (file-regular-p file))
  1768. (with-temp-buffer
  1769. (nnheader-insert-file-contents file)
  1770. (goto-char (point-min))
  1771. (looking-at message-unix-mail-delimiter))))
  1772. (defun message-fetch-field (header &optional not-all)
  1773. "The same as `mail-fetch-field', only remove all newlines.
  1774. The buffer is expected to be narrowed to just the header of the message;
  1775. see `message-narrow-to-headers-or-head'."
  1776. (let* ((inhibit-point-motion-hooks t)
  1777. (value (mail-fetch-field header nil (not not-all))))
  1778. (when value
  1779. (while (string-match "\n[\t ]+" value)
  1780. (setq value (replace-match " " t t value)))
  1781. value)))
  1782. (defun message-field-value (header &optional not-all)
  1783. "The same as `message-fetch-field', only narrow to the headers first."
  1784. (save-excursion
  1785. (save-restriction
  1786. (message-narrow-to-headers-or-head)
  1787. (message-fetch-field header not-all))))
  1788. (defun message-narrow-to-field ()
  1789. "Narrow the buffer to the header on the current line."
  1790. (beginning-of-line)
  1791. (while (looking-at "[ \t]")
  1792. (forward-line -1))
  1793. (narrow-to-region
  1794. (point)
  1795. (progn
  1796. (forward-line 1)
  1797. (if (re-search-forward "^[^ \n\t]" nil t)
  1798. (point-at-bol)
  1799. (point-max))))
  1800. (goto-char (point-min)))
  1801. (defun message-add-header (&rest headers)
  1802. "Add the HEADERS to the message header, skipping those already present."
  1803. (while headers
  1804. (let (hclean)
  1805. (unless (string-match "^\\([^:]+\\):[ \t]*[^ \t]" (car headers))
  1806. (error "Invalid header `%s'" (car headers)))
  1807. (setq hclean (match-string 1 (car headers)))
  1808. (save-restriction
  1809. (message-narrow-to-headers)
  1810. (unless (re-search-forward (concat "^" (regexp-quote hclean) ":") nil t)
  1811. (goto-char (point-max))
  1812. (if (string-match "\n$" (car headers))
  1813. (insert (car headers))
  1814. (insert (car headers) ?\n)))))
  1815. (setq headers (cdr headers))))
  1816. (defmacro message-with-reply-buffer (&rest forms)
  1817. "Evaluate FORMS in the reply buffer, if it exists."
  1818. `(when (and (bufferp message-reply-buffer)
  1819. (buffer-name message-reply-buffer))
  1820. (with-current-buffer message-reply-buffer
  1821. ,@forms)))
  1822. (put 'message-with-reply-buffer 'lisp-indent-function 0)
  1823. (put 'message-with-reply-buffer 'edebug-form-spec '(body))
  1824. (defun message-fetch-reply-field (header)
  1825. "Fetch field HEADER from the message we're replying to."
  1826. (message-with-reply-buffer
  1827. (save-restriction
  1828. (mail-narrow-to-head)
  1829. (message-fetch-field header))))
  1830. (defun message-strip-list-identifiers (subject)
  1831. "Remove list identifiers in `gnus-list-identifiers' from string SUBJECT."
  1832. (require 'gnus-sum) ; for gnus-list-identifiers
  1833. (let ((regexp (if (stringp gnus-list-identifiers)
  1834. gnus-list-identifiers
  1835. (mapconcat 'identity gnus-list-identifiers " *\\|"))))
  1836. (if (string-match (concat "\\(\\(\\(Re: +\\)?\\(" regexp
  1837. " *\\)\\)+\\(Re: +\\)?\\)") subject)
  1838. (concat (substring subject 0 (match-beginning 1))
  1839. (or (match-string 3 subject)
  1840. (match-string 5 subject))
  1841. (substring subject
  1842. (match-end 1)))
  1843. subject)))
  1844. (defun message-strip-subject-re (subject)
  1845. "Remove \"Re:\" from subject lines in string SUBJECT."
  1846. (if (string-match message-subject-re-regexp subject)
  1847. (substring subject (match-end 0))
  1848. subject))
  1849. (defcustom message-replacement-char "."
  1850. "Replacement character used instead of unprintable or not decodable chars."
  1851. :group 'message-various
  1852. :version "22.1" ;; Gnus 5.10.9
  1853. :type '(choice string
  1854. (const ".")
  1855. (const "?")))
  1856. ;; FIXME: We also should call `message-strip-subject-encoded-words'
  1857. ;; when forwarding. Probably in `message-make-forward-subject' and
  1858. ;; `message-forward-make-body'.
  1859. (defun message-strip-subject-encoded-words (subject)
  1860. "Fix non-decodable words in SUBJECT."
  1861. ;; Cf. `gnus-simplify-subject-fully'.
  1862. (let* ((case-fold-search t)
  1863. (replacement-chars (format "[%s%s%s]"
  1864. message-replacement-char
  1865. message-replacement-char
  1866. message-replacement-char))
  1867. (enc-word-re "=\\?\\([^?]+\\)\\?\\([QB]\\)\\?\\([^?]+\\)\\(\\?=\\)")
  1868. cs-string
  1869. (have-marker
  1870. (with-temp-buffer
  1871. (insert subject)
  1872. (goto-char (point-min))
  1873. (when (re-search-forward enc-word-re nil t)
  1874. (setq cs-string (match-string 1)))))
  1875. cs-coding q-or-b word-beg word-end)
  1876. (if (or (not have-marker) ;; No encoded word found...
  1877. ;; ... or double encoding was correct:
  1878. (and (stringp cs-string)
  1879. (setq cs-string (downcase cs-string))
  1880. (mm-coding-system-p (intern cs-string))
  1881. (not (prog1
  1882. (y-or-n-p
  1883. (format "\
  1884. Decoded Subject \"%s\"
  1885. contains a valid encoded word. Decode again? "
  1886. subject))
  1887. (setq cs-coding (intern cs-string))))))
  1888. subject
  1889. (with-temp-buffer
  1890. (insert subject)
  1891. (goto-char (point-min))
  1892. (while (re-search-forward enc-word-re nil t)
  1893. (setq cs-string (downcase (match-string 1))
  1894. q-or-b (match-string 2)
  1895. word-beg (match-beginning 0)
  1896. word-end (match-end 0))
  1897. (setq cs-coding
  1898. (if (mm-coding-system-p (intern cs-string))
  1899. (setq cs-coding (intern cs-string))
  1900. nil))
  1901. ;; No double encoded subject? => bogus charset.
  1902. (unless cs-coding
  1903. (setq cs-coding
  1904. (mm-read-coding-system
  1905. (format "\
  1906. Decoded Subject \"%s\"
  1907. contains an encoded word. The charset `%s' is unknown or invalid.
  1908. Hit RET to replace non-decodable characters with \"%s\" or enter replacement
  1909. charset: "
  1910. subject cs-string message-replacement-char)))
  1911. (if cs-coding
  1912. (replace-match (concat "=?" (symbol-name cs-coding)
  1913. "?\\2?\\3\\4\\5"))
  1914. (save-excursion
  1915. (goto-char word-beg)
  1916. (re-search-forward "=\\?\\([^?]+\\)\\?\\([QB]\\)\\?" word-end t)
  1917. (replace-match "")
  1918. ;; QP or base64
  1919. (if (string-match "\\`Q\\'" q-or-b)
  1920. ;; QP
  1921. (progn
  1922. (message "Replacing non-decodable characters with \"%s\"."
  1923. message-replacement-char)
  1924. (while (re-search-forward "\\(=[A-F0-9][A-F0-9]\\)+"
  1925. word-end t)
  1926. (replace-match message-replacement-char)))
  1927. ;; base64
  1928. (message "Replacing non-decodable characters with \"%s\"."
  1929. replacement-chars)
  1930. (re-search-forward "[^?]+" word-end t)
  1931. (replace-match replacement-chars))
  1932. (re-search-forward "\\?=")
  1933. (replace-match "")))))
  1934. (rfc2047-decode-region (point-min) (point-max))
  1935. (buffer-string)))))
  1936. ;;; Start of functions adopted from `message-utils.el'.
  1937. (defun message-strip-subject-trailing-was (subject)
  1938. "Remove trailing \"(was: <old subject>)\" from SUBJECT lines.
  1939. Leading \"Re: \" is not stripped by this function. Use the function
  1940. `message-strip-subject-re' for this."
  1941. (let* ((query message-subject-trailing-was-query)
  1942. (new) (found))
  1943. (setq found
  1944. (string-match
  1945. (if (eq query 'ask)
  1946. message-subject-trailing-was-ask-regexp
  1947. message-subject-trailing-was-regexp)
  1948. subject))
  1949. (if found
  1950. (setq new (substring subject 0 (match-beginning 0))))
  1951. (if (or (not found) (eq query nil))
  1952. subject
  1953. (if (eq query 'ask)
  1954. (if (message-y-or-n-p
  1955. "Strip `(was: <old subject>)' in subject? " t
  1956. (concat
  1957. "Strip `(was: <old subject>)' in subject "
  1958. "and use the new one instead?\n\n"
  1959. "Current subject is: \""
  1960. subject "\"\n\n"
  1961. "New subject would be: \""
  1962. new "\"\n\n"
  1963. "See the variable `message-subject-trailing-was-query' "
  1964. "to get rid of this query."
  1965. ))
  1966. new subject)
  1967. new))))
  1968. ;;; Suggested by Jonas Steverud @ www.dtek.chalmers.se/~d4jonas/
  1969. (defun message-change-subject (new-subject)
  1970. "Ask for NEW-SUBJECT header, append (was: <Old Subject>)."
  1971. (interactive
  1972. (list
  1973. (read-from-minibuffer "New subject: ")))
  1974. (cond ((and (not (or (null new-subject) ; new subject not empty
  1975. (zerop (string-width new-subject))
  1976. (string-match "^[ \t]*$" new-subject))))
  1977. (save-excursion
  1978. (let ((old-subject
  1979. (save-restriction
  1980. (message-narrow-to-headers)
  1981. (message-fetch-field "Subject"))))
  1982. (cond ((not old-subject)
  1983. (error "No current subject"))
  1984. ((not (string-match
  1985. (concat "^[ \t]*"
  1986. (regexp-quote new-subject)
  1987. " \t]*$")
  1988. old-subject)) ; yes, it really is a new subject
  1989. ;; delete eventual Re: prefix
  1990. (setq old-subject
  1991. (message-strip-subject-re old-subject))
  1992. (message-goto-subject)
  1993. (message-delete-line)
  1994. (insert (concat "Subject: "
  1995. new-subject
  1996. " (was: "
  1997. old-subject ")\n")))))))))
  1998. (defun message-mark-inserted-region (beg end &optional verbatim)
  1999. "Mark some region in the current article with enclosing tags.
  2000. See `message-mark-insert-begin' and `message-mark-insert-end'.
  2001. If VERBATIM, use slrn style verbatim marks (\"#v+\" and \"#v-\")."
  2002. (interactive "r\nP")
  2003. (save-excursion
  2004. ;; add to the end of the region first, otherwise end would be invalid
  2005. (goto-char end)
  2006. (insert (if verbatim "#v-\n" message-mark-insert-end))
  2007. (goto-char beg)
  2008. (insert (if verbatim "#v+\n" message-mark-insert-begin))))
  2009. (defun message-mark-insert-file (file &optional verbatim)
  2010. "Insert FILE at point, marking it with enclosing tags.
  2011. See `message-mark-insert-begin' and `message-mark-insert-end'.
  2012. If VERBATIM, use slrn style verbatim marks (\"#v+\" and \"#v-\")."
  2013. (interactive "fFile to insert: \nP")
  2014. ;; reverse insertion to get correct result.
  2015. (let ((p (point)))
  2016. (insert (if verbatim "#v-\n" message-mark-insert-end))
  2017. (goto-char p)
  2018. (insert-file-contents file)
  2019. (goto-char p)
  2020. (insert (if verbatim "#v+\n" message-mark-insert-begin))))
  2021. (defun message-add-archive-header ()
  2022. "Insert \"X-No-Archive: Yes\" in the header and a note in the body.
  2023. The note can be customized using `message-archive-note'. When called with a
  2024. prefix argument, ask for a text to insert. If you don't want the note in the
  2025. body, set `message-archive-note' to nil."
  2026. (interactive)
  2027. (if current-prefix-arg
  2028. (setq message-archive-note
  2029. (read-from-minibuffer "Reason for No-Archive: "
  2030. (cons message-archive-note 0))))
  2031. (save-excursion
  2032. (if (message-goto-signature)
  2033. (re-search-backward message-signature-separator))
  2034. (when message-archive-note
  2035. (insert message-archive-note)
  2036. (newline))
  2037. (message-add-header message-archive-header)
  2038. (message-sort-headers)))
  2039. (defun message-cross-post-followup-to-header (target-group)
  2040. "Mangles FollowUp-To and Newsgroups header to point to TARGET-GROUP.
  2041. With prefix-argument just set Follow-Up, don't cross-post."
  2042. (interactive
  2043. (list ; Completion based on Gnus
  2044. (completing-read "Followup To: "
  2045. (if (boundp 'gnus-newsrc-alist)
  2046. gnus-newsrc-alist)
  2047. nil nil '("poster" . 0)
  2048. (if (boundp 'gnus-group-history)
  2049. 'gnus-group-history))))
  2050. (message-remove-header "Follow[Uu]p-[Tt]o" t)
  2051. (message-goto-newsgroups)
  2052. (beginning-of-line)
  2053. ;; if we already did a crosspost before, kill old target
  2054. (if (and message-cross-post-old-target
  2055. (re-search-forward
  2056. (regexp-quote (concat "," message-cross-post-old-target))
  2057. nil t))
  2058. (replace-match ""))
  2059. ;; unless (followup is to poster or user explicitly asked not
  2060. ;; to cross-post, or target-group is already in Newsgroups)
  2061. ;; add target-group to Newsgroups line.
  2062. (cond ((and (or
  2063. ;; def: cross-post, req:no
  2064. (and message-cross-post-default (not current-prefix-arg))
  2065. ;; def: no-cross-post, req:yes
  2066. (and (not message-cross-post-default) current-prefix-arg))
  2067. (not (string-match "poster" target-group))
  2068. (not (string-match (regexp-quote target-group)
  2069. (message-fetch-field "Newsgroups"))))
  2070. (end-of-line)
  2071. (insert (concat "," target-group))))
  2072. (end-of-line) ; ensure Followup: comes after Newsgroups:
  2073. ;; unless new followup would be identical to Newsgroups line
  2074. ;; make a new Followup-To line
  2075. (if (not (string-match (concat "^[ \t]*"
  2076. target-group
  2077. "[ \t]*$")
  2078. (message-fetch-field "Newsgroups")))
  2079. (insert (concat "\nFollowup-To: " target-group)))
  2080. (setq message-cross-post-old-target target-group))
  2081. (defun message-cross-post-insert-note (target-group cross-post in-old
  2082. old-groups)
  2083. "Insert a in message body note about a set Followup or Crosspost.
  2084. If there have been previous notes, delete them. TARGET-GROUP specifies the
  2085. group to Followup-To. When CROSS-POST is t, insert note about
  2086. crossposting. IN-OLD specifies whether TARGET-GROUP is a member of
  2087. OLD-GROUPS. OLD-GROUPS lists the old-groups the posting would have
  2088. been made to before the user asked for a Crosspost."
  2089. ;; start scanning body for previous uses
  2090. (message-goto-signature)
  2091. (let ((head (re-search-backward
  2092. (concat "^" mail-header-separator)
  2093. nil t))) ; just search in body
  2094. (message-goto-signature)
  2095. (while (re-search-backward
  2096. (concat "^" (regexp-quote message-cross-post-note) ".*")
  2097. head t)
  2098. (message-delete-line))
  2099. (message-goto-signature)
  2100. (while (re-search-backward
  2101. (concat "^" (regexp-quote message-followup-to-note) ".*")
  2102. head t)
  2103. (message-delete-line))
  2104. ;; insert new note
  2105. (if (message-goto-signature)
  2106. (re-search-backward message-signature-separator))
  2107. (if (or in-old
  2108. (not cross-post)
  2109. (string-match "^[ \t]*poster[ \t]*$" target-group))
  2110. (insert (concat message-followup-to-note target-group "\n"))
  2111. (insert (concat message-cross-post-note target-group "\n")))))
  2112. (defun message-cross-post-followup-to (target-group)
  2113. "Crossposts message and set Followup-To to TARGET-GROUP.
  2114. With prefix-argument just set Follow-Up, don't cross-post."
  2115. (interactive
  2116. (list ; Completion based on Gnus
  2117. (completing-read "Followup To: "
  2118. (if (boundp 'gnus-newsrc-alist)
  2119. gnus-newsrc-alist)
  2120. nil nil '("poster" . 0)
  2121. (if (boundp 'gnus-group-history)
  2122. 'gnus-group-history))))
  2123. (cond ((not (or (null target-group) ; new subject not empty
  2124. (zerop (string-width target-group))
  2125. (string-match "^[ \t]*$" target-group)))
  2126. (save-excursion
  2127. (let* ((old-groups (message-fetch-field "Newsgroups"))
  2128. (in-old (string-match
  2129. (regexp-quote target-group)
  2130. (or old-groups ""))))
  2131. ;; check whether target exactly matches old Newsgroups
  2132. (cond ((not old-groups)
  2133. (error "No current newsgroup"))
  2134. ((or (not in-old)
  2135. (not (string-match
  2136. (concat "^[ \t]*"
  2137. (regexp-quote target-group)
  2138. "[ \t]*$")
  2139. old-groups)))
  2140. ;; yes, Newsgroups line must change
  2141. (message-cross-post-followup-to-header target-group)
  2142. ;; insert note whether we do cross-post or followup-to
  2143. (funcall message-cross-post-note-function
  2144. target-group
  2145. (if (or (and message-cross-post-default
  2146. (not current-prefix-arg))
  2147. (and (not message-cross-post-default)
  2148. current-prefix-arg)) t)
  2149. in-old old-groups))))))))
  2150. ;;; Reduce To: to Cc: or Bcc: header
  2151. (defun message-reduce-to-to-cc ()
  2152. "Replace contents of To: header with contents of Cc: or Bcc: header."
  2153. (interactive)
  2154. (let ((cc-content
  2155. (save-restriction (message-narrow-to-headers)
  2156. (message-fetch-field "cc")))
  2157. (bcc nil))
  2158. (if (and (not cc-content)
  2159. (setq cc-content
  2160. (save-restriction
  2161. (message-narrow-to-headers)
  2162. (message-fetch-field "bcc"))))
  2163. (setq bcc t))
  2164. (cond (cc-content
  2165. (save-excursion
  2166. (message-goto-to)
  2167. (message-delete-line)
  2168. (insert (concat "To: " cc-content "\n"))
  2169. (save-restriction
  2170. (message-narrow-to-headers)
  2171. (message-remove-header (if bcc
  2172. "bcc"
  2173. "cc"))))))))
  2174. ;;; End of functions adopted from `message-utils.el'.
  2175. (defun message-remove-header (header &optional is-regexp first reverse)
  2176. "Remove HEADER in the narrowed buffer.
  2177. If IS-REGEXP, HEADER is a regular expression.
  2178. If FIRST, only remove the first instance of the header.
  2179. Return the number of headers removed."
  2180. (goto-char (point-min))
  2181. (let ((regexp (if is-regexp header (concat "^" (regexp-quote header) ":")))
  2182. (number 0)
  2183. (case-fold-search t)
  2184. last)
  2185. (while (and (not (eobp))
  2186. (not last))
  2187. (if (if reverse
  2188. (not (looking-at regexp))
  2189. (looking-at regexp))
  2190. (progn
  2191. (incf number)
  2192. (when first
  2193. (setq last t))
  2194. (delete-region
  2195. (point)
  2196. ;; There might be a continuation header, so we have to search
  2197. ;; until we find a new non-continuation line.
  2198. (progn
  2199. (forward-line 1)
  2200. (if (re-search-forward "^[^ \t]" nil t)
  2201. (goto-char (match-beginning 0))
  2202. (point-max)))))
  2203. (forward-line 1)
  2204. (if (re-search-forward "^[^ \t]" nil t)
  2205. (goto-char (match-beginning 0))
  2206. (goto-char (point-max)))))
  2207. number))
  2208. (defun message-remove-first-header (header)
  2209. "Remove the first instance of HEADER if there is more than one."
  2210. (let ((count 0)
  2211. (regexp (concat "^" (regexp-quote header) ":")))
  2212. (save-excursion
  2213. (goto-char (point-min))
  2214. (while (re-search-forward regexp nil t)
  2215. (incf count)))
  2216. (while (> count 1)
  2217. (message-remove-header header nil t)
  2218. (decf count))))
  2219. (defun message-narrow-to-headers ()
  2220. "Narrow the buffer to the head of the message."
  2221. (widen)
  2222. (narrow-to-region
  2223. (goto-char (point-min))
  2224. (if (re-search-forward
  2225. (concat "^" (regexp-quote mail-header-separator) "\n") nil t)
  2226. (match-beginning 0)
  2227. (point-max)))
  2228. (goto-char (point-min)))
  2229. (defun message-narrow-to-head-1 ()
  2230. "Like `message-narrow-to-head'. Don't widen."
  2231. (narrow-to-region
  2232. (goto-char (point-min))
  2233. (if (search-forward "\n\n" nil 1)
  2234. (1- (point))
  2235. (point-max)))
  2236. (goto-char (point-min)))
  2237. ;; FIXME: clarify difference: message-narrow-to-head,
  2238. ;; message-narrow-to-headers-or-head, message-narrow-to-headers
  2239. (defun message-narrow-to-head ()
  2240. "Narrow the buffer to the head of the message.
  2241. Point is left at the beginning of the narrowed-to region."
  2242. (widen)
  2243. (message-narrow-to-head-1))
  2244. (defun message-narrow-to-headers-or-head ()
  2245. "Narrow the buffer to the head of the message."
  2246. (widen)
  2247. (narrow-to-region
  2248. (goto-char (point-min))
  2249. (if (re-search-forward (concat "\\(\n\\)\n\\|^\\("
  2250. (regexp-quote mail-header-separator)
  2251. "\n\\)")
  2252. nil t)
  2253. (or (match-end 1) (match-beginning 2))
  2254. (point-max)))
  2255. (goto-char (point-min)))
  2256. (defun message-news-p ()
  2257. "Say whether the current buffer contains a news message."
  2258. (and (not message-this-is-mail)
  2259. (or message-this-is-news
  2260. (save-excursion
  2261. (save-restriction
  2262. (message-narrow-to-headers)
  2263. (and (message-fetch-field "newsgroups")
  2264. (not (message-fetch-field "posted-to"))))))))
  2265. (defun message-mail-p ()
  2266. "Say whether the current buffer contains a mail message."
  2267. (and (not message-this-is-news)
  2268. (or message-this-is-mail
  2269. (save-excursion
  2270. (save-restriction
  2271. (message-narrow-to-headers)
  2272. (or (message-fetch-field "to")
  2273. (message-fetch-field "cc")
  2274. (message-fetch-field "bcc")))))))
  2275. (defun message-subscribed-p ()
  2276. "Say whether we need to insert a MFT header."
  2277. (or message-subscribed-regexps
  2278. message-subscribed-addresses
  2279. message-subscribed-address-file
  2280. message-subscribed-address-functions))
  2281. (defun message-next-header ()
  2282. "Go to the beginning of the next header."
  2283. (beginning-of-line)
  2284. (or (eobp) (forward-char 1))
  2285. (not (if (re-search-forward "^[^ \t]" nil t)
  2286. (beginning-of-line)
  2287. (goto-char (point-max)))))
  2288. (defun message-sort-headers-1 ()
  2289. "Sort the buffer as headers using `message-rank' text props."
  2290. (goto-char (point-min))
  2291. (require 'sort)
  2292. (sort-subr
  2293. nil 'message-next-header
  2294. (lambda ()
  2295. (message-next-header)
  2296. (unless (bobp)
  2297. (forward-char -1)))
  2298. (lambda ()
  2299. (or (get-text-property (point) 'message-rank)
  2300. 10000))))
  2301. (defun message-sort-headers ()
  2302. "Sort the headers of the current message according to `message-header-format-alist'."
  2303. (interactive)
  2304. (save-excursion
  2305. (save-restriction
  2306. (let ((max (1+ (length message-header-format-alist)))
  2307. rank)
  2308. (message-narrow-to-headers)
  2309. (while (re-search-forward "^[^ \n]+:" nil t)
  2310. (put-text-property
  2311. (match-beginning 0) (1+ (match-beginning 0))
  2312. 'message-rank
  2313. (if (setq rank (length (memq (assq (intern (buffer-substring
  2314. (match-beginning 0)
  2315. (1- (match-end 0))))
  2316. message-header-format-alist)
  2317. message-header-format-alist)))
  2318. (- max rank)
  2319. (1+ max)))))
  2320. (message-sort-headers-1))))
  2321. (defun message-kill-address ()
  2322. "Kill the address under point."
  2323. (interactive)
  2324. (let ((start (point)))
  2325. (message-skip-to-next-address)
  2326. (kill-region start (point))))
  2327. (autoload 'Info-goto-node "info")
  2328. (defvar mml2015-use)
  2329. (defun message-info (&optional arg)
  2330. "Display the Message manual.
  2331. Prefixed with one \\[universal-argument], display the Emacs MIME
  2332. manual. With two \\[universal-argument]'s, display the EasyPG or
  2333. PGG manual, depending on the value of `mml2015-use'."
  2334. (interactive "p")
  2335. ;; Don't use `info' because support for `(filename)nodename' is not
  2336. ;; available in XEmacs < 21.5.12.
  2337. (Info-goto-node (format "(%s)Top"
  2338. (cond ((eq arg 16)
  2339. (require 'mml2015)
  2340. mml2015-use)
  2341. ((eq arg 4) 'emacs-mime)
  2342. ;; `booleanp' only available in Emacs 22+
  2343. ((and (not (memq arg '(nil t)))
  2344. (symbolp arg))
  2345. arg)
  2346. (t
  2347. 'message)))))
  2348. ;;;
  2349. ;;; Message mode
  2350. ;;;
  2351. ;;; Set up keymap.
  2352. (defvar message-mode-map nil)
  2353. (unless message-mode-map
  2354. (setq message-mode-map (make-keymap))
  2355. (set-keymap-parent message-mode-map text-mode-map)
  2356. (define-key message-mode-map "\C-c?" 'describe-mode)
  2357. (define-key message-mode-map "\C-c\C-f\C-t" 'message-goto-to)
  2358. (define-key message-mode-map "\C-c\C-f\C-o" 'message-goto-from)
  2359. (define-key message-mode-map "\C-c\C-f\C-b" 'message-goto-bcc)
  2360. (define-key message-mode-map "\C-c\C-f\C-w" 'message-goto-fcc)
  2361. (define-key message-mode-map "\C-c\C-f\C-c" 'message-goto-cc)
  2362. (define-key message-mode-map "\C-c\C-f\C-s" 'message-goto-subject)
  2363. (define-key message-mode-map "\C-c\C-f\C-r" 'message-goto-reply-to)
  2364. (define-key message-mode-map "\C-c\C-f\C-n" 'message-goto-newsgroups)
  2365. (define-key message-mode-map "\C-c\C-f\C-d" 'message-goto-distribution)
  2366. (define-key message-mode-map "\C-c\C-f\C-f" 'message-goto-followup-to)
  2367. (define-key message-mode-map "\C-c\C-f\C-m" 'message-goto-mail-followup-to)
  2368. (define-key message-mode-map "\C-c\C-f\C-k" 'message-goto-keywords)
  2369. (define-key message-mode-map "\C-c\C-f\C-u" 'message-goto-summary)
  2370. (define-key message-mode-map "\C-c\C-f\C-i"
  2371. 'message-insert-or-toggle-importance)
  2372. (define-key message-mode-map "\C-c\C-f\C-a"
  2373. 'message-generate-unsubscribed-mail-followup-to)
  2374. ;; modify headers (and insert notes in body)
  2375. (define-key message-mode-map "\C-c\C-fs" 'message-change-subject)
  2376. ;;
  2377. (define-key message-mode-map "\C-c\C-fx" 'message-cross-post-followup-to)
  2378. ;; prefix+message-cross-post-followup-to = same w/o cross-post
  2379. (define-key message-mode-map "\C-c\C-ft" 'message-reduce-to-to-cc)
  2380. (define-key message-mode-map "\C-c\C-fa" 'message-add-archive-header)
  2381. ;; mark inserted text
  2382. (define-key message-mode-map "\C-c\M-m" 'message-mark-inserted-region)
  2383. (define-key message-mode-map "\C-c\M-f" 'message-mark-insert-file)
  2384. (define-key message-mode-map "\C-c\C-b" 'message-goto-body)
  2385. (define-key message-mode-map "\C-c\C-i" 'message-goto-signature)
  2386. (define-key message-mode-map "\C-c\C-t" 'message-insert-to)
  2387. (define-key message-mode-map "\C-c\C-fw" 'message-insert-wide-reply)
  2388. (define-key message-mode-map "\C-c\C-n" 'message-insert-newsgroups)
  2389. (define-key message-mode-map "\C-c\C-l" 'message-to-list-only)
  2390. (define-key message-mode-map "\C-c\C-f\C-e" 'message-insert-expires)
  2391. (define-key message-mode-map "\C-c\C-u" 'message-insert-or-toggle-importance)
  2392. (define-key message-mode-map "\C-c\M-n"
  2393. 'message-insert-disposition-notification-to)
  2394. (define-key message-mode-map "\C-c\C-y" 'message-yank-original)
  2395. (define-key message-mode-map "\C-c\M-\C-y" 'message-yank-buffer)
  2396. (define-key message-mode-map "\C-c\C-q" 'message-fill-yanked-message)
  2397. (define-key message-mode-map "\C-c\C-w" 'message-insert-signature)
  2398. (define-key message-mode-map "\C-c\M-h" 'message-insert-headers)
  2399. (define-key message-mode-map "\C-c\C-r" 'message-caesar-buffer-body)
  2400. (define-key message-mode-map "\C-c\C-o" 'message-sort-headers)
  2401. (define-key message-mode-map "\C-c\M-r" 'message-rename-buffer)
  2402. (define-key message-mode-map "\C-c\C-c" 'message-send-and-exit)
  2403. (define-key message-mode-map "\C-c\C-s" 'message-send)
  2404. (define-key message-mode-map "\C-c\C-k" 'message-kill-buffer)
  2405. (define-key message-mode-map "\C-c\C-d" 'message-dont-send)
  2406. (define-key message-mode-map "\C-c\n" 'gnus-delay-article)
  2407. (define-key message-mode-map "\C-c\M-k" 'message-kill-address)
  2408. (define-key message-mode-map "\C-c\C-e" 'message-elide-region)
  2409. (define-key message-mode-map "\C-c\C-v" 'message-delete-not-region)
  2410. (define-key message-mode-map "\C-c\C-z" 'message-kill-to-signature)
  2411. (define-key message-mode-map "\M-\r" 'message-newline-and-reformat)
  2412. (define-key message-mode-map [remap split-line] 'message-split-line)
  2413. (define-key message-mode-map "\C-c\C-a" 'mml-attach-file)
  2414. (define-key message-mode-map "\C-a" 'message-beginning-of-line)
  2415. (define-key message-mode-map "\t" 'message-tab)
  2416. (define-key message-mode-map "\M-n" 'message-display-abbrev))
  2417. (easy-menu-define
  2418. message-mode-menu message-mode-map "Message Menu."
  2419. `("Message"
  2420. ["Yank Original" message-yank-original message-reply-buffer]
  2421. ["Fill Yanked Message" message-fill-yanked-message t]
  2422. ["Insert Signature" message-insert-signature t]
  2423. ["Caesar (rot13) Message" message-caesar-buffer-body t]
  2424. ["Caesar (rot13) Region" message-caesar-region (message-mark-active-p)]
  2425. ["Elide Region" message-elide-region
  2426. :active (message-mark-active-p)
  2427. ,@(if (featurep 'xemacs) nil
  2428. '(:help "Replace text in region with an ellipsis"))]
  2429. ["Delete Outside Region" message-delete-not-region
  2430. :active (message-mark-active-p)
  2431. ,@(if (featurep 'xemacs) nil
  2432. '(:help "Delete all quoted text outside region"))]
  2433. ["Kill To Signature" message-kill-to-signature t]
  2434. ["Newline and Reformat" message-newline-and-reformat t]
  2435. ["Rename buffer" message-rename-buffer t]
  2436. ["Spellcheck" ispell-message
  2437. ,@(if (featurep 'xemacs) '(t)
  2438. '(:help "Spellcheck this message"))]
  2439. "----"
  2440. ["Insert Region Marked" message-mark-inserted-region
  2441. :active (message-mark-active-p)
  2442. ,@(if (featurep 'xemacs) nil
  2443. '(:help "Mark region with enclosing tags"))]
  2444. ["Insert File Marked..." message-mark-insert-file
  2445. ,@(if (featurep 'xemacs) '(t)
  2446. '(:help "Insert file at point marked with enclosing tags"))]
  2447. "----"
  2448. ["Send Message" message-send-and-exit
  2449. ,@(if (featurep 'xemacs) '(t)
  2450. '(:help "Send this message"))]
  2451. ["Postpone Message" message-dont-send
  2452. ,@(if (featurep 'xemacs) '(t)
  2453. '(:help "File this draft message and exit"))]
  2454. ["Send at Specific Time..." gnus-delay-article
  2455. ,@(if (featurep 'xemacs) '(t)
  2456. '(:help "Ask, then arrange to send message at that time"))]
  2457. ["Kill Message" message-kill-buffer
  2458. ,@(if (featurep 'xemacs) '(t)
  2459. '(:help "Delete this message without sending"))]
  2460. "----"
  2461. ["Message manual" message-info
  2462. ,@(if (featurep 'xemacs) '(t)
  2463. '(:help "Display the Message manual"))]))
  2464. (easy-menu-define
  2465. message-mode-field-menu message-mode-map ""
  2466. `("Field"
  2467. ["To" message-goto-to t]
  2468. ["From" message-goto-from t]
  2469. ["Subject" message-goto-subject t]
  2470. ["Change subject..." message-change-subject t]
  2471. ["Cc" message-goto-cc t]
  2472. ["Bcc" message-goto-bcc t]
  2473. ["Fcc" message-goto-fcc t]
  2474. ["Reply-To" message-goto-reply-to t]
  2475. ["Flag As Important" message-insert-importance-high
  2476. ,@(if (featurep 'xemacs) '(t)
  2477. '(:help "Mark this message as important"))]
  2478. ["Flag As Unimportant" message-insert-importance-low
  2479. ,@(if (featurep 'xemacs) '(t)
  2480. '(:help "Mark this message as unimportant"))]
  2481. ["Request Receipt"
  2482. message-insert-disposition-notification-to
  2483. ,@(if (featurep 'xemacs) '(t)
  2484. '(:help "Request a receipt notification"))]
  2485. "----"
  2486. ;; (typical) news stuff
  2487. ["Summary" message-goto-summary t]
  2488. ["Keywords" message-goto-keywords t]
  2489. ["Newsgroups" message-goto-newsgroups t]
  2490. ["Fetch Newsgroups" message-insert-newsgroups t]
  2491. ["Followup-To" message-goto-followup-to t]
  2492. ;; ["Followup-To (with note in body)" message-cross-post-followup-to t]
  2493. ["Crosspost / Followup-To..." message-cross-post-followup-to t]
  2494. ["Distribution" message-goto-distribution t]
  2495. ["Expires" message-insert-expires t ]
  2496. ["X-No-Archive" message-add-archive-header t ]
  2497. "----"
  2498. ;; (typical) mailing-lists stuff
  2499. ["Fetch To" message-insert-to
  2500. ,@(if (featurep 'xemacs) '(t)
  2501. '(:help "Insert a To header that points to the author."))]
  2502. ["Fetch To and Cc" message-insert-wide-reply
  2503. ,@(if (featurep 'xemacs) '(t)
  2504. '(:help
  2505. "Insert To and Cc headers as if you were doing a wide reply."))]
  2506. "----"
  2507. ["Send to list only" message-to-list-only t]
  2508. ["Mail-Followup-To" message-goto-mail-followup-to t]
  2509. ["Unsubscribed list post" message-generate-unsubscribed-mail-followup-to
  2510. ,@(if (featurep 'xemacs) '(t)
  2511. '(:help "Insert a reasonable `Mail-Followup-To:' header."))]
  2512. ["Reduce To: to Cc:" message-reduce-to-to-cc t]
  2513. "----"
  2514. ["Sort Headers" message-sort-headers t]
  2515. ["Encode non-ASCII domain names" message-idna-to-ascii-rhs t]
  2516. ;; We hide `message-hidden-headers' by narrowing the buffer.
  2517. ["Show Hidden Headers" widen t]
  2518. ["Goto Body" message-goto-body t]
  2519. ["Goto Signature" message-goto-signature t]))
  2520. (defvar message-tool-bar-map nil)
  2521. (defvar facemenu-add-face-function)
  2522. (defvar facemenu-remove-face-function)
  2523. ;;; Forbidden properties
  2524. ;;
  2525. ;; We use `after-change-functions' to keep special text properties
  2526. ;; that interfere with the normal function of message mode out of the
  2527. ;; buffer.
  2528. (defcustom message-strip-special-text-properties t
  2529. "Strip special properties from the message buffer.
  2530. Emacs has a number of special text properties which can break message
  2531. composing in various ways. If this option is set, message will strip
  2532. these properties from the message composition buffer. However, some
  2533. packages requires these properties to be present in order to work.
  2534. If you use one of these packages, turn this option off, and hope the
  2535. message composition doesn't break too bad."
  2536. :version "22.1"
  2537. :group 'message-various
  2538. :link '(custom-manual "(message)Various Message Variables")
  2539. :type 'boolean)
  2540. (defvar message-forbidden-properties
  2541. ;; No reason this should be clutter up customize. We make it a
  2542. ;; property list (rather than a list of property symbols), to be
  2543. ;; directly useful for `remove-text-properties'.
  2544. '(field nil read-only nil invisible nil intangible nil
  2545. mouse-face nil modification-hooks nil insert-in-front-hooks nil
  2546. insert-behind-hooks nil point-entered nil point-left nil)
  2547. ;; Other special properties:
  2548. ;; category, face, display: probably doesn't do any harm.
  2549. ;; fontified: is used by font-lock.
  2550. ;; syntax-table, local-map: I dunno.
  2551. ;; We need to add XEmacs names to the list.
  2552. "Property list of with properties forbidden in message buffers.
  2553. The values of the properties are ignored, only the property names are used.")
  2554. (defun message-tamago-not-in-use-p (pos)
  2555. "Return t when tamago version 4 is not in use at the cursor position.
  2556. Tamago version 4 is a popular input method for writing Japanese text.
  2557. It uses the properties `intangible', `invisible', `modification-hooks'
  2558. and `read-only' when translating ascii or kana text to kanji text.
  2559. These properties are essential to work, so we should never strip them."
  2560. (not (and (boundp 'egg-modefull-mode)
  2561. (symbol-value 'egg-modefull-mode)
  2562. (or (memq (get-text-property pos 'intangible)
  2563. '(its-part-1 its-part-2))
  2564. (get-text-property pos 'egg-end)
  2565. (get-text-property pos 'egg-lang)
  2566. (get-text-property pos 'egg-start)))))
  2567. (defsubst message-mail-alias-type-p (type)
  2568. (if (atom message-mail-alias-type)
  2569. (eq message-mail-alias-type type)
  2570. (memq type message-mail-alias-type)))
  2571. (defun message-strip-forbidden-properties (begin end &optional old-length)
  2572. "Strip forbidden properties between BEGIN and END, ignoring the third arg.
  2573. This function is intended to be called from `after-change-functions'.
  2574. See also `message-forbidden-properties'."
  2575. (when (and (message-mail-alias-type-p 'ecomplete)
  2576. (memq this-command message-self-insert-commands))
  2577. (message-display-abbrev))
  2578. (when (and message-strip-special-text-properties
  2579. (message-tamago-not-in-use-p begin))
  2580. (let ((buffer-read-only nil)
  2581. (inhibit-read-only t))
  2582. (remove-text-properties begin end message-forbidden-properties))))
  2583. (autoload 'ecomplete-setup "ecomplete") ;; for Emacs <23.
  2584. ;;;###autoload
  2585. (define-derived-mode message-mode text-mode "Message"
  2586. "Major mode for editing mail and news to be sent.
  2587. Like Text Mode but with these additional commands:\\<message-mode-map>
  2588. C-c C-s `message-send' (send the message) C-c C-c `message-send-and-exit'
  2589. C-c C-d Postpone sending the message C-c C-k Kill the message
  2590. C-c C-f move to a header field (and create it if there isn't):
  2591. C-c C-f C-t move to To C-c C-f C-s move to Subject
  2592. C-c C-f C-c move to Cc C-c C-f C-b move to Bcc
  2593. C-c C-f C-w move to Fcc C-c C-f C-r move to Reply-To
  2594. C-c C-f C-u move to Summary C-c C-f C-n move to Newsgroups
  2595. C-c C-f C-k move to Keywords C-c C-f C-d move to Distribution
  2596. C-c C-f C-o move to From (\"Originator\")
  2597. C-c C-f C-f move to Followup-To
  2598. C-c C-f C-m move to Mail-Followup-To
  2599. C-c C-f C-e move to Expires
  2600. C-c C-f C-i cycle through Importance values
  2601. C-c C-f s change subject and append \"(was: <Old Subject>)\"
  2602. C-c C-f x crossposting with FollowUp-To header and note in body
  2603. C-c C-f t replace To: header with contents of Cc: or Bcc:
  2604. C-c C-f a Insert X-No-Archive: header and a note in the body
  2605. C-c C-t `message-insert-to' (add a To header to a news followup)
  2606. C-c C-l `message-to-list-only' (removes all but list address in to/cc)
  2607. C-c C-n `message-insert-newsgroups' (add a Newsgroup header to a news reply)
  2608. C-c C-b `message-goto-body' (move to beginning of message text).
  2609. C-c C-i `message-goto-signature' (move to the beginning of the signature).
  2610. C-c C-w `message-insert-signature' (insert `message-signature-file' file).
  2611. C-c C-y `message-yank-original' (insert current message, if any).
  2612. C-c C-q `message-fill-yanked-message' (fill what was yanked).
  2613. C-c C-e `message-elide-region' (elide the text between point and mark).
  2614. C-c C-v `message-delete-not-region' (remove the text outside the region).
  2615. C-c C-z `message-kill-to-signature' (kill the text up to the signature).
  2616. C-c C-r `message-caesar-buffer-body' (rot13 the message body).
  2617. C-c C-a `mml-attach-file' (attach a file as MIME).
  2618. C-c C-u `message-insert-or-toggle-importance' (insert or cycle importance).
  2619. C-c M-n `message-insert-disposition-notification-to' (request receipt).
  2620. C-c M-m `message-mark-inserted-region' (mark region with enclosing tags).
  2621. C-c M-f `message-mark-insert-file' (insert file marked with enclosing tags).
  2622. M-RET `message-newline-and-reformat' (break the line and reformat)."
  2623. (setq local-abbrev-table text-mode-abbrev-table)
  2624. (set (make-local-variable 'message-reply-buffer) nil)
  2625. (set (make-local-variable 'message-inserted-headers) nil)
  2626. (set (make-local-variable 'message-send-actions) nil)
  2627. (set (make-local-variable 'message-return-action) nil)
  2628. (set (make-local-variable 'message-exit-actions) nil)
  2629. (set (make-local-variable 'message-kill-actions) nil)
  2630. (set (make-local-variable 'message-postpone-actions) nil)
  2631. (set (make-local-variable 'message-draft-article) nil)
  2632. (setq buffer-offer-save t)
  2633. (set (make-local-variable 'facemenu-add-face-function)
  2634. (lambda (face end)
  2635. (let ((face-fun (cdr (assq face message-face-alist))))
  2636. (if face-fun
  2637. (funcall face-fun (point) end)
  2638. (error "Face %s not configured for %s mode" face mode-name)))
  2639. ""))
  2640. (set (make-local-variable 'facemenu-remove-face-function) t)
  2641. (set (make-local-variable 'message-reply-headers) nil)
  2642. (make-local-variable 'message-newsreader)
  2643. (make-local-variable 'message-mailer)
  2644. (make-local-variable 'message-post-method)
  2645. (set (make-local-variable 'message-sent-message-via) nil)
  2646. (set (make-local-variable 'message-checksum) nil)
  2647. (set (make-local-variable 'message-mime-part) 0)
  2648. (message-setup-fill-variables)
  2649. (when message-fill-column
  2650. (setq fill-column message-fill-column)
  2651. (turn-on-auto-fill))
  2652. ;; Allow using comment commands to add/remove quoting.
  2653. ;; (set (make-local-variable 'comment-start) message-yank-prefix)
  2654. (when message-yank-prefix
  2655. (set (make-local-variable 'comment-start) message-yank-prefix)
  2656. (set (make-local-variable 'comment-start-skip)
  2657. (concat "^" (regexp-quote message-yank-prefix) "[ \t]*")))
  2658. (if (featurep 'xemacs)
  2659. (message-setup-toolbar)
  2660. (set (make-local-variable 'font-lock-defaults)
  2661. '(message-font-lock-keywords t))
  2662. (if (boundp 'tool-bar-map)
  2663. (set (make-local-variable 'tool-bar-map) (message-make-tool-bar))))
  2664. (easy-menu-add message-mode-menu message-mode-map)
  2665. (easy-menu-add message-mode-field-menu message-mode-map)
  2666. (gnus-make-local-hook 'after-change-functions)
  2667. ;; Mmmm... Forbidden properties...
  2668. (add-hook 'after-change-functions 'message-strip-forbidden-properties
  2669. nil 'local)
  2670. ;; Allow mail alias things.
  2671. (cond
  2672. ((message-mail-alias-type-p 'abbrev)
  2673. (if (fboundp 'mail-abbrevs-setup)
  2674. (mail-abbrevs-setup)
  2675. (if (fboundp 'mail-aliases-setup) ; warning avoidance
  2676. (mail-aliases-setup))))
  2677. ((message-mail-alias-type-p 'ecomplete)
  2678. (ecomplete-setup)))
  2679. (add-hook 'completion-at-point-functions 'message-completion-function nil t)
  2680. (unless buffer-file-name
  2681. (message-set-auto-save-file-name))
  2682. (unless (buffer-base-buffer)
  2683. ;; Don't enable multibyte on an indirect buffer. Maybe enabling
  2684. ;; multibyte is not necessary at all. -- zsh
  2685. (mm-enable-multibyte))
  2686. (set (make-local-variable 'indent-tabs-mode) nil) ;No tabs for indentation.
  2687. (mml-mode))
  2688. (defun message-setup-fill-variables ()
  2689. "Setup message fill variables."
  2690. (set (make-local-variable 'fill-paragraph-function)
  2691. 'message-fill-paragraph)
  2692. (make-local-variable 'paragraph-separate)
  2693. (make-local-variable 'paragraph-start)
  2694. (make-local-variable 'adaptive-fill-regexp)
  2695. (unless (boundp 'adaptive-fill-first-line-regexp)
  2696. (setq adaptive-fill-first-line-regexp nil))
  2697. (make-local-variable 'adaptive-fill-first-line-regexp)
  2698. (let ((quote-prefix-regexp
  2699. ;; User should change message-cite-prefix-regexp if
  2700. ;; message-yank-prefix is set to an abnormal value.
  2701. (concat "\\(" message-cite-prefix-regexp "\\)[ \t]*")))
  2702. (setq paragraph-start
  2703. (concat
  2704. (regexp-quote mail-header-separator) "$\\|"
  2705. "[ \t]*$\\|" ; blank lines
  2706. "-- $\\|" ; signature delimiter
  2707. "---+$\\|" ; delimiters for forwarded messages
  2708. page-delimiter "$\\|" ; spoiler warnings
  2709. ".*wrote:$\\|" ; attribution lines
  2710. quote-prefix-regexp "$\\|" ; empty lines in quoted text
  2711. ; mml tags
  2712. "<#!*/?\\(multipart\\|part\\|external\\|mml\\|secure\\)"))
  2713. (setq paragraph-separate paragraph-start)
  2714. (setq adaptive-fill-regexp
  2715. (concat quote-prefix-regexp "\\|" adaptive-fill-regexp))
  2716. (setq adaptive-fill-first-line-regexp
  2717. (concat quote-prefix-regexp "\\|"
  2718. adaptive-fill-first-line-regexp)))
  2719. (make-local-variable 'auto-fill-inhibit-regexp)
  2720. ;;(setq auto-fill-inhibit-regexp "^[A-Z][^: \n\t]+:")
  2721. (setq auto-fill-inhibit-regexp nil)
  2722. (make-local-variable 'normal-auto-fill-function)
  2723. (setq normal-auto-fill-function 'message-do-auto-fill)
  2724. ;; KLUDGE: auto fill might already be turned on in `text-mode-hook'.
  2725. ;; In that case, ensure that it uses the right function. The real
  2726. ;; solution would be not to use `define-derived-mode', and run
  2727. ;; `text-mode-hook' ourself at the end of the mode.
  2728. ;; -- Per Abrahamsen <abraham@dina.kvl.dk> Date: 2001-10-19.
  2729. ;; This kludge is unneeded in Emacs>=21 since define-derived-mode is
  2730. ;; now careful to run parent hooks after the body. --Stef
  2731. (when auto-fill-function
  2732. (setq auto-fill-function normal-auto-fill-function)))
  2733. ;;;
  2734. ;;; Message mode commands
  2735. ;;;
  2736. ;;; Movement commands
  2737. (defun message-goto-to ()
  2738. "Move point to the To header."
  2739. (interactive)
  2740. (message-position-on-field "To"))
  2741. (defun message-goto-from ()
  2742. "Move point to the From header."
  2743. (interactive)
  2744. (message-position-on-field "From"))
  2745. (defun message-goto-subject ()
  2746. "Move point to the Subject header."
  2747. (interactive)
  2748. (message-position-on-field "Subject"))
  2749. (defun message-goto-cc ()
  2750. "Move point to the Cc header."
  2751. (interactive)
  2752. (message-position-on-field "Cc" "To"))
  2753. (defun message-goto-bcc ()
  2754. "Move point to the Bcc header."
  2755. (interactive)
  2756. (message-position-on-field "Bcc" "Cc" "To"))
  2757. (defun message-goto-fcc ()
  2758. "Move point to the Fcc header."
  2759. (interactive)
  2760. (message-position-on-field "Fcc" "To" "Newsgroups"))
  2761. (defun message-goto-reply-to ()
  2762. "Move point to the Reply-To header."
  2763. (interactive)
  2764. (message-position-on-field "Reply-To" "Subject"))
  2765. (defun message-goto-newsgroups ()
  2766. "Move point to the Newsgroups header."
  2767. (interactive)
  2768. (message-position-on-field "Newsgroups"))
  2769. (defun message-goto-distribution ()
  2770. "Move point to the Distribution header."
  2771. (interactive)
  2772. (message-position-on-field "Distribution"))
  2773. (defun message-goto-followup-to ()
  2774. "Move point to the Followup-To header."
  2775. (interactive)
  2776. (message-position-on-field "Followup-To" "Newsgroups"))
  2777. (defun message-goto-mail-followup-to ()
  2778. "Move point to the Mail-Followup-To header."
  2779. (interactive)
  2780. (message-position-on-field "Mail-Followup-To" "To"))
  2781. (defun message-goto-keywords ()
  2782. "Move point to the Keywords header."
  2783. (interactive)
  2784. (message-position-on-field "Keywords" "Subject"))
  2785. (defun message-goto-summary ()
  2786. "Move point to the Summary header."
  2787. (interactive)
  2788. (message-position-on-field "Summary" "Subject"))
  2789. (eval-when-compile
  2790. (defmacro message-called-interactively-p (kind)
  2791. (condition-case nil
  2792. (progn
  2793. (eval '(called-interactively-p 'any))
  2794. ;; Emacs >=23.2
  2795. `(called-interactively-p ,kind))
  2796. ;; Emacs <23.2
  2797. (wrong-number-of-arguments '(called-interactively-p))
  2798. ;; XEmacs
  2799. (void-function '(interactive-p)))))
  2800. (defun message-goto-body ()
  2801. "Move point to the beginning of the message body."
  2802. (interactive)
  2803. (when (and (message-called-interactively-p 'any)
  2804. (looking-at "[ \t]*\n"))
  2805. (expand-abbrev))
  2806. (goto-char (point-min))
  2807. (or (search-forward (concat "\n" mail-header-separator "\n") nil t)
  2808. (search-forward-regexp "[^:]+:\\([^\n]\\|\n[ \t]\\)+\n\n" nil t)))
  2809. (defun message-in-body-p ()
  2810. "Return t if point is in the message body."
  2811. (let ((body (save-excursion (message-goto-body))))
  2812. (>= (point) body)))
  2813. (defun message-goto-eoh ()
  2814. "Move point to the end of the headers."
  2815. (interactive)
  2816. (message-goto-body)
  2817. (forward-line -1))
  2818. (defun message-goto-signature ()
  2819. "Move point to the beginning of the message signature.
  2820. If there is no signature in the article, go to the end and
  2821. return nil."
  2822. (interactive)
  2823. (goto-char (point-min))
  2824. (if (re-search-forward message-signature-separator nil t)
  2825. (forward-line 1)
  2826. (goto-char (point-max))
  2827. nil))
  2828. (defun message-generate-unsubscribed-mail-followup-to (&optional include-cc)
  2829. "Insert a reasonable MFT header in a post to an unsubscribed list.
  2830. When making original posts to a mailing list you are not subscribed to,
  2831. you have to type in a MFT header by hand. The contents, usually, are
  2832. the addresses of the list and your own address. This function inserts
  2833. such a header automatically. It fetches the contents of the To: header
  2834. in the current mail buffer, and appends the current `user-mail-address'.
  2835. If the optional argument INCLUDE-CC is non-nil, the addresses in the
  2836. Cc: header are also put into the MFT."
  2837. (interactive "P")
  2838. (let* (cc tos)
  2839. (save-restriction
  2840. (message-narrow-to-headers)
  2841. (message-remove-header "Mail-Followup-To")
  2842. (setq cc (and include-cc (message-fetch-field "Cc")))
  2843. (setq tos (if cc
  2844. (concat (message-fetch-field "To") "," cc)
  2845. (message-fetch-field "To"))))
  2846. (message-goto-mail-followup-to)
  2847. (insert (concat tos ", " user-mail-address))))
  2848. (defun message-insert-to (&optional force)
  2849. "Insert a To header that points to the author of the article being replied to.
  2850. If the original author requested not to be sent mail, don't insert unless the
  2851. prefix FORCE is given."
  2852. (interactive "P")
  2853. (let* ((mct (message-fetch-reply-field "mail-copies-to"))
  2854. (dont (and mct (or (equal (downcase mct) "never")
  2855. (equal (downcase mct) "nobody"))))
  2856. (to (or (message-fetch-reply-field "mail-reply-to")
  2857. (message-fetch-reply-field "reply-to")
  2858. (message-fetch-reply-field "from"))))
  2859. (when (and dont to)
  2860. (message
  2861. (if force
  2862. "Ignoring the user request not to have copies sent via mail"
  2863. "Complying with the user request not to have copies sent via mail")))
  2864. (when (and force (not to))
  2865. (error "No mail address in the article"))
  2866. (when (and to (or force (not dont)))
  2867. (message-carefully-insert-headers (list (cons 'To to))))))
  2868. (defun message-insert-wide-reply ()
  2869. "Insert To and Cc headers as if you were doing a wide reply."
  2870. (interactive)
  2871. (let ((headers (message-with-reply-buffer
  2872. (message-get-reply-headers t))))
  2873. (message-carefully-insert-headers headers)))
  2874. (defcustom message-header-synonyms
  2875. '((To Cc Bcc)
  2876. (Original-To))
  2877. "List of lists of header synonyms.
  2878. E.g., if this list contains a member list with elements `Cc' and `To',
  2879. then `message-carefully-insert-headers' will not insert a `To' header
  2880. when the message is already `Cc'ed to the recipient."
  2881. :version "22.1"
  2882. :group 'message-headers
  2883. :link '(custom-manual "(message)Message Headers")
  2884. :type '(repeat sexp))
  2885. (defun message-carefully-insert-headers (headers)
  2886. "Insert the HEADERS, an alist, into the message buffer.
  2887. Does not insert the headers when they are already present there
  2888. or in the synonym headers, defined by `message-header-synonyms'."
  2889. ;; FIXME: Should compare only the address and not the full name. Comparison
  2890. ;; should be done case-folded (and with `string=' rather than
  2891. ;; `string-match').
  2892. ;; (mail-strip-quoted-names "Foo Bar <foo@bar>, bla@fasel (Bla Fasel)")
  2893. (dolist (header headers)
  2894. (let* ((header-name (symbol-name (car header)))
  2895. (new-header (cdr header))
  2896. (synonyms (loop for synonym in message-header-synonyms
  2897. when (memq (car header) synonym) return synonym))
  2898. (old-header
  2899. (loop for synonym in synonyms
  2900. for old-header = (mail-fetch-field (symbol-name synonym))
  2901. when (and old-header (string-match new-header old-header))
  2902. return synonym)))
  2903. (if old-header
  2904. (message "already have `%s' in `%s'" new-header old-header)
  2905. (when (and (message-position-on-field header-name)
  2906. (setq old-header (mail-fetch-field header-name))
  2907. (not (string-match "\\` *\\'" old-header)))
  2908. (insert ", "))
  2909. (insert new-header)))))
  2910. (defun message-widen-reply ()
  2911. "Widen the reply to include maximum recipients."
  2912. (interactive)
  2913. (let ((follow-to
  2914. (and (bufferp message-reply-buffer)
  2915. (buffer-name message-reply-buffer)
  2916. (with-current-buffer message-reply-buffer
  2917. (message-get-reply-headers t)))))
  2918. (save-excursion
  2919. (save-restriction
  2920. (message-narrow-to-headers)
  2921. (dolist (elem follow-to)
  2922. (message-remove-header (symbol-name (car elem)))
  2923. (goto-char (point-min))
  2924. (insert (symbol-name (car elem)) ": "
  2925. (cdr elem) "\n"))))))
  2926. (defun message-insert-newsgroups ()
  2927. "Insert the Newsgroups header from the article being replied to."
  2928. (interactive)
  2929. (when (and (message-position-on-field "Newsgroups")
  2930. (mail-fetch-field "newsgroups")
  2931. (not (string-match "\\` *\\'" (mail-fetch-field "newsgroups"))))
  2932. (insert ","))
  2933. (insert (or (message-fetch-reply-field "newsgroups") "")))
  2934. ;;; Various commands
  2935. (defun message-delete-not-region (beg end)
  2936. "Delete everything in the body of the current message outside of the region."
  2937. (interactive "r")
  2938. (let (citeprefix)
  2939. (save-excursion
  2940. (goto-char beg)
  2941. ;; snarf citation prefix, if appropriate
  2942. (unless (eq (point) (progn (beginning-of-line) (point)))
  2943. (when (looking-at message-cite-prefix-regexp)
  2944. (setq citeprefix (match-string 0))))
  2945. (goto-char end)
  2946. (delete-region (point) (if (not (message-goto-signature))
  2947. (point)
  2948. (forward-line -2)
  2949. (point)))
  2950. (insert "\n")
  2951. (goto-char beg)
  2952. (delete-region beg (progn (message-goto-body)
  2953. (forward-line 2)
  2954. (point)))
  2955. (when citeprefix
  2956. (insert citeprefix))))
  2957. (when (message-goto-signature)
  2958. (forward-line -2)))
  2959. (defun message-kill-to-signature (&optional arg)
  2960. "Kill all text up to the signature.
  2961. If a numeric argument or prefix arg is given, leave that number
  2962. of lines before the signature intact."
  2963. (interactive "P")
  2964. (save-excursion
  2965. (save-restriction
  2966. (let ((point (point)))
  2967. (narrow-to-region point (point-max))
  2968. (message-goto-signature)
  2969. (unless (eobp)
  2970. (if (and arg (numberp arg))
  2971. (forward-line (- -1 arg))
  2972. (end-of-line -1)))
  2973. (unless (= point (point))
  2974. (kill-region point (point))
  2975. (unless (bolp)
  2976. (insert "\n")))))))
  2977. (defun message-newline-and-reformat (&optional arg not-break)
  2978. "Insert four newlines, and then reformat if inside quoted text.
  2979. Prefix arg means justify as well."
  2980. (interactive (list (if current-prefix-arg 'full)))
  2981. (let (quoted point beg end leading-space bolp fill-paragraph-function)
  2982. (setq point (point))
  2983. (beginning-of-line)
  2984. (setq beg (point))
  2985. (setq bolp (= beg point))
  2986. ;; Find first line of the paragraph.
  2987. (if not-break
  2988. (while (and (not (eobp))
  2989. (not (looking-at message-cite-prefix-regexp))
  2990. (looking-at paragraph-start))
  2991. (forward-line 1)))
  2992. ;; Find the prefix
  2993. (when (looking-at message-cite-prefix-regexp)
  2994. (setq quoted (match-string 0))
  2995. (goto-char (match-end 0))
  2996. (looking-at "[ \t]*")
  2997. (setq leading-space (match-string 0)))
  2998. (if (and quoted
  2999. (not not-break)
  3000. (not bolp)
  3001. (< (- point beg) (length quoted)))
  3002. ;; break inside the cite prefix.
  3003. (setq quoted nil
  3004. end nil))
  3005. (if quoted
  3006. (progn
  3007. (forward-line 1)
  3008. (while (and (not (eobp))
  3009. (not (looking-at paragraph-separate))
  3010. (looking-at message-cite-prefix-regexp)
  3011. (equal quoted (match-string 0)))
  3012. (goto-char (match-end 0))
  3013. (looking-at "[ \t]*")
  3014. (if (> (length leading-space) (length (match-string 0)))
  3015. (setq leading-space (match-string 0)))
  3016. (forward-line 1))
  3017. (setq end (point))
  3018. (goto-char beg)
  3019. (while (and (if (bobp) nil (forward-line -1) t)
  3020. (not (looking-at paragraph-start))
  3021. (looking-at message-cite-prefix-regexp)
  3022. (equal quoted (match-string 0)))
  3023. (setq beg (point))
  3024. (goto-char (match-end 0))
  3025. (looking-at "[ \t]*")
  3026. (if (> (length leading-space) (length (match-string 0)))
  3027. (setq leading-space (match-string 0)))))
  3028. (while (and (not (eobp))
  3029. (not (looking-at paragraph-separate))
  3030. (not (looking-at message-cite-prefix-regexp)))
  3031. (forward-line 1))
  3032. (setq end (point))
  3033. (goto-char beg)
  3034. (while (and (if (bobp) nil (forward-line -1) t)
  3035. (not (looking-at paragraph-start))
  3036. (not (looking-at message-cite-prefix-regexp)))
  3037. (setq beg (point))))
  3038. (goto-char point)
  3039. (save-restriction
  3040. (narrow-to-region beg end)
  3041. (if not-break
  3042. (setq point nil)
  3043. (if bolp
  3044. (newline)
  3045. (newline)
  3046. (newline))
  3047. (setq point (point))
  3048. ;; (newline 2) doesn't mark both newline's as hard, so call
  3049. ;; newline twice. -jas
  3050. (newline)
  3051. (newline)
  3052. (delete-region (point) (re-search-forward "[ \t]*"))
  3053. (when (and quoted (not bolp))
  3054. (insert quoted leading-space)))
  3055. (undo-boundary)
  3056. (if quoted
  3057. (let* ((adaptive-fill-regexp
  3058. (regexp-quote (concat quoted leading-space)))
  3059. (adaptive-fill-first-line-regexp
  3060. adaptive-fill-regexp ))
  3061. (fill-paragraph arg))
  3062. (fill-paragraph arg))
  3063. (if point (goto-char point)))))
  3064. (defun message-fill-paragraph (&optional arg)
  3065. "Message specific function to fill a paragraph.
  3066. This function is used as the value of `fill-paragraph-function' in
  3067. Message buffers and is not meant to be called directly."
  3068. (interactive (list (if current-prefix-arg 'full)))
  3069. (if (if (boundp 'filladapt-mode) filladapt-mode)
  3070. nil
  3071. (if (message-point-in-header-p)
  3072. (message-fill-field)
  3073. (message-newline-and-reformat arg t))
  3074. t))
  3075. (defun message-point-in-header-p ()
  3076. "Return t if point is in the header."
  3077. (save-excursion
  3078. (and
  3079. (not
  3080. (re-search-backward
  3081. (concat "^" (regexp-quote mail-header-separator) "\n") nil t))
  3082. (re-search-forward
  3083. (concat "^" (regexp-quote mail-header-separator) "\n") nil t))))
  3084. (defun message-do-auto-fill ()
  3085. "Like `do-auto-fill', but don't fill in message header."
  3086. (unless (message-point-in-header-p)
  3087. (do-auto-fill)))
  3088. (defun message-insert-signature (&optional force)
  3089. "Insert a signature. See documentation for variable `message-signature'."
  3090. (interactive (list 0))
  3091. (let* ((signature
  3092. (cond
  3093. ((and (null message-signature)
  3094. (eq force 0))
  3095. (save-excursion
  3096. (goto-char (point-max))
  3097. (not (re-search-backward message-signature-separator nil t))))
  3098. ((and (null message-signature)
  3099. force)
  3100. t)
  3101. ((functionp message-signature)
  3102. (funcall message-signature))
  3103. ((listp message-signature)
  3104. (eval message-signature))
  3105. (t message-signature)))
  3106. signature-file)
  3107. (setq signature
  3108. (cond ((stringp signature)
  3109. signature)
  3110. ((and (eq t signature) message-signature-file)
  3111. (setq signature-file
  3112. (if (and message-signature-directory
  3113. ;; don't actually use the signature directory
  3114. ;; if message-signature-file contains a path.
  3115. (not (file-name-directory
  3116. message-signature-file)))
  3117. (expand-file-name message-signature-file
  3118. message-signature-directory)
  3119. message-signature-file))
  3120. (file-exists-p signature-file))))
  3121. (when signature
  3122. (goto-char (point-max))
  3123. ;; Insert the signature.
  3124. (unless (bolp)
  3125. (insert "\n"))
  3126. (when message-signature-insert-empty-line
  3127. (insert "\n"))
  3128. (insert "-- \n")
  3129. (if (eq signature t)
  3130. (insert-file-contents signature-file)
  3131. (insert signature))
  3132. (goto-char (point-max))
  3133. (or (bolp) (insert "\n")))))
  3134. (defun message-insert-importance-high ()
  3135. "Insert header to mark message as important."
  3136. (interactive)
  3137. (save-excursion
  3138. (save-restriction
  3139. (message-narrow-to-headers)
  3140. (message-remove-header "Importance"))
  3141. (message-goto-eoh)
  3142. (insert "Importance: high\n")))
  3143. (defun message-insert-importance-low ()
  3144. "Insert header to mark message as unimportant."
  3145. (interactive)
  3146. (save-excursion
  3147. (save-restriction
  3148. (message-narrow-to-headers)
  3149. (message-remove-header "Importance"))
  3150. (message-goto-eoh)
  3151. (insert "Importance: low\n")))
  3152. (defun message-insert-or-toggle-importance ()
  3153. "Insert a \"Importance: high\" header, or cycle through the header values.
  3154. The three allowed values according to RFC 1327 are `high', `normal'
  3155. and `low'."
  3156. (interactive)
  3157. (save-excursion
  3158. (let ((new "high")
  3159. cur)
  3160. (save-restriction
  3161. (message-narrow-to-headers)
  3162. (when (setq cur (message-fetch-field "Importance"))
  3163. (message-remove-header "Importance")
  3164. (setq new (cond ((string= cur "high")
  3165. "low")
  3166. ((string= cur "low")
  3167. "normal")
  3168. (t
  3169. "high")))))
  3170. (message-goto-eoh)
  3171. (insert (format "Importance: %s\n" new)))))
  3172. (defun message-insert-disposition-notification-to ()
  3173. "Request a disposition notification (return receipt) to this message.
  3174. Note that this should not be used in newsgroups."
  3175. (interactive)
  3176. (save-excursion
  3177. (save-restriction
  3178. (message-narrow-to-headers)
  3179. (message-remove-header "Disposition-Notification-To"))
  3180. (message-goto-eoh)
  3181. (insert (format "Disposition-Notification-To: %s\n"
  3182. (or (message-field-value "Reply-to")
  3183. (message-field-value "From")
  3184. (message-make-from))))))
  3185. (defun message-elide-region (b e)
  3186. "Elide the text in the region.
  3187. An ellipsis (from `message-elide-ellipsis') will be inserted where the
  3188. text was killed."
  3189. (interactive "r")
  3190. (let ((lines (count-lines b e))
  3191. (chars (- e b)))
  3192. (kill-region b e)
  3193. (insert (format-spec message-elide-ellipsis
  3194. `((?l . ,lines)
  3195. (?c . ,chars))))))
  3196. (defvar message-caesar-translation-table nil)
  3197. (defun message-caesar-region (b e &optional n)
  3198. "Caesar rotate region B to E by N, default 13, for decrypting netnews."
  3199. (interactive
  3200. (list
  3201. (min (point) (or (mark t) (point)))
  3202. (max (point) (or (mark t) (point)))
  3203. (when current-prefix-arg
  3204. (prefix-numeric-value current-prefix-arg))))
  3205. (setq n (if (numberp n) (mod n 26) 13)) ;canonize N
  3206. (unless (or (zerop n) ; no action needed for a rot of 0
  3207. (= b e)) ; no region to rotate
  3208. ;; We build the table, if necessary.
  3209. (when (or (not message-caesar-translation-table)
  3210. (/= (aref message-caesar-translation-table ?a) (+ ?a n)))
  3211. (setq message-caesar-translation-table
  3212. (message-make-caesar-translation-table n)))
  3213. (translate-region b e message-caesar-translation-table)))
  3214. (defun message-make-caesar-translation-table (n)
  3215. "Create a rot table with offset N."
  3216. (let ((i -1)
  3217. (table (make-string 256 0)))
  3218. (while (< (incf i) 256)
  3219. (aset table i i))
  3220. (concat
  3221. (substring table 0 ?A)
  3222. (substring table (+ ?A n) (+ ?A n (- 26 n)))
  3223. (substring table ?A (+ ?A n))
  3224. (substring table (+ ?A 26) ?a)
  3225. (substring table (+ ?a n) (+ ?a n (- 26 n)))
  3226. (substring table ?a (+ ?a n))
  3227. (substring table (+ ?a 26) 255))))
  3228. (defun message-caesar-buffer-body (&optional rotnum wide)
  3229. "Caesar rotate all letters in the current buffer by 13 places.
  3230. Used to encode/decode possibly offensive messages (commonly in rec.humor).
  3231. With prefix arg, specifies the number of places to rotate each letter forward.
  3232. Mail and USENET news headers are not rotated unless WIDE is non-nil."
  3233. (interactive (if current-prefix-arg
  3234. (list (prefix-numeric-value current-prefix-arg))
  3235. (list nil)))
  3236. (save-excursion
  3237. (save-restriction
  3238. (when (and (not wide) (message-goto-body))
  3239. (narrow-to-region (point) (point-max)))
  3240. (message-caesar-region (point-min) (point-max) rotnum))))
  3241. (defun message-pipe-buffer-body (program)
  3242. "Pipe the message body in the current buffer through PROGRAM."
  3243. (save-excursion
  3244. (save-restriction
  3245. (when (message-goto-body)
  3246. (narrow-to-region (point) (point-max)))
  3247. (shell-command-on-region
  3248. (point-min) (point-max) program nil t))))
  3249. (defun message-rename-buffer (&optional enter-string)
  3250. "Rename the *message* buffer to \"*message* RECIPIENT\".
  3251. If the function is run with a prefix, it will ask for a new buffer
  3252. name, rather than giving an automatic name."
  3253. (interactive "Pbuffer name: ")
  3254. (save-excursion
  3255. (save-restriction
  3256. (goto-char (point-min))
  3257. (narrow-to-region (point)
  3258. (search-forward mail-header-separator nil 'end))
  3259. (let* ((mail-to (or
  3260. (if (message-news-p) (message-fetch-field "Newsgroups")
  3261. (message-fetch-field "To"))
  3262. ""))
  3263. (mail-trimmed-to
  3264. (if (string-match "," mail-to)
  3265. (concat (substring mail-to 0 (match-beginning 0)) ", ...")
  3266. mail-to))
  3267. (name-default (concat "*message* " mail-trimmed-to))
  3268. (name (if enter-string
  3269. (read-string "New buffer name: " name-default)
  3270. name-default)))
  3271. (rename-buffer name t)))))
  3272. (defun message-fill-yanked-message (&optional justifyp)
  3273. "Fill the paragraphs of a message yanked into this one.
  3274. Numeric argument means justify as well."
  3275. (interactive "P")
  3276. (save-excursion
  3277. (goto-char (point-min))
  3278. (search-forward (concat "\n" mail-header-separator "\n") nil t)
  3279. (let ((fill-prefix message-yank-prefix))
  3280. (fill-individual-paragraphs (point) (point-max) justifyp))))
  3281. (defun message-indent-citation (&optional start end yank-only)
  3282. "Modify text just inserted from a message to be cited.
  3283. The inserted text should be the region.
  3284. When this function returns, the region is again around the modified text.
  3285. Normally, indent each nonblank line `message-indentation-spaces' spaces.
  3286. However, if `message-yank-prefix' is non-nil, insert that prefix on each line."
  3287. (unless start (setq start (point)))
  3288. (unless yank-only
  3289. ;; Remove unwanted headers.
  3290. (when message-ignored-cited-headers
  3291. (let (all-removed)
  3292. (save-restriction
  3293. (narrow-to-region
  3294. (goto-char start)
  3295. (if (search-forward "\n\n" nil t)
  3296. (1- (point))
  3297. (point)))
  3298. (message-remove-header message-ignored-cited-headers t)
  3299. (when (= (point-min) (point-max))
  3300. (setq all-removed t))
  3301. (goto-char (point-max)))
  3302. (if all-removed
  3303. (goto-char start)
  3304. (forward-line 1))))
  3305. ;; Delete blank lines at the start of the buffer.
  3306. (while (and (point-min)
  3307. (eolp)
  3308. (not (eobp)))
  3309. (message-delete-line))
  3310. ;; Delete blank lines at the end of the buffer.
  3311. (goto-char (point-max))
  3312. (unless (eq (preceding-char) ?\n)
  3313. (insert "\n"))
  3314. (while (and (zerop (forward-line -1))
  3315. (looking-at "$"))
  3316. (message-delete-line)))
  3317. ;; Do the indentation.
  3318. (if (null message-yank-prefix)
  3319. (indent-rigidly start (or end (mark t)) message-indentation-spaces)
  3320. (save-excursion
  3321. (goto-char start)
  3322. (while (< (point) (or end (mark t)))
  3323. (cond ((looking-at ">")
  3324. (insert message-yank-cited-prefix))
  3325. ((looking-at "^$")
  3326. (insert message-yank-empty-prefix))
  3327. (t
  3328. (insert message-yank-prefix)))
  3329. (forward-line 1))))
  3330. (goto-char start))
  3331. (defun message-remove-blank-cited-lines (&optional remove)
  3332. "Remove cited lines containing only blanks.
  3333. If REMOVE is non-nil, remove newlines, too.
  3334. To use this automatically, you may add this function to
  3335. `gnus-message-setup-hook'."
  3336. (interactive "P")
  3337. (let ((citexp
  3338. (concat
  3339. "^\\("
  3340. (when (boundp 'message-yank-cited-prefix)
  3341. (concat message-yank-cited-prefix "\\|"))
  3342. message-yank-prefix
  3343. "\\)+ *\n"
  3344. )))
  3345. (gnus-message 8 "removing `%s'" citexp)
  3346. (save-excursion
  3347. (message-goto-body)
  3348. (while (re-search-forward citexp nil t)
  3349. (replace-match (if remove "" "\n"))))))
  3350. (defun message--yank-original-internal (arg)
  3351. (let ((modified (buffer-modified-p))
  3352. body-text)
  3353. (when (and message-reply-buffer
  3354. message-cite-function)
  3355. (when (equal message-cite-reply-position 'above)
  3356. (save-excursion
  3357. (setq body-text
  3358. (buffer-substring (message-goto-body)
  3359. (point-max)))
  3360. (delete-region (message-goto-body) (point-max))))
  3361. (if (bufferp message-reply-buffer)
  3362. (delete-windows-on message-reply-buffer t))
  3363. (push-mark (save-excursion
  3364. (cond
  3365. ((bufferp message-reply-buffer)
  3366. (insert-buffer-substring message-reply-buffer))
  3367. ((and (consp message-reply-buffer)
  3368. (functionp (car message-reply-buffer)))
  3369. (apply (car message-reply-buffer)
  3370. (cdr message-reply-buffer))))
  3371. (unless (bolp)
  3372. (insert ?\n))
  3373. (point)))
  3374. (unless arg
  3375. (funcall message-cite-function)
  3376. (unless (eq (char-before (mark t)) ?\n)
  3377. (let ((pt (point)))
  3378. (goto-char (mark t))
  3379. (insert-before-markers ?\n)
  3380. (goto-char pt))))
  3381. (case message-cite-reply-position
  3382. (above
  3383. (message-goto-body)
  3384. (insert body-text)
  3385. (insert (if (bolp) "\n" "\n\n"))
  3386. (message-goto-body))
  3387. (below
  3388. (message-goto-signature)))
  3389. ;; Add a `message-setup-very-last-hook' here?
  3390. ;; Add `gnus-article-highlight-citation' here?
  3391. (unless modified
  3392. (setq message-checksum (message-checksum))))))
  3393. (defun message-yank-original (&optional arg)
  3394. "Insert the message being replied to, if any.
  3395. Puts point before the text and mark after.
  3396. Normally indents each nonblank line ARG spaces (default 3). However,
  3397. if `message-yank-prefix' is non-nil, insert that prefix on each line.
  3398. This function uses `message-cite-function' to do the actual citing.
  3399. Just \\[universal-argument] as argument means don't indent, insert no
  3400. prefix, and don't delete any headers."
  3401. (interactive "P")
  3402. ;; eval the let forms contained in message-cite-style
  3403. (eval
  3404. `(let ,message-cite-style
  3405. (message--yank-original-internal ',arg))))
  3406. (defun message-yank-buffer (buffer)
  3407. "Insert BUFFER into the current buffer and quote it."
  3408. (interactive "bYank buffer: ")
  3409. (let ((message-reply-buffer (get-buffer buffer)))
  3410. (save-window-excursion
  3411. (message-yank-original))))
  3412. (defun message-buffers ()
  3413. "Return a list of active message buffers."
  3414. (let (buffers)
  3415. (save-current-buffer
  3416. (dolist (buffer (buffer-list t))
  3417. (set-buffer buffer)
  3418. (when (and (eq major-mode 'message-mode)
  3419. (null message-sent-message-via))
  3420. (push (buffer-name buffer) buffers))))
  3421. (nreverse buffers)))
  3422. (defun message-cite-original-1 (strip-signature)
  3423. "Cite an original message.
  3424. If STRIP-SIGNATURE is non-nil, strips off the signature from the
  3425. original message.
  3426. This function uses `mail-citation-hook' if that is non-nil."
  3427. (if (and (boundp 'mail-citation-hook)
  3428. mail-citation-hook)
  3429. (run-hooks 'mail-citation-hook)
  3430. (let* ((start (point))
  3431. (end (mark t))
  3432. (x-no-archive nil)
  3433. (functions
  3434. (when message-indent-citation-function
  3435. (if (listp message-indent-citation-function)
  3436. message-indent-citation-function
  3437. (list message-indent-citation-function))))
  3438. ;; This function may be called by `gnus-summary-yank-message' and
  3439. ;; may insert a different article from the original. So, we will
  3440. ;; modify the value of `message-reply-headers' with that article.
  3441. (message-reply-headers
  3442. (save-restriction
  3443. (narrow-to-region start end)
  3444. (message-narrow-to-head-1)
  3445. (setq x-no-archive (message-fetch-field "x-no-archive"))
  3446. (vector 0
  3447. (or (message-fetch-field "subject") "none")
  3448. (or (message-fetch-field "from") "nobody")
  3449. (message-fetch-field "date")
  3450. (message-fetch-field "message-id" t)
  3451. (message-fetch-field "references")
  3452. 0 0 ""))))
  3453. (mml-quote-region start end)
  3454. (when strip-signature
  3455. ;; Allow undoing.
  3456. (undo-boundary)
  3457. (goto-char end)
  3458. (when (re-search-backward message-signature-separator start t)
  3459. ;; Also peel off any blank lines before the signature.
  3460. (forward-line -1)
  3461. (while (looking-at "^[ \t]*$")
  3462. (forward-line -1))
  3463. (forward-line 1)
  3464. (delete-region (point) end)
  3465. (unless (search-backward "\n\n" start t)
  3466. ;; Insert a blank line if it is peeled off.
  3467. (insert "\n"))))
  3468. (goto-char start)
  3469. (mapc 'funcall functions)
  3470. (when message-citation-line-function
  3471. (unless (bolp)
  3472. (insert "\n"))
  3473. (funcall message-citation-line-function))
  3474. (when (and x-no-archive
  3475. (not message-cite-articles-with-x-no-archive)
  3476. (string-match "yes" x-no-archive))
  3477. (undo-boundary)
  3478. (delete-region (point) (mark t))
  3479. (insert "> [Quoted text removed due to X-No-Archive]\n")
  3480. (push-mark)
  3481. (forward-line -1)))))
  3482. (defun message-cite-original ()
  3483. "Cite function in the standard Message manner."
  3484. (message-cite-original-1 nil))
  3485. (defvar gnus-extract-address-components)
  3486. (autoload 'format-spec "format-spec")
  3487. (defun message-insert-formatted-citation-line (&optional from date)
  3488. "Function that inserts a formatted citation line.
  3489. See `message-citation-line-format'."
  3490. ;; The optional args are for testing/debugging. They will disappear later.
  3491. ;; Example:
  3492. ;; (with-temp-buffer
  3493. ;; (message-insert-formatted-citation-line
  3494. ;; "John Doe <john.doe@example.invalid>"
  3495. ;; (current-time))
  3496. ;; (buffer-string))
  3497. (when (or message-reply-headers (and from date))
  3498. (unless from
  3499. (setq from (mail-header-from message-reply-headers)))
  3500. (let* ((data (condition-case ()
  3501. (funcall (if (boundp gnus-extract-address-components)
  3502. gnus-extract-address-components
  3503. 'mail-extract-address-components)
  3504. from)
  3505. (error nil)))
  3506. (name (car data))
  3507. (fname name)
  3508. (lname name)
  3509. (net (car (cdr data)))
  3510. (name-or-net (or (car data)
  3511. (car (cdr data)) from))
  3512. (replydate
  3513. (or
  3514. date
  3515. ;; We need Gnus functionality if the user wants date or time from
  3516. ;; the original article:
  3517. (when (string-match "%[^fnNFL]" message-citation-line-format)
  3518. (autoload 'gnus-date-get-time "gnus-util")
  3519. (gnus-date-get-time (mail-header-date message-reply-headers)))))
  3520. (flist
  3521. (let ((i ?A) lst)
  3522. (when (stringp name)
  3523. ;; Guess first name and last name:
  3524. (cond ((string-match
  3525. "\\`\\(\\w\\|[-.]\\)+ \\(\\w\\|[-.]\\)+\\'" name)
  3526. (setq fname (nth 0 (split-string name "[ \t]+"))
  3527. lname (nth 1 (split-string name "[ \t]+"))))
  3528. ((string-match
  3529. "\\`\\(\\w\\|[-.]\\)+, \\(\\w\\|[-.]\\)+\\'" name)
  3530. (setq fname (nth 1 (split-string name "[ \t,]+"))
  3531. lname (nth 0 (split-string name "[ \t,]+"))))
  3532. ((string-match
  3533. "\\`\\(\\w\\|[-.]\\)+\\'" name)
  3534. (setq fname name
  3535. lname ""))))
  3536. ;; The following letters are not used in `format-time-string':
  3537. (push ?E lst) (push "<E>" lst)
  3538. (push ?F lst) (push fname lst)
  3539. ;; We might want to use "" instead of "<X>" later.
  3540. (push ?J lst) (push "<J>" lst)
  3541. (push ?K lst) (push "<K>" lst)
  3542. (push ?L lst) (push lname lst)
  3543. (push ?N lst) (push name-or-net lst)
  3544. (push ?O lst) (push "<O>" lst)
  3545. (push ?P lst) (push "<P>" lst)
  3546. (push ?Q lst) (push "<Q>" lst)
  3547. (push ?f lst) (push from lst)
  3548. (push ?i lst) (push "<i>" lst)
  3549. (push ?n lst) (push net lst)
  3550. (push ?o lst) (push "<o>" lst)
  3551. (push ?q lst) (push "<q>" lst)
  3552. (push ?t lst) (push "<t>" lst)
  3553. (push ?v lst) (push "<v>" lst)
  3554. ;; Delegate the rest to `format-time-string':
  3555. (while (<= i ?z)
  3556. (when (and (not (memq i lst))
  3557. ;; Skip (Z,a)
  3558. (or (<= i ?Z)
  3559. (>= i ?a)))
  3560. (push i lst)
  3561. (push (condition-case nil
  3562. (format-time-string (format "%%%c" i) replydate)
  3563. (error (format ">%c<" i)))
  3564. lst))
  3565. (setq i (1+ i)))
  3566. (reverse lst)))
  3567. (spec (apply 'format-spec-make flist)))
  3568. (insert (format-spec message-citation-line-format spec)))
  3569. (newline)))
  3570. (defun message-cite-original-without-signature ()
  3571. "Cite function in the standard Message manner.
  3572. This function strips off the signature from the original message."
  3573. (message-cite-original-1 t))
  3574. (defun message-insert-citation-line ()
  3575. "Insert a simple citation line."
  3576. (when message-reply-headers
  3577. (insert (mail-header-from message-reply-headers) " writes:")
  3578. (newline)
  3579. (newline)))
  3580. (defun message-position-on-field (header &rest afters)
  3581. (let ((case-fold-search t))
  3582. (save-restriction
  3583. (narrow-to-region
  3584. (goto-char (point-min))
  3585. (progn
  3586. (re-search-forward
  3587. (concat "^" (regexp-quote mail-header-separator) "$"))
  3588. (match-beginning 0)))
  3589. (goto-char (point-min))
  3590. (if (re-search-forward (concat "^" (regexp-quote header) ":") nil t)
  3591. (progn
  3592. (re-search-forward "^[^ \t]" nil 'move)
  3593. (beginning-of-line)
  3594. (skip-chars-backward "\n")
  3595. t)
  3596. (while (and afters
  3597. (not (re-search-forward
  3598. (concat "^" (regexp-quote (car afters)) ":")
  3599. nil t)))
  3600. (pop afters))
  3601. (when afters
  3602. (re-search-forward "^[^ \t]" nil 'move)
  3603. (beginning-of-line))
  3604. (insert header ": \n")
  3605. (forward-char -1)
  3606. nil))))
  3607. (defun message-remove-signature ()
  3608. "Remove the signature from the text between point and mark.
  3609. The text will also be indented the normal way."
  3610. (save-excursion
  3611. (let ((start (point))
  3612. mark)
  3613. (if (not (re-search-forward message-signature-separator (mark t) t))
  3614. ;; No signature here, so we just indent the cited text.
  3615. (message-indent-citation)
  3616. ;; Find the last non-empty line.
  3617. (forward-line -1)
  3618. (while (looking-at "[ \t]*$")
  3619. (forward-line -1))
  3620. (forward-line 1)
  3621. (setq mark (set-marker (make-marker) (point)))
  3622. (goto-char start)
  3623. (message-indent-citation)
  3624. ;; Enable undoing the deletion.
  3625. (undo-boundary)
  3626. (delete-region mark (mark t))
  3627. (set-marker mark nil)))))
  3628. ;;;
  3629. ;;; Sending messages
  3630. ;;;
  3631. (defun message-send-and-exit (&optional arg)
  3632. "Send message like `message-send', then, if no errors, exit from mail buffer.
  3633. The usage of ARG is defined by the instance that called Message.
  3634. It should typically alter the sending method in some way or other."
  3635. (interactive "P")
  3636. (let ((buf (current-buffer))
  3637. (actions message-exit-actions))
  3638. (when (and (message-send arg)
  3639. (buffer-name buf))
  3640. (message-bury buf)
  3641. (if message-kill-buffer-on-exit
  3642. (kill-buffer buf))
  3643. (message-do-actions actions)
  3644. t)))
  3645. (defun message-dont-send ()
  3646. "Don't send the message you have been editing.
  3647. Instead, just auto-save the buffer and then bury it."
  3648. (interactive)
  3649. (set-buffer-modified-p t)
  3650. (save-buffer)
  3651. (let ((actions message-postpone-actions))
  3652. (message-bury (current-buffer))
  3653. (message-do-actions actions)))
  3654. (defun message-kill-buffer ()
  3655. "Kill the current buffer."
  3656. (interactive)
  3657. (when (or (not (buffer-modified-p))
  3658. (not message-kill-buffer-query)
  3659. (yes-or-no-p "Message modified; kill anyway? "))
  3660. (let ((actions message-kill-actions)
  3661. (draft-article message-draft-article)
  3662. (auto-save-file-name buffer-auto-save-file-name)
  3663. (file-name buffer-file-name)
  3664. (modified (buffer-modified-p)))
  3665. (setq buffer-file-name nil)
  3666. (kill-buffer (current-buffer))
  3667. (when (and (or (and auto-save-file-name
  3668. (file-exists-p auto-save-file-name))
  3669. (and file-name
  3670. (file-exists-p file-name)))
  3671. (progn
  3672. ;; If the message buffer has lived in a dedicated window,
  3673. ;; `kill-buffer' has killed the frame. Thus the
  3674. ;; `yes-or-no-p' may show up in a lowered frame. Make sure
  3675. ;; that the user can see the question by raising the
  3676. ;; current frame:
  3677. (raise-frame)
  3678. (yes-or-no-p (format "Remove the backup file%s? "
  3679. (if modified " too" "")))))
  3680. (ignore-errors
  3681. (delete-file auto-save-file-name))
  3682. (let ((message-draft-article draft-article))
  3683. (message-disassociate-draft)))
  3684. (message-do-actions actions))))
  3685. (defun message-bury (buffer)
  3686. "Bury this mail BUFFER."
  3687. (if message-return-action
  3688. (progn
  3689. (bury-buffer buffer)
  3690. (apply (car message-return-action) (cdr message-return-action)))
  3691. (with-current-buffer buffer (bury-buffer))))
  3692. (defun message-send (&optional arg)
  3693. "Send the message in the current buffer.
  3694. If `message-interactive' is non-nil, wait for success indication or
  3695. error messages, and inform user.
  3696. Otherwise any failure is reported in a message back to the user from
  3697. the mailer.
  3698. The usage of ARG is defined by the instance that called Message.
  3699. It should typically alter the sending method in some way or other."
  3700. (interactive "P")
  3701. ;; Make it possible to undo the coming changes.
  3702. (undo-boundary)
  3703. (let ((inhibit-read-only t))
  3704. (put-text-property (point-min) (point-max) 'read-only nil))
  3705. (message-fix-before-sending)
  3706. (run-hooks 'message-send-hook)
  3707. (when message-confirm-send
  3708. (or (y-or-n-p "Send message? ")
  3709. (keyboard-quit)))
  3710. (message message-sending-message)
  3711. (let ((alist message-send-method-alist)
  3712. (success t)
  3713. elem sent dont-barf-on-no-method
  3714. (message-options message-options))
  3715. (message-options-set-recipient)
  3716. (while (and success
  3717. (setq elem (pop alist)))
  3718. (when (funcall (cadr elem))
  3719. (when (and (or (not (memq (car elem)
  3720. message-sent-message-via))
  3721. (message-fetch-field "supersedes")
  3722. (if (or (message-gnksa-enable-p 'multiple-copies)
  3723. (not (eq (car elem) 'news)))
  3724. (y-or-n-p
  3725. (format
  3726. "Already sent message via %s; resend? "
  3727. (car elem)))
  3728. (error "Denied posting -- multiple copies")))
  3729. (setq success (funcall (caddr elem) arg)))
  3730. (setq sent t))))
  3731. (unless (or sent
  3732. (not success)
  3733. (let ((fcc (message-fetch-field "Fcc"))
  3734. (gcc (message-fetch-field "Gcc")))
  3735. (when (or fcc gcc)
  3736. (or (eq message-allow-no-recipients 'always)
  3737. (and (not (eq message-allow-no-recipients 'never))
  3738. (setq dont-barf-on-no-method
  3739. (gnus-y-or-n-p
  3740. (format "No receiver, perform %s anyway? "
  3741. (cond ((and fcc gcc) "Fcc and Gcc")
  3742. (fcc "Fcc")
  3743. (t "Gcc"))))))))))
  3744. (error "No methods specified to send by"))
  3745. (when (or dont-barf-on-no-method
  3746. (and success sent))
  3747. (message-do-fcc)
  3748. (save-excursion
  3749. (run-hooks 'message-sent-hook))
  3750. (message "Sending...done")
  3751. ;; Do ecomplete address snarfing.
  3752. (when (and (message-mail-alias-type-p 'ecomplete)
  3753. (not message-inhibit-ecomplete))
  3754. (message-put-addresses-in-ecomplete))
  3755. ;; Mark the buffer as unmodified and delete auto-save.
  3756. (set-buffer-modified-p nil)
  3757. (delete-auto-save-file-if-necessary t)
  3758. (message-disassociate-draft)
  3759. ;; Delete other mail buffers and stuff.
  3760. (message-do-send-housekeeping)
  3761. (message-do-actions message-send-actions)
  3762. ;; Return success.
  3763. t)))
  3764. (defun message-send-via-mail (arg)
  3765. "Send the current message via mail."
  3766. (message-send-mail arg))
  3767. (defun message-send-via-news (arg)
  3768. "Send the current message via news."
  3769. (funcall message-send-news-function arg))
  3770. (defmacro message-check (type &rest forms)
  3771. "Eval FORMS if TYPE is to be checked."
  3772. `(or (message-check-element ,type)
  3773. (save-excursion
  3774. ,@forms)))
  3775. (put 'message-check 'lisp-indent-function 1)
  3776. (put 'message-check 'edebug-form-spec '(form body))
  3777. (defun message-text-with-property (prop &optional start end reverse)
  3778. "Return a list of start and end positions where the text has PROP.
  3779. START and END bound the search, they default to `point-min' and
  3780. `point-max' respectively. If REVERSE is non-nil, find text which does
  3781. not have PROP."
  3782. (unless start
  3783. (setq start (point-min)))
  3784. (unless end
  3785. (setq end (point-max)))
  3786. (let (next regions)
  3787. (if reverse
  3788. (while (and start
  3789. (setq start (text-property-any start end prop nil)))
  3790. (setq next (next-single-property-change start prop nil end))
  3791. (push (cons start (or next end)) regions)
  3792. (setq start next))
  3793. (while (and start
  3794. (or (get-text-property start prop)
  3795. (and (setq start (next-single-property-change
  3796. start prop nil end))
  3797. (get-text-property start prop))))
  3798. (setq next (text-property-any start end prop nil))
  3799. (push (cons start (or next end)) regions)
  3800. (setq start next)))
  3801. (nreverse regions)))
  3802. (defcustom message-bogus-addresses
  3803. '("noreply" "nospam" "invalid" "@@" "[^[:ascii:]].*@" "[ \t]")
  3804. "List of regexps of potentially bogus mail addresses.
  3805. See `message-check-recipients' how to setup checking.
  3806. This list should make it possible to catch typos or warn about
  3807. spam-trap addresses. It doesn't aim to verify strict RFC
  3808. conformance."
  3809. :version "23.1" ;; No Gnus
  3810. :group 'message-headers
  3811. :type '(choice
  3812. (const :tag "None" nil)
  3813. (list
  3814. (set :inline t
  3815. (const "noreply")
  3816. (const "nospam")
  3817. (const "invalid")
  3818. (const :tag "duplicate @" "@@")
  3819. (const :tag "non-ascii local part" "[^[:ascii:]].*@")
  3820. ;; Already caught by `message-valid-fqdn-regexp'
  3821. ;; (const :tag "`_' in domain part" "@.*_")
  3822. (const :tag "whitespace" "[ \t]"))
  3823. (repeat :inline t
  3824. :tag "Other"
  3825. (regexp)))))
  3826. (defun message-fix-before-sending ()
  3827. "Do various things to make the message nice before sending it."
  3828. ;; Make sure there's a newline at the end of the message.
  3829. (goto-char (point-max))
  3830. (unless (bolp)
  3831. (insert "\n"))
  3832. ;; Make the hidden headers visible.
  3833. (widen)
  3834. ;; Sort headers before sending the message.
  3835. (message-sort-headers)
  3836. ;; Make invisible text visible.
  3837. ;; It doesn't seem as if this is useful, since the invisible property
  3838. ;; is clobbered by an after-change hook anyhow.
  3839. (message-check 'invisible-text
  3840. (let ((regions (message-text-with-property 'invisible))
  3841. from to)
  3842. (when regions
  3843. (while regions
  3844. (setq from (caar regions)
  3845. to (cdar regions)
  3846. regions (cdr regions))
  3847. (put-text-property from to 'invisible nil)
  3848. (message-overlay-put (message-make-overlay from to)
  3849. 'face 'highlight))
  3850. (unless (yes-or-no-p
  3851. "Invisible text found and made visible; continue sending? ")
  3852. (error "Invisible text found and made visible")))))
  3853. (message-check 'illegible-text
  3854. (let (char found choice nul-chars)
  3855. (message-goto-body)
  3856. (setq nul-chars (save-excursion
  3857. (search-forward "\000" nil t)))
  3858. (while (progn
  3859. (skip-chars-forward mm-7bit-chars)
  3860. (when (get-text-property (point) 'no-illegible-text)
  3861. ;; There is a signed or encrypted raw message part
  3862. ;; that is considered to be safe.
  3863. (goto-char (or (next-single-property-change
  3864. (point) 'no-illegible-text)
  3865. (point-max))))
  3866. (setq char (char-after)))
  3867. (when (or (< (mm-char-int char) 128)
  3868. (and (mm-multibyte-p)
  3869. (memq (char-charset char)
  3870. '(eight-bit-control eight-bit-graphic
  3871. ;; Emacs 23, Bug#1770:
  3872. eight-bit
  3873. control-1))
  3874. (not (get-text-property
  3875. (point) 'untranslated-utf-8))))
  3876. (message-overlay-put (message-make-overlay (point) (1+ (point)))
  3877. 'face 'highlight)
  3878. (setq found t))
  3879. (forward-char))
  3880. (when found
  3881. (setq choice
  3882. (gnus-multiple-choice
  3883. (if nul-chars
  3884. "NUL characters found, which may cause problems. Continue sending?"
  3885. "Non-printable characters found. Continue sending?")
  3886. `((?d "Remove non-printable characters and send")
  3887. (?r ,(format
  3888. "Replace non-printable characters with \"%s\" and send"
  3889. message-replacement-char))
  3890. (?s "Send as is without removing anything")
  3891. (?e "Continue editing"))))
  3892. (if (eq choice ?e)
  3893. (error "Non-printable characters"))
  3894. (message-goto-body)
  3895. (skip-chars-forward mm-7bit-chars)
  3896. (while (not (eobp))
  3897. (when (let ((char (char-after)))
  3898. (or (< (mm-char-int char) 128)
  3899. (and (mm-multibyte-p)
  3900. ;; FIXME: Wrong for Emacs 23 (unicode) and for
  3901. ;; things like undecodable utf-8 (in Emacs 21?).
  3902. ;; Should at least use find-coding-systems-region.
  3903. ;; -- fx
  3904. (memq (char-charset char)
  3905. '(eight-bit-control eight-bit-graphic
  3906. ;; Emacs 23, Bug#1770:
  3907. eight-bit
  3908. control-1))
  3909. (not (get-text-property
  3910. (point) 'untranslated-utf-8)))))
  3911. (if (eq choice ?i)
  3912. (message-kill-all-overlays)
  3913. (delete-char 1)
  3914. (when (eq choice ?r)
  3915. (insert message-replacement-char))))
  3916. (forward-char)
  3917. (skip-chars-forward mm-7bit-chars)))))
  3918. (message-check 'bogus-recipient
  3919. ;; Warn before sending a mail to an invalid address.
  3920. (message-check-recipients)))
  3921. (defun message-bogus-recipient-p (recipients)
  3922. "Check if a mail address in RECIPIENTS looks bogus.
  3923. RECIPIENTS is a mail header. Return a list of potentially bogus
  3924. addresses. If none is found, return nil.
  3925. An address might be bogus if the domain part is not fully
  3926. qualified, see `message-valid-fqdn-regexp', or if there's a
  3927. matching entry in `message-bogus-addresses'."
  3928. ;; FIXME: How about "foo@subdomain", when the MTA adds ".domain.tld"?
  3929. (let (found)
  3930. (mapc (lambda (address)
  3931. (setq address (or (cadr address) ""))
  3932. (when
  3933. (or (string= "" address)
  3934. (not
  3935. (or
  3936. (not (string-match "@" address))
  3937. (string-match
  3938. (concat ".@.*\\("
  3939. message-valid-fqdn-regexp "\\)\\'") address)))
  3940. (and message-bogus-addresses
  3941. (let ((re
  3942. (if (listp message-bogus-addresses)
  3943. (mapconcat 'identity
  3944. message-bogus-addresses
  3945. "\\|")
  3946. message-bogus-addresses)))
  3947. (string-match re address))))
  3948. (push address found)))
  3949. ;;
  3950. (mail-extract-address-components recipients t))
  3951. found))
  3952. (defun message-check-recipients ()
  3953. "Warn before composing or sending a mail to an invalid address.
  3954. This function could be useful in `message-setup-hook'."
  3955. (interactive)
  3956. (save-restriction
  3957. (message-narrow-to-headers)
  3958. (dolist (hdr '("To" "Cc" "Bcc"))
  3959. (let ((addr (message-fetch-field hdr)))
  3960. (when (stringp addr)
  3961. (dolist (bog (message-bogus-recipient-p addr))
  3962. (and bog
  3963. (not (y-or-n-p
  3964. (format
  3965. "Address `%s'%s might be bogus. Continue? "
  3966. bog
  3967. ;; If the encoded version of the email address
  3968. ;; is different from the unencoded version,
  3969. ;; then we likely have invisible characters or
  3970. ;; the like. Display the encoded version,
  3971. ;; too.
  3972. (let ((encoded (rfc2047-encode-string bog)))
  3973. (if (string= encoded bog)
  3974. ""
  3975. (format " (%s)" encoded))))))
  3976. (error "Bogus address"))))))))
  3977. (custom-add-option 'message-setup-hook 'message-check-recipients)
  3978. (defun message-add-action (action &rest types)
  3979. "Add ACTION to be performed when doing an exit of type TYPES."
  3980. (while types
  3981. (add-to-list (intern (format "message-%s-actions" (pop types)))
  3982. action)))
  3983. (defun message-delete-action (action &rest types)
  3984. "Delete ACTION from lists of actions performed when doing an exit of type TYPES."
  3985. (let (var)
  3986. (while types
  3987. (set (setq var (intern (format "message-%s-actions" (pop types))))
  3988. (delq action (symbol-value var))))))
  3989. (defun message-do-actions (actions)
  3990. "Perform all actions in ACTIONS."
  3991. ;; Now perform actions on successful sending.
  3992. (dolist (action actions)
  3993. (ignore-errors
  3994. (cond
  3995. ;; A simple function.
  3996. ((functionp action)
  3997. (funcall action))
  3998. ;; Something to be evalled.
  3999. (t
  4000. (eval action))))))
  4001. (defun message-send-mail-partially ()
  4002. "Send mail as message/partial."
  4003. ;; replace the header delimiter with a blank line
  4004. (goto-char (point-min))
  4005. (re-search-forward
  4006. (concat "^" (regexp-quote mail-header-separator) "\n"))
  4007. (replace-match "\n")
  4008. (run-hooks 'message-send-mail-hook)
  4009. (let ((p (goto-char (point-min)))
  4010. (tembuf (message-generate-new-buffer-clone-locals " message temp"))
  4011. (curbuf (current-buffer))
  4012. (id (message-make-message-id)) (n 1)
  4013. plist total header)
  4014. (while (not (eobp))
  4015. (if (< (point-max) (+ p message-send-mail-partially-limit))
  4016. (goto-char (point-max))
  4017. (goto-char (+ p message-send-mail-partially-limit))
  4018. (beginning-of-line)
  4019. (if (<= (point) p) (forward-line 1))) ;; In case of bad message.
  4020. (push p plist)
  4021. (setq p (point)))
  4022. (setq total (length plist))
  4023. (push (point-max) plist)
  4024. (setq plist (nreverse plist))
  4025. (unwind-protect
  4026. (save-excursion
  4027. (setq p (pop plist))
  4028. (while plist
  4029. (set-buffer curbuf)
  4030. (copy-to-buffer tembuf p (car plist))
  4031. (set-buffer tembuf)
  4032. (goto-char (point-min))
  4033. (if header
  4034. (progn
  4035. (goto-char (point-min))
  4036. (narrow-to-region (point) (point))
  4037. (insert header))
  4038. (message-goto-eoh)
  4039. (setq header (buffer-substring (point-min) (point)))
  4040. (goto-char (point-min))
  4041. (narrow-to-region (point) (point))
  4042. (insert header)
  4043. (message-remove-header "Mime-Version")
  4044. (message-remove-header "Content-Type")
  4045. (message-remove-header "Content-Transfer-Encoding")
  4046. (message-remove-header "Message-ID")
  4047. (message-remove-header "Lines")
  4048. (goto-char (point-max))
  4049. (insert "Mime-Version: 1.0\n")
  4050. (setq header (buffer-string)))
  4051. (goto-char (point-max))
  4052. (insert (format "Content-Type: message/partial; id=\"%s\"; number=%d; total=%d\n\n"
  4053. id n total))
  4054. (forward-char -1)
  4055. (let ((mail-header-separator ""))
  4056. (when (memq 'Message-ID message-required-mail-headers)
  4057. (insert "Message-ID: " (message-make-message-id) "\n"))
  4058. (when (memq 'Lines message-required-mail-headers)
  4059. (insert "Lines: " (message-make-lines) "\n"))
  4060. (message-goto-subject)
  4061. (end-of-line)
  4062. (insert (format " (%d/%d)" n total))
  4063. (widen)
  4064. (funcall (or message-send-mail-real-function
  4065. message-send-mail-function)))
  4066. (setq n (+ n 1))
  4067. (setq p (pop plist))
  4068. (erase-buffer)))
  4069. (kill-buffer tembuf))))
  4070. (declare-function hashcash-wait-async "hashcash" (&optional buffer))
  4071. (defun message-send-mail (&optional arg)
  4072. (require 'mail-utils)
  4073. (let* ((tembuf (message-generate-new-buffer-clone-locals " message temp"))
  4074. (case-fold-search nil)
  4075. (news (message-news-p))
  4076. (mailbuf (current-buffer))
  4077. (message-this-is-mail t)
  4078. ;; gnus-setup-posting-charset is autoloaded in mml.el (FIXME
  4079. ;; maybe it should not be), which this file requires. Hence
  4080. ;; the fboundp test is always true. Loading it from gnus-msg
  4081. ;; loads many Gnus files (Bug#5642). If
  4082. ;; gnus-group-posting-charset-alist hasn't been customized,
  4083. ;; this is just going to return nil anyway. FIXME it would
  4084. ;; be good to improve this further, because even if g-g-p-c-a
  4085. ;; has been customized, that is likely to just be for news.
  4086. ;; Eg either move the definition from gnus-msg, or separate out
  4087. ;; the mail and news parts.
  4088. (message-posting-charset
  4089. (if (and (fboundp 'gnus-setup-posting-charset)
  4090. (boundp 'gnus-group-posting-charset-alist))
  4091. (gnus-setup-posting-charset nil)
  4092. message-posting-charset))
  4093. (headers message-required-mail-headers)
  4094. options)
  4095. (when (and message-generate-hashcash
  4096. (not (eq message-generate-hashcash 'opportunistic)))
  4097. (message "Generating hashcash...")
  4098. (require 'hashcash)
  4099. ;; Wait for calculations already started to finish...
  4100. (hashcash-wait-async)
  4101. ;; ...and do calculations not already done. mail-add-payment
  4102. ;; will leave existing X-Hashcash headers alone.
  4103. (mail-add-payment)
  4104. (message "Generating hashcash...done"))
  4105. (save-restriction
  4106. (message-narrow-to-headers)
  4107. ;; Generate the Mail-Followup-To header if the header is not there...
  4108. (if (and (message-subscribed-p)
  4109. (not (mail-fetch-field "mail-followup-to")))
  4110. (setq headers
  4111. (cons
  4112. (cons "Mail-Followup-To" (message-make-mail-followup-to))
  4113. message-required-mail-headers))
  4114. ;; otherwise, delete the MFT header if the field is empty
  4115. (when (equal "" (mail-fetch-field "mail-followup-to"))
  4116. (message-remove-header "^Mail-Followup-To:")))
  4117. ;; Insert some headers.
  4118. (let ((message-deletable-headers
  4119. (if news nil message-deletable-headers)))
  4120. (message-generate-headers headers))
  4121. ;; Check continuation headers.
  4122. (message-check 'continuation-headers
  4123. (goto-char (point-min))
  4124. (while (re-search-forward "^[^ \t\n][^ \t\n:]*[ \t\n]" nil t)
  4125. (goto-char (match-beginning 0))
  4126. (if (y-or-n-p "Fix continuation lines? ")
  4127. (insert " ")
  4128. (forward-line 1)
  4129. (unless (y-or-n-p "Send anyway? ")
  4130. (error "Failed to send the message")))))
  4131. ;; Let the user do all of the above.
  4132. (run-hooks 'message-header-hook))
  4133. (setq options message-options)
  4134. (unwind-protect
  4135. (with-current-buffer tembuf
  4136. (erase-buffer)
  4137. (setq message-options options)
  4138. ;; Avoid copying text props (except hard newlines).
  4139. (insert (with-current-buffer mailbuf
  4140. (mml-buffer-substring-no-properties-except-hard-newlines
  4141. (point-min) (point-max))))
  4142. ;; Remove some headers.
  4143. (message-encode-message-body)
  4144. (save-restriction
  4145. (message-narrow-to-headers)
  4146. ;; We (re)generate the Lines header.
  4147. (when (memq 'Lines message-required-mail-headers)
  4148. (message-generate-headers '(Lines)))
  4149. ;; Remove some headers.
  4150. (message-remove-header message-ignored-mail-headers t)
  4151. (let ((mail-parse-charset message-default-charset))
  4152. (mail-encode-encoded-word-buffer)))
  4153. (goto-char (point-max))
  4154. ;; require one newline at the end.
  4155. (or (= (preceding-char) ?\n)
  4156. (insert ?\n))
  4157. (message-cleanup-headers)
  4158. ;; FIXME: we're inserting the courtesy copy after encoding.
  4159. ;; This is wrong if the courtesy copy string contains
  4160. ;; non-ASCII characters. -- jh
  4161. (when
  4162. (save-restriction
  4163. (message-narrow-to-headers)
  4164. (and news
  4165. (not (message-fetch-field "List-Post"))
  4166. (not (message-fetch-field "List-ID"))
  4167. (or (message-fetch-field "cc")
  4168. (message-fetch-field "bcc")
  4169. (message-fetch-field "to"))
  4170. (let ((content-type (message-fetch-field
  4171. "content-type")))
  4172. (and
  4173. (or
  4174. (not content-type)
  4175. (string= "text/plain"
  4176. (car
  4177. (mail-header-parse-content-type
  4178. content-type))))
  4179. (not
  4180. (string= "base64"
  4181. (message-fetch-field
  4182. "content-transfer-encoding")))))))
  4183. (message-insert-courtesy-copy
  4184. (with-current-buffer mailbuf
  4185. message-courtesy-message)))
  4186. ;; Let's make sure we encoded all the body.
  4187. (assert (save-excursion
  4188. (goto-char (point-min))
  4189. (not (re-search-forward "[^\000-\377]" nil t))))
  4190. (mm-disable-multibyte)
  4191. (if (or (not message-send-mail-partially-limit)
  4192. (< (buffer-size) message-send-mail-partially-limit)
  4193. (not (message-y-or-n-p
  4194. "The message size is too large, split? "
  4195. t
  4196. "\
  4197. The message size, "
  4198. (/ (buffer-size) 1000) "KB, is too large.
  4199. Some mail gateways (MTA's) bounce large messages. To avoid the
  4200. problem, answer `y', and the message will be split into several
  4201. smaller pieces, the size of each is about "
  4202. (/ message-send-mail-partially-limit 1000)
  4203. "KB except the last
  4204. one.
  4205. However, some mail readers (MUA's) can't read split messages, i.e.,
  4206. mails in message/partially format. Answer `n', and the message will be
  4207. sent in one piece.
  4208. The size limit is controlled by `message-send-mail-partially-limit'.
  4209. If you always want Gnus to send messages in one piece, set
  4210. `message-send-mail-partially-limit' to nil.
  4211. ")))
  4212. (progn
  4213. (message "Sending via mail...")
  4214. (funcall (or message-send-mail-real-function
  4215. message-send-mail-function)))
  4216. (message-send-mail-partially))
  4217. (setq options message-options))
  4218. (kill-buffer tembuf))
  4219. (set-buffer mailbuf)
  4220. (setq message-options options)
  4221. (push 'mail message-sent-message-via)))
  4222. (defvar sendmail-program)
  4223. (defun message-send-mail-with-sendmail ()
  4224. "Send off the prepared buffer with sendmail."
  4225. (require 'sendmail)
  4226. (let ((errbuf (if message-interactive
  4227. (message-generate-new-buffer-clone-locals
  4228. " sendmail errors")
  4229. 0))
  4230. resend-to-addresses delimline)
  4231. (unwind-protect
  4232. (progn
  4233. (let ((case-fold-search t))
  4234. (save-restriction
  4235. (message-narrow-to-headers)
  4236. (setq resend-to-addresses (message-fetch-field "resent-to")))
  4237. ;; Change header-delimiter to be what sendmail expects.
  4238. (goto-char (point-min))
  4239. (re-search-forward
  4240. (concat "^" (regexp-quote mail-header-separator) "\n"))
  4241. (replace-match "\n")
  4242. (backward-char 1)
  4243. (setq delimline (point-marker))
  4244. (run-hooks 'message-send-mail-hook)
  4245. ;; Insert an extra newline if we need it to work around
  4246. ;; Sun's bug that swallows newlines.
  4247. (goto-char (1+ delimline))
  4248. (when (eval message-mailer-swallows-blank-line)
  4249. (newline))
  4250. (when message-interactive
  4251. (with-current-buffer errbuf
  4252. (erase-buffer))))
  4253. (let* ((default-directory "/")
  4254. (coding-system-for-write message-send-coding-system)
  4255. (cpr (apply
  4256. 'call-process-region
  4257. (append
  4258. (list (point-min) (point-max) sendmail-program
  4259. nil errbuf nil "-oi")
  4260. message-sendmail-extra-arguments
  4261. ;; Always specify who from,
  4262. ;; since some systems have broken sendmails.
  4263. ;; But some systems are more broken with -f, so
  4264. ;; we'll let users override this.
  4265. (and (null message-sendmail-f-is-evil)
  4266. (list "-f" (message-sendmail-envelope-from)))
  4267. ;; These mean "report errors by mail"
  4268. ;; and "deliver in background".
  4269. (if (null message-interactive) '("-oem" "-odb"))
  4270. ;; Get the addresses from the message
  4271. ;; unless this is a resend.
  4272. ;; We must not do that for a resend
  4273. ;; because we would find the original addresses.
  4274. ;; For a resend, include the specific addresses.
  4275. (if resend-to-addresses
  4276. (list resend-to-addresses)
  4277. '("-t"))))))
  4278. (unless (or (null cpr) (and (numberp cpr) (zerop cpr)))
  4279. (if errbuf (pop-to-buffer errbuf))
  4280. (error "Sending...failed with exit value %d" cpr)))
  4281. (when message-interactive
  4282. (with-current-buffer errbuf
  4283. (goto-char (point-min))
  4284. (while (re-search-forward "\n+ *" nil t)
  4285. (replace-match "; "))
  4286. (if (not (zerop (buffer-size)))
  4287. (error "Sending...failed to %s"
  4288. (buffer-string))))))
  4289. (when (bufferp errbuf)
  4290. (kill-buffer errbuf)))))
  4291. (defun message-send-mail-with-qmail ()
  4292. "Pass the prepared message buffer to qmail-inject.
  4293. Refer to the documentation for the variable `message-send-mail-function'
  4294. to find out how to use this."
  4295. ;; replace the header delimiter with a blank line
  4296. (goto-char (point-min))
  4297. (re-search-forward
  4298. (concat "^" (regexp-quote mail-header-separator) "\n"))
  4299. (replace-match "\n")
  4300. (run-hooks 'message-send-mail-hook)
  4301. ;; send the message
  4302. (case
  4303. (let ((coding-system-for-write message-send-coding-system))
  4304. (apply
  4305. 'call-process-region (point-min) (point-max)
  4306. message-qmail-inject-program nil nil nil
  4307. ;; qmail-inject's default behavior is to look for addresses on the
  4308. ;; command line; if there're none, it scans the headers.
  4309. ;; yes, it does The Right Thing w.r.t. Resent-To and it's kin.
  4310. ;;
  4311. ;; in general, ALL of qmail-inject's defaults are perfect for simply
  4312. ;; reading a formatted (i. e., at least a To: or Resent-To header)
  4313. ;; message from stdin.
  4314. ;;
  4315. ;; qmail also has the advantage of not having been raped by
  4316. ;; various vendors, so we don't have to allow for that, either --
  4317. ;; compare this with message-send-mail-with-sendmail and weep
  4318. ;; for sendmail's lost innocence.
  4319. ;;
  4320. ;; all this is way cool coz it lets us keep the arguments entirely
  4321. ;; free for -inject-arguments -- a big win for the user and for us
  4322. ;; since we don't have to play that double-guessing game and the user
  4323. ;; gets full control (no gestapo'ish -f's, for instance). --sj
  4324. (if (functionp message-qmail-inject-args)
  4325. (funcall message-qmail-inject-args)
  4326. message-qmail-inject-args)))
  4327. ;; qmail-inject doesn't say anything on it's stdout/stderr,
  4328. ;; we have to look at the retval instead
  4329. (0 nil)
  4330. (100 (error "qmail-inject reported permanent failure"))
  4331. (111 (error "qmail-inject reported transient failure"))
  4332. ;; should never happen
  4333. (t (error "qmail-inject reported unknown failure"))))
  4334. (defvar mh-previous-window-config)
  4335. (defun message-send-mail-with-mh ()
  4336. "Send the prepared message buffer with mh."
  4337. (let ((mh-previous-window-config nil)
  4338. (name (mh-new-draft-name)))
  4339. (setq buffer-file-name name)
  4340. ;; MH wants to generate these headers itself.
  4341. (when message-mh-deletable-headers
  4342. (let ((headers message-mh-deletable-headers))
  4343. (while headers
  4344. (goto-char (point-min))
  4345. (and (re-search-forward
  4346. (concat "^" (symbol-name (car headers)) ": *") nil t)
  4347. (message-delete-line))
  4348. (pop headers))))
  4349. (run-hooks 'message-send-mail-hook)
  4350. ;; Pass it on to mh.
  4351. (mh-send-letter)))
  4352. (defun message-smtpmail-send-it ()
  4353. "Send the prepared message buffer with `smtpmail-send-it'.
  4354. The only difference from `smtpmail-send-it' is that this command
  4355. evaluates `message-send-mail-hook' just before sending a message.
  4356. It is useful if your ISP requires the POP-before-SMTP
  4357. authentication. See the Gnus manual for details."
  4358. (run-hooks 'message-send-mail-hook)
  4359. (smtpmail-send-it))
  4360. (defun message-send-mail-with-mailclient ()
  4361. "Send the prepared message buffer with `mailclient-send-it'.
  4362. The only difference from `mailclient-send-it' is that this
  4363. command evaluates `message-send-mail-hook' just before sending a message."
  4364. (run-hooks 'message-send-mail-hook)
  4365. (mailclient-send-it))
  4366. (defun message-canlock-generate ()
  4367. "Return a string that is non-trivial to guess.
  4368. Do not use this for anything important, it is cryptographically weak."
  4369. (require 'sha1)
  4370. (let (sha1-maximum-internal-length)
  4371. (sha1 (concat (message-unique-id)
  4372. (format "%x%x%x" (random)
  4373. (progn (random t) (random))
  4374. (random))
  4375. (prin1-to-string (recent-keys))
  4376. (prin1-to-string (garbage-collect))))))
  4377. (defvar canlock-password)
  4378. (defvar canlock-password-for-verify)
  4379. (defun message-canlock-password ()
  4380. "The password used by message for cancel locks.
  4381. This is the value of `canlock-password', if that option is non-nil.
  4382. Otherwise, generate and save a value for `canlock-password' first."
  4383. (require 'canlock)
  4384. (unless canlock-password
  4385. (customize-save-variable 'canlock-password (message-canlock-generate))
  4386. (setq canlock-password-for-verify canlock-password))
  4387. canlock-password)
  4388. (defun message-insert-canlock ()
  4389. (when message-insert-canlock
  4390. (message-canlock-password)
  4391. (canlock-insert-header)))
  4392. (autoload 'nnheader-get-report "nnheader")
  4393. (declare-function gnus-setup-posting-charset "gnus-msg" (group))
  4394. (defun message-send-news (&optional arg)
  4395. (require 'gnus-msg)
  4396. (let* ((tembuf (message-generate-new-buffer-clone-locals " *message temp*"))
  4397. (case-fold-search nil)
  4398. (method (if (functionp message-post-method)
  4399. (funcall message-post-method arg)
  4400. message-post-method))
  4401. (newsgroups-field (save-restriction
  4402. (message-narrow-to-headers-or-head)
  4403. (message-fetch-field "Newsgroups")))
  4404. (followup-field (save-restriction
  4405. (message-narrow-to-headers-or-head)
  4406. (message-fetch-field "Followup-To")))
  4407. ;; BUG: We really need to get the charset for each name in the
  4408. ;; Newsgroups and Followup-To lines to allow crossposting
  4409. ;; between group names with incompatible character sets.
  4410. ;; -- Per Abrahamsen <abraham@dina.kvl.dk> 2001-10-08.
  4411. (group-field-charset
  4412. (gnus-group-name-charset method newsgroups-field))
  4413. (followup-field-charset
  4414. (gnus-group-name-charset method (or followup-field "")))
  4415. (rfc2047-header-encoding-alist
  4416. (append (when group-field-charset
  4417. (list (cons "Newsgroups" group-field-charset)))
  4418. (when followup-field-charset
  4419. (list (cons "Followup-To" followup-field-charset)))
  4420. rfc2047-header-encoding-alist))
  4421. (messbuf (current-buffer))
  4422. (message-syntax-checks
  4423. (if (and arg
  4424. (listp message-syntax-checks))
  4425. (cons '(existing-newsgroups . disabled)
  4426. message-syntax-checks)
  4427. message-syntax-checks))
  4428. (message-this-is-news t)
  4429. (message-posting-charset
  4430. (gnus-setup-posting-charset newsgroups-field))
  4431. result)
  4432. (if (not (message-check-news-body-syntax))
  4433. nil
  4434. (save-restriction
  4435. (message-narrow-to-headers)
  4436. ;; Insert some headers.
  4437. (message-generate-headers message-required-news-headers)
  4438. (message-insert-canlock)
  4439. ;; Let the user do all of the above.
  4440. (run-hooks 'message-header-hook))
  4441. ;; Note: This check will be disabled by the ".*" default value for
  4442. ;; gnus-group-name-charset-group-alist. -- Pa 2001-10-07.
  4443. (when (and group-field-charset
  4444. (listp message-syntax-checks))
  4445. (setq message-syntax-checks
  4446. (cons '(valid-newsgroups . disabled)
  4447. message-syntax-checks)))
  4448. (message-cleanup-headers)
  4449. (if (not (let ((message-post-method method))
  4450. (message-check-news-syntax)))
  4451. nil
  4452. (unwind-protect
  4453. (with-current-buffer tembuf
  4454. (buffer-disable-undo)
  4455. (erase-buffer)
  4456. ;; Avoid copying text props (except hard newlines).
  4457. (insert
  4458. (with-current-buffer messbuf
  4459. (mml-buffer-substring-no-properties-except-hard-newlines
  4460. (point-min) (point-max))))
  4461. (message-encode-message-body)
  4462. ;; Remove some headers.
  4463. (save-restriction
  4464. (message-narrow-to-headers)
  4465. ;; We (re)generate the Lines header.
  4466. (when (memq 'Lines message-required-mail-headers)
  4467. (message-generate-headers '(Lines)))
  4468. ;; Remove some headers.
  4469. (message-remove-header message-ignored-news-headers t)
  4470. (let ((mail-parse-charset message-default-charset))
  4471. (mail-encode-encoded-word-buffer)))
  4472. (goto-char (point-max))
  4473. ;; require one newline at the end.
  4474. (or (= (preceding-char) ?\n)
  4475. (insert ?\n))
  4476. (let ((case-fold-search t))
  4477. ;; Remove the delimiter.
  4478. (goto-char (point-min))
  4479. (re-search-forward
  4480. (concat "^" (regexp-quote mail-header-separator) "\n"))
  4481. (replace-match "\n")
  4482. (backward-char 1))
  4483. (run-hooks 'message-send-news-hook)
  4484. (gnus-open-server method)
  4485. (message "Sending news via %s..." (gnus-server-string method))
  4486. (setq result (let ((mail-header-separator ""))
  4487. (gnus-request-post method))))
  4488. (kill-buffer tembuf))
  4489. (set-buffer messbuf)
  4490. (if result
  4491. (push 'news message-sent-message-via)
  4492. (message "Couldn't send message via news: %s"
  4493. (nnheader-get-report (car method)))
  4494. nil)))))
  4495. ;;;
  4496. ;;; Header generation & syntax checking.
  4497. ;;;
  4498. (defun message-check-element (type)
  4499. "Return non-nil if this TYPE is not to be checked."
  4500. (if (eq message-syntax-checks 'dont-check-for-anything-just-trust-me)
  4501. t
  4502. (let ((able (assq type message-syntax-checks)))
  4503. (and (consp able)
  4504. (eq (cdr able) 'disabled)))))
  4505. (defun message-check-news-syntax ()
  4506. "Check the syntax of the message."
  4507. (save-excursion
  4508. (save-restriction
  4509. (widen)
  4510. ;; We narrow to the headers and check them first.
  4511. (save-excursion
  4512. (save-restriction
  4513. (message-narrow-to-headers)
  4514. (message-check-news-header-syntax))))))
  4515. (defun message-check-news-header-syntax ()
  4516. (and
  4517. ;; Check Newsgroups header.
  4518. (message-check 'newsgroups
  4519. (let ((group (message-fetch-field "newsgroups")))
  4520. (or
  4521. (and group
  4522. (not (string-match "\\`[ \t]*\\'" group)))
  4523. (ignore
  4524. (message
  4525. "The newsgroups field is empty or missing. Posting is denied.")))))
  4526. ;; Check the Subject header.
  4527. (message-check 'subject
  4528. (let* ((case-fold-search t)
  4529. (subject (message-fetch-field "subject")))
  4530. (or
  4531. (and subject
  4532. (not (string-match "\\`[ \t]*\\'" subject)))
  4533. (ignore
  4534. (message
  4535. "The subject field is empty or missing. Posting is denied.")))))
  4536. ;; Check for commands in Subject.
  4537. (message-check 'subject-cmsg
  4538. (if (string-match "^cmsg " (message-fetch-field "subject"))
  4539. (y-or-n-p
  4540. "The control code \"cmsg\" is in the subject. Really post? ")
  4541. t))
  4542. ;; Check long header lines.
  4543. (message-check 'long-header-lines
  4544. (let ((header nil)
  4545. (length 0)
  4546. found)
  4547. (while (and (not found)
  4548. (re-search-forward "^\\([^ \t:]+\\): " nil t))
  4549. (if (> (- (point) (match-beginning 0)) 998)
  4550. (setq found t
  4551. length (- (point) (match-beginning 0)))
  4552. (setq header (match-string-no-properties 1)))
  4553. (forward-line 1))
  4554. (if found
  4555. (y-or-n-p (format "Your %s header is too long (%d). Really post? "
  4556. header length))
  4557. t)))
  4558. ;; Check for multiple identical headers.
  4559. (message-check 'multiple-headers
  4560. (let (found)
  4561. (while (and (not found)
  4562. (re-search-forward "^[^ \t:]+: " nil t))
  4563. (save-excursion
  4564. (or (re-search-forward
  4565. (concat "^"
  4566. (regexp-quote
  4567. (setq found
  4568. (buffer-substring
  4569. (match-beginning 0) (- (match-end 0) 2))))
  4570. ":")
  4571. nil t)
  4572. (setq found nil))))
  4573. (if found
  4574. (y-or-n-p (format "Multiple %s headers. Really post? " found))
  4575. t)))
  4576. ;; Check for Version and Sendsys.
  4577. (message-check 'sendsys
  4578. (if (re-search-forward "^Sendsys:\\|^Version:" nil t)
  4579. (y-or-n-p
  4580. (format "The article contains a %s command. Really post? "
  4581. (buffer-substring (match-beginning 0)
  4582. (1- (match-end 0)))))
  4583. t))
  4584. ;; See whether we can shorten Followup-To.
  4585. (message-check 'shorten-followup-to
  4586. (let ((newsgroups (message-fetch-field "newsgroups"))
  4587. (followup-to (message-fetch-field "followup-to"))
  4588. to)
  4589. (when (and newsgroups
  4590. (string-match "," newsgroups)
  4591. (not followup-to)
  4592. (not
  4593. (zerop
  4594. (length
  4595. (setq to (completing-read
  4596. "Followups to (default no Followup-To header): "
  4597. (mapcar #'list
  4598. (cons "poster"
  4599. (message-tokenize-header
  4600. newsgroups)))))))))
  4601. (goto-char (point-min))
  4602. (insert "Followup-To: " to "\n"))
  4603. t))
  4604. ;; Check "Shoot me".
  4605. (message-check 'shoot
  4606. (if (re-search-forward
  4607. "Message-ID.*.i-did-not-set--mail-host-address--so-tickle-me" nil t)
  4608. (y-or-n-p "You appear to have a misconfigured system. Really post? ")
  4609. t))
  4610. ;; Check for Approved.
  4611. (message-check 'approved
  4612. (if (re-search-forward "^Approved:" nil t)
  4613. (y-or-n-p "The article contains an Approved header. Really post? ")
  4614. t))
  4615. ;; Check the Message-ID header.
  4616. (message-check 'message-id
  4617. (let* ((case-fold-search t)
  4618. (message-id (message-fetch-field "message-id" t)))
  4619. (or (not message-id)
  4620. ;; Is there an @ in the ID?
  4621. (and (string-match "@" message-id)
  4622. ;; Is there a dot in the ID?
  4623. (string-match "@[^.]*\\." message-id)
  4624. ;; Does the ID end with a dot?
  4625. (not (string-match "\\.>" message-id)))
  4626. (y-or-n-p
  4627. (format "The Message-ID looks strange: \"%s\". Really post? "
  4628. message-id)))))
  4629. ;; Check the Newsgroups & Followup-To headers.
  4630. (message-check 'existing-newsgroups
  4631. (let* ((case-fold-search t)
  4632. (newsgroups (message-fetch-field "newsgroups"))
  4633. (followup-to (message-fetch-field "followup-to"))
  4634. (groups (message-tokenize-header
  4635. (if followup-to
  4636. (concat newsgroups "," followup-to)
  4637. newsgroups)))
  4638. (post-method (if (functionp message-post-method)
  4639. (funcall message-post-method)
  4640. message-post-method))
  4641. ;; KLUDGE to handle nnvirtual groups. Doing this right
  4642. ;; would probably involve a new nnoo function.
  4643. ;; -- Per Abrahamsen <abraham@dina.kvl.dk>, 2001-10-17.
  4644. (method (if (and (consp post-method)
  4645. (eq (car post-method) 'nnvirtual)
  4646. gnus-message-group-art)
  4647. (let ((group (car (nnvirtual-find-group-art
  4648. (car gnus-message-group-art)
  4649. (cdr gnus-message-group-art)))))
  4650. (gnus-find-method-for-group group))
  4651. post-method))
  4652. (known-groups
  4653. (mapcar (lambda (n)
  4654. (gnus-group-name-decode
  4655. (gnus-group-real-name n)
  4656. (gnus-group-name-charset method n)))
  4657. (gnus-groups-from-server method)))
  4658. errors)
  4659. (while groups
  4660. (when (and (not (equal (car groups) "poster"))
  4661. (not (member (car groups) known-groups))
  4662. (not (member (car groups) errors)))
  4663. (push (car groups) errors))
  4664. (pop groups))
  4665. (cond
  4666. ;; Gnus is not running.
  4667. ((or (not (and (boundp 'gnus-active-hashtb)
  4668. gnus-active-hashtb))
  4669. (not (boundp 'gnus-read-active-file)))
  4670. t)
  4671. ;; We don't have all the group names.
  4672. ((and (or (not gnus-read-active-file)
  4673. (eq gnus-read-active-file 'some))
  4674. errors)
  4675. (y-or-n-p
  4676. (format
  4677. "Really use %s possibly unknown group%s: %s? "
  4678. (if (= (length errors) 1) "this" "these")
  4679. (if (= (length errors) 1) "" "s")
  4680. (mapconcat 'identity errors ", "))))
  4681. ;; There were no errors.
  4682. ((not errors)
  4683. t)
  4684. ;; There are unknown groups.
  4685. (t
  4686. (y-or-n-p
  4687. (format
  4688. "Really post to %s unknown group%s: %s? "
  4689. (if (= (length errors) 1) "this" "these")
  4690. (if (= (length errors) 1) "" "s")
  4691. (mapconcat 'identity errors ", ")))))))
  4692. ;; Check continuation headers.
  4693. (message-check 'continuation-headers
  4694. (goto-char (point-min))
  4695. (let ((do-posting t))
  4696. (while (re-search-forward "^[^ \t\n][^ \t\n:]*[ \t\n]" nil t)
  4697. (goto-char (match-beginning 0))
  4698. (if (y-or-n-p "Fix continuation lines? ")
  4699. (insert " ")
  4700. (forward-line 1)
  4701. (unless (y-or-n-p "Send anyway? ")
  4702. (setq do-posting nil))))
  4703. do-posting))
  4704. ;; Check the Newsgroups & Followup-To headers for syntax errors.
  4705. (message-check 'valid-newsgroups
  4706. (let ((case-fold-search t)
  4707. (headers '("Newsgroups" "Followup-To"))
  4708. header error)
  4709. (while (and headers (not error))
  4710. (when (setq header (mail-fetch-field (car headers)))
  4711. (if (or
  4712. (not
  4713. (string-match
  4714. "\\`\\([-+_&.a-zA-Z0-9]+\\)?\\(,[-+_&.a-zA-Z0-9]+\\)*\\'"
  4715. header))
  4716. (memq
  4717. nil (mapcar
  4718. (lambda (g)
  4719. (not (string-match "\\.\\'\\|\\.\\." g)))
  4720. (message-tokenize-header header ","))))
  4721. (setq error t)))
  4722. (unless error
  4723. (pop headers)))
  4724. (if (not error)
  4725. t
  4726. (y-or-n-p
  4727. (format "The %s header looks odd: \"%s\". Really post? "
  4728. (car headers) header)))))
  4729. (message-check 'repeated-newsgroups
  4730. (let ((case-fold-search t)
  4731. (headers '("Newsgroups" "Followup-To"))
  4732. header error groups group)
  4733. (while (and headers
  4734. (not error))
  4735. (when (setq header (mail-fetch-field (pop headers)))
  4736. (setq groups (message-tokenize-header header ","))
  4737. (while (setq group (pop groups))
  4738. (when (member group groups)
  4739. (setq error group
  4740. groups nil)))))
  4741. (if (not error)
  4742. t
  4743. (y-or-n-p
  4744. (format "Group %s is repeated in headers. Really post? " error)))))
  4745. ;; Check the From header.
  4746. (message-check 'from
  4747. (let* ((case-fold-search t)
  4748. (from (message-fetch-field "from"))
  4749. ad)
  4750. (cond
  4751. ((not from)
  4752. (message "There is no From line. Posting is denied.")
  4753. nil)
  4754. ((or (not (string-match
  4755. "@[^\\.]*\\."
  4756. (setq ad (nth 1 (mail-extract-address-components
  4757. from))))) ;larsi@ifi
  4758. (string-match "\\.\\." ad) ;larsi@ifi..uio
  4759. (string-match "@\\." ad) ;larsi@.ifi.uio
  4760. (string-match "\\.$" ad) ;larsi@ifi.uio.
  4761. (not (string-match "^[^@]+@[^@]+$" ad)) ;larsi.ifi.uio
  4762. (string-match "(.*).*(.*)" from)) ;(lars) (lars)
  4763. (message
  4764. "Denied posting -- the From looks strange: \"%s\"." from)
  4765. nil)
  4766. ((let ((addresses (rfc822-addresses from)))
  4767. ;; `rfc822-addresses' returns a string if parsing fails.
  4768. (while (and (consp addresses)
  4769. (not (eq (string-to-char (car addresses)) ?\()))
  4770. (setq addresses (cdr addresses)))
  4771. addresses)
  4772. (message
  4773. "Denied posting -- bad From address: \"%s\"." from)
  4774. nil)
  4775. (t t))))
  4776. ;; Check the Reply-To header.
  4777. (message-check 'reply-to
  4778. (let* ((case-fold-search t)
  4779. (reply-to (message-fetch-field "reply-to"))
  4780. ad)
  4781. (cond
  4782. ((not reply-to)
  4783. t)
  4784. ((string-match "," reply-to)
  4785. (y-or-n-p
  4786. (format "Multiple Reply-To addresses: \"%s\". Really post? "
  4787. reply-to)))
  4788. ((or (not (string-match
  4789. "@[^\\.]*\\."
  4790. (setq ad (nth 1 (mail-extract-address-components
  4791. reply-to))))) ;larsi@ifi
  4792. (string-match "\\.\\." ad) ;larsi@ifi..uio
  4793. (string-match "@\\." ad) ;larsi@.ifi.uio
  4794. (string-match "\\.$" ad) ;larsi@ifi.uio.
  4795. (not (string-match "^[^@]+@[^@]+$" ad)) ;larsi.ifi.uio
  4796. (string-match "(.*).*(.*)" reply-to)) ;(lars) (lars)
  4797. (y-or-n-p
  4798. (format
  4799. "The Reply-To looks strange: \"%s\". Really post? "
  4800. reply-to)))
  4801. (t t))))))
  4802. (defun message-check-news-body-syntax ()
  4803. (and
  4804. ;; Check for long lines.
  4805. (message-check 'long-lines
  4806. (goto-char (point-min))
  4807. (re-search-forward
  4808. (concat "^" (regexp-quote mail-header-separator) "$"))
  4809. (forward-line 1)
  4810. (while (and
  4811. (or (looking-at
  4812. "<#\\(/\\)?\\(multipart\\|part\\|external\\|mml\\)")
  4813. (let ((p (point)))
  4814. (end-of-line)
  4815. (< (- (point) p) 80)))
  4816. (zerop (forward-line 1))))
  4817. (or (bolp)
  4818. (eobp)
  4819. (y-or-n-p
  4820. "You have lines longer than 79 characters. Really post? ")))
  4821. ;; Check whether the article is empty.
  4822. (message-check 'empty
  4823. (goto-char (point-min))
  4824. (re-search-forward
  4825. (concat "^" (regexp-quote mail-header-separator) "$"))
  4826. (forward-line 1)
  4827. (let ((b (point)))
  4828. (goto-char (point-max))
  4829. (re-search-backward message-signature-separator nil t)
  4830. (beginning-of-line)
  4831. (or (re-search-backward "[^ \n\t]" b t)
  4832. (if (message-gnksa-enable-p 'empty-article)
  4833. (y-or-n-p "Empty article. Really post? ")
  4834. (message "Denied posting -- Empty article.")
  4835. nil))))
  4836. ;; Check for control characters.
  4837. (message-check 'control-chars
  4838. (if (re-search-forward
  4839. (mm-string-to-multibyte "[\000-\007\013\015-\032\034-\037\200-\237]")
  4840. nil t)
  4841. (y-or-n-p
  4842. "The article contains control characters. Really post? ")
  4843. t))
  4844. ;; Check excessive size.
  4845. (message-check 'size
  4846. (if (> (buffer-size) 60000)
  4847. (y-or-n-p
  4848. (format "The article is %d octets long. Really post? "
  4849. (buffer-size)))
  4850. t))
  4851. ;; Check whether any new text has been added.
  4852. (message-check 'new-text
  4853. (or
  4854. (not message-checksum)
  4855. (not (eq (message-checksum) message-checksum))
  4856. (if (message-gnksa-enable-p 'quoted-text-only)
  4857. (y-or-n-p
  4858. "It looks like no new text has been added. Really post? ")
  4859. (message "Denied posting -- no new text has been added.")
  4860. nil)))
  4861. ;; Check the length of the signature.
  4862. (message-check 'signature
  4863. (let (sig-start sig-end)
  4864. (goto-char (point-max))
  4865. (if (not (re-search-backward message-signature-separator nil t))
  4866. t
  4867. (setq sig-start (1+ (point-at-eol)))
  4868. (setq sig-end
  4869. (if (re-search-forward
  4870. "<#/?\\(multipart\\|part\\|external\\|mml\\)" nil t)
  4871. (- (point-at-bol) 1)
  4872. (point-max)))
  4873. (if (>= (count-lines sig-start sig-end) 5)
  4874. (if (message-gnksa-enable-p 'signature)
  4875. (y-or-n-p
  4876. (format "Signature is excessively long (%d lines). Really post? "
  4877. (count-lines sig-start sig-end)))
  4878. (message "Denied posting -- Excessive signature.")
  4879. nil)
  4880. t))))
  4881. ;; Ensure that text follows last quoted portion.
  4882. (message-check 'quoting-style
  4883. (goto-char (point-max))
  4884. (let ((no-problem t))
  4885. (when (search-backward-regexp "^>[^\n]*\n" nil t)
  4886. (setq no-problem (search-forward-regexp "^[ \t]*[^>\n]" nil t)))
  4887. (if no-problem
  4888. t
  4889. (if (message-gnksa-enable-p 'quoted-text-only)
  4890. (y-or-n-p "Your text should follow quoted text. Really post? ")
  4891. ;; Ensure that
  4892. (goto-char (point-min))
  4893. (re-search-forward
  4894. (concat "^" (regexp-quote mail-header-separator) "$"))
  4895. (if (search-forward-regexp "^[ \t]*[^>\n]" nil t)
  4896. (y-or-n-p "Your text should follow quoted text. Really post? ")
  4897. (message "Denied posting -- only quoted text.")
  4898. nil)))))))
  4899. (defun message-checksum ()
  4900. "Return a \"checksum\" for the current buffer."
  4901. (let ((sum 0))
  4902. (save-excursion
  4903. (goto-char (point-min))
  4904. (re-search-forward
  4905. (concat "^" (regexp-quote mail-header-separator) "$"))
  4906. (while (not (eobp))
  4907. (when (not (looking-at "[ \t\n]"))
  4908. (setq sum (logxor (ash sum 1) (if (natnump sum) 0 1)
  4909. (char-after))))
  4910. (forward-char 1)))
  4911. sum))
  4912. (defun message-do-fcc ()
  4913. "Process Fcc headers in the current buffer."
  4914. (let ((case-fold-search t)
  4915. (buf (current-buffer))
  4916. list file
  4917. (mml-externalize-attachments message-fcc-externalize-attachments))
  4918. (save-excursion
  4919. (save-restriction
  4920. (message-narrow-to-headers)
  4921. (setq file (message-fetch-field "fcc" t)))
  4922. (when file
  4923. (set-buffer (get-buffer-create " *message temp*"))
  4924. (erase-buffer)
  4925. (insert-buffer-substring buf)
  4926. (message-encode-message-body)
  4927. (save-restriction
  4928. (message-narrow-to-headers)
  4929. (while (setq file (message-fetch-field "fcc" t))
  4930. (push file list)
  4931. (message-remove-header "fcc" nil t))
  4932. (let ((mail-parse-charset message-default-charset)
  4933. (rfc2047-header-encoding-alist
  4934. (cons '("Newsgroups" . default)
  4935. rfc2047-header-encoding-alist)))
  4936. (mail-encode-encoded-word-buffer)))
  4937. (goto-char (point-min))
  4938. (when (re-search-forward
  4939. (concat "^" (regexp-quote mail-header-separator) "$")
  4940. nil t)
  4941. (replace-match "" t t ))
  4942. ;; Process FCC operations.
  4943. (while list
  4944. (setq file (pop list))
  4945. (if (string-match "^[ \t]*|[ \t]*\\(.*\\)[ \t]*$" file)
  4946. ;; Pipe the article to the program in question.
  4947. (call-process-region (point-min) (point-max) shell-file-name
  4948. nil nil nil shell-command-switch
  4949. (match-string 1 file))
  4950. ;; Save the article.
  4951. (setq file (expand-file-name file))
  4952. (unless (file-exists-p (file-name-directory file))
  4953. (make-directory (file-name-directory file) t))
  4954. (if (and message-fcc-handler-function
  4955. (not (eq message-fcc-handler-function 'rmail-output)))
  4956. (funcall message-fcc-handler-function file)
  4957. ;; FIXME this option, rmail-output (also used if
  4958. ;; message-fcc-handler-function is nil) is not
  4959. ;; documented anywhere AFAICS. It should work in Emacs
  4960. ;; 23; I suspect it does not work in Emacs 22.
  4961. ;; FIXME I don't see the need for the two different cases here.
  4962. ;; mail-use-rfc822 makes no difference (in Emacs 23),and
  4963. ;; the third argument just controls \"Wrote file\" message.
  4964. (if (and (file-readable-p file) (mail-file-babyl-p file))
  4965. (rmail-output file 1 nil t)
  4966. (let ((mail-use-rfc822 t))
  4967. (rmail-output file 1 t t))))))
  4968. (kill-buffer (current-buffer))))))
  4969. (defun message-output (filename)
  4970. "Append this article to Unix/babyl mail file FILENAME."
  4971. (if (or (and (file-readable-p filename)
  4972. (mail-file-babyl-p filename))
  4973. ;; gnus-output-to-mail does the wrong thing with live, mbox
  4974. ;; Rmail buffers in Emacs 23.
  4975. ;; http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=597255
  4976. (let ((buff (find-buffer-visiting filename)))
  4977. (and buff (with-current-buffer buff
  4978. (eq major-mode 'rmail-mode)))))
  4979. (gnus-output-to-rmail filename t)
  4980. (gnus-output-to-mail filename t)))
  4981. (defun message-cleanup-headers ()
  4982. "Do various automatic cleanups of the headers."
  4983. ;; Remove empty lines in the header.
  4984. (save-restriction
  4985. (message-narrow-to-headers)
  4986. ;; Remove blank lines.
  4987. (while (re-search-forward "^[ \t]*\n" nil t)
  4988. (replace-match "" t t))
  4989. ;; Correct Newsgroups and Followup-To headers: Change sequence of
  4990. ;; spaces to comma and eliminate spaces around commas. Eliminate
  4991. ;; embedded line breaks.
  4992. (goto-char (point-min))
  4993. (while (re-search-forward "^\\(Newsgroups\\|Followup-To\\): +" nil t)
  4994. (save-restriction
  4995. (narrow-to-region
  4996. (point)
  4997. (if (re-search-forward "^[^ \t]" nil t)
  4998. (match-beginning 0)
  4999. (forward-line 1)
  5000. (point)))
  5001. (goto-char (point-min))
  5002. (while (re-search-forward "\n[ \t]+" nil t)
  5003. (replace-match " " t t)) ;No line breaks (too confusing)
  5004. (goto-char (point-min))
  5005. (while (re-search-forward "[ \t\n]*,[ \t\n]*\\|[ \t]+" nil t)
  5006. (replace-match "," t t))
  5007. (goto-char (point-min))
  5008. ;; Remove trailing commas.
  5009. (when (re-search-forward ",+$" nil t)
  5010. (replace-match "" t t))))))
  5011. (defun message-make-date (&optional now)
  5012. "Make a valid data header.
  5013. If NOW, use that time instead."
  5014. (let ((system-time-locale "C"))
  5015. (format-time-string "%a, %d %b %Y %T %z" now)))
  5016. (defun message-insert-expires (days)
  5017. "Insert the Expires header. Expiry in DAYS days."
  5018. (interactive "NExpire article in how many days? ")
  5019. (save-excursion
  5020. (message-position-on-field "Expires" "X-Draft-From")
  5021. (insert (message-make-expires-date days))))
  5022. (defun message-make-expires-date (days)
  5023. "Make date string for the Expires header. Expiry in DAYS days.
  5024. In posting styles use `(\"Expires\" (make-expires-date 30))'."
  5025. (let* ((cur (decode-time (current-time)))
  5026. (nday (+ days (nth 3 cur))))
  5027. (setf (nth 3 cur) nday)
  5028. (message-make-date (apply 'encode-time cur))))
  5029. (defun message-make-message-id ()
  5030. "Make a unique Message-ID."
  5031. (concat "<" (message-unique-id)
  5032. (let ((psubject (save-excursion (message-fetch-field "subject")))
  5033. (psupersedes
  5034. (save-excursion (message-fetch-field "supersedes"))))
  5035. (if (or
  5036. (and message-reply-headers
  5037. (mail-header-references message-reply-headers)
  5038. (mail-header-subject message-reply-headers)
  5039. psubject
  5040. (not (string=
  5041. (message-strip-subject-re
  5042. (mail-header-subject message-reply-headers))
  5043. (message-strip-subject-re psubject))))
  5044. (and psupersedes
  5045. (string-match "_-_@" psupersedes)))
  5046. "_-_" ""))
  5047. "@" (message-make-fqdn) ">"))
  5048. (defvar message-unique-id-char nil)
  5049. ;; If you ever change this function, make sure the new version
  5050. ;; cannot generate IDs that the old version could.
  5051. ;; You might for example insert a "." somewhere (not next to another dot
  5052. ;; or string boundary), or modify the "fsf" string.
  5053. (defun message-unique-id ()
  5054. (random t)
  5055. ;; Don't use microseconds from (current-time), they may be unsupported.
  5056. ;; Instead we use this randomly inited counter.
  5057. (setq message-unique-id-char
  5058. (% (1+ (or message-unique-id-char
  5059. (logand (random most-positive-fixnum) (1- (lsh 1 20)))))
  5060. ;; (current-time) returns 16-bit ints,
  5061. ;; and 2^16*25 just fits into 4 digits i base 36.
  5062. (* 25 25)))
  5063. (let ((tm (current-time)))
  5064. (concat
  5065. (if (or (eq system-type 'ms-dos)
  5066. ;; message-number-base36 doesn't handle bigints.
  5067. (floatp (user-uid)))
  5068. (let ((user (downcase (user-login-name))))
  5069. (while (string-match "[^a-z0-9_]" user)
  5070. (aset user (match-beginning 0) ?_))
  5071. user)
  5072. (message-number-base36 (user-uid) -1))
  5073. (message-number-base36 (+ (car tm)
  5074. (lsh (% message-unique-id-char 25) 16)) 4)
  5075. (message-number-base36 (+ (nth 1 tm)
  5076. (lsh (/ message-unique-id-char 25) 16)) 4)
  5077. ;; Append a given name, because while the generated ID is unique
  5078. ;; to this newsreader, other newsreaders might otherwise generate
  5079. ;; the same ID via another algorithm.
  5080. ".fsf")))
  5081. (defun message-number-base36 (num len)
  5082. (if (if (< len 0)
  5083. (<= num 0)
  5084. (= len 0))
  5085. ""
  5086. (concat (message-number-base36 (/ num 36) (1- len))
  5087. (char-to-string (aref "zyxwvutsrqponmlkjihgfedcba9876543210"
  5088. (% num 36))))))
  5089. (defun message-make-organization ()
  5090. "Make an Organization header."
  5091. (let* ((organization
  5092. (when message-user-organization
  5093. (if (functionp message-user-organization)
  5094. (funcall message-user-organization)
  5095. message-user-organization))))
  5096. (with-temp-buffer
  5097. (mm-enable-multibyte)
  5098. (cond ((stringp organization)
  5099. (insert organization))
  5100. ((and (eq t organization)
  5101. message-user-organization-file
  5102. (file-exists-p message-user-organization-file))
  5103. (insert-file-contents message-user-organization-file)))
  5104. (goto-char (point-min))
  5105. (while (re-search-forward "[\t\n]+" nil t)
  5106. (replace-match "" t t))
  5107. (unless (zerop (buffer-size))
  5108. (buffer-string)))))
  5109. (defun message-make-lines ()
  5110. "Count the number of lines and return numeric string."
  5111. (save-excursion
  5112. (save-restriction
  5113. (widen)
  5114. (message-goto-body)
  5115. (int-to-string (count-lines (point) (point-max))))))
  5116. (defun message-make-references ()
  5117. "Return the References header for this message."
  5118. (when message-reply-headers
  5119. (let ((message-id (mail-header-id message-reply-headers))
  5120. (references (mail-header-references message-reply-headers)))
  5121. (if (or references message-id)
  5122. (concat (or references "") (and references " ")
  5123. (or message-id ""))
  5124. nil))))
  5125. (defun message-make-in-reply-to ()
  5126. "Return the In-Reply-To header for this message."
  5127. (when message-reply-headers
  5128. (let ((from (mail-header-from message-reply-headers))
  5129. (date (mail-header-date message-reply-headers))
  5130. (msg-id (mail-header-id message-reply-headers)))
  5131. (when from
  5132. (let ((name (mail-extract-address-components from)))
  5133. (concat
  5134. msg-id (if msg-id " (")
  5135. (if (car name)
  5136. (if (string-match "[^\000-\177]" (car name))
  5137. ;; Quote a string containing non-ASCII characters.
  5138. ;; It will make the RFC2047 encoder cause an error
  5139. ;; if there are special characters.
  5140. (mm-with-multibyte-buffer
  5141. (insert (car name))
  5142. (goto-char (point-min))
  5143. (while (search-forward "\"" nil t)
  5144. (when (prog2
  5145. (backward-char)
  5146. (zerop (% (skip-chars-backward "\\\\") 2))
  5147. (goto-char (match-beginning 0)))
  5148. (insert "\\"))
  5149. (forward-char))
  5150. ;; Those quotes will be removed by the RFC2047 encoder.
  5151. (concat "\"" (buffer-string) "\""))
  5152. (car name))
  5153. (nth 1 name))
  5154. "'s message of \""
  5155. (if (or (not date) (string= date ""))
  5156. "(unknown date)" date)
  5157. "\"" (if msg-id ")")))))))
  5158. (defun message-make-distribution ()
  5159. "Make a Distribution header."
  5160. (let ((orig-distribution (message-fetch-reply-field "distribution")))
  5161. (cond ((functionp message-distribution-function)
  5162. (funcall message-distribution-function))
  5163. (t orig-distribution))))
  5164. (defun message-make-expires ()
  5165. "Return an Expires header based on `message-expires'."
  5166. (let ((current (current-time))
  5167. (future (* 1.0 message-expires 60 60 24)))
  5168. ;; Add the future to current.
  5169. (setcar current (+ (car current) (round (/ future (expt 2 16)))))
  5170. (setcar (cdr current) (+ (nth 1 current) (% (round future) (expt 2 16))))
  5171. (message-make-date current)))
  5172. (defun message-make-path ()
  5173. "Return uucp path."
  5174. (let ((login-name (user-login-name)))
  5175. (cond ((null message-user-path)
  5176. (concat (system-name) "!" login-name))
  5177. ((stringp message-user-path)
  5178. ;; Support GENERICPATH. Suggested by vixie@decwrl.dec.com.
  5179. (concat message-user-path "!" login-name))
  5180. (t login-name))))
  5181. (defun message-make-from (&optional name address)
  5182. "Make a From header."
  5183. (let* ((style message-from-style)
  5184. (login (or address (message-make-address)))
  5185. (fullname (or name
  5186. (and (boundp 'user-full-name)
  5187. user-full-name)
  5188. (user-full-name))))
  5189. (when (string= fullname "&")
  5190. (setq fullname (user-login-name)))
  5191. (with-temp-buffer
  5192. (mm-enable-multibyte)
  5193. (cond
  5194. ((or (null style)
  5195. (equal fullname ""))
  5196. (insert login))
  5197. ((or (eq style 'angles)
  5198. (and (not (eq style 'parens))
  5199. ;; Use angles if no quoting is needed, or if parens would
  5200. ;; need quoting too.
  5201. (or (not (string-match "[^- !#-'*+/-9=?A-Z^-~]" fullname))
  5202. (let ((tmp (concat fullname nil)))
  5203. (while (string-match "([^()]*)" tmp)
  5204. (aset tmp (match-beginning 0) ?-)
  5205. (aset tmp (1- (match-end 0)) ?-))
  5206. (string-match "[\\()]" tmp)))))
  5207. (insert fullname)
  5208. (goto-char (point-min))
  5209. ;; Look for a character that cannot appear unquoted
  5210. ;; according to RFC 822.
  5211. (when (re-search-forward "[^- !#-'*+/-9=?A-Z^-~]" nil 1)
  5212. ;; Quote fullname, escaping specials.
  5213. (goto-char (point-min))
  5214. (insert "\"")
  5215. (while (re-search-forward "[\"\\]" nil 1)
  5216. (replace-match "\\\\\\&" t))
  5217. (insert "\""))
  5218. (insert " <" login ">"))
  5219. (t ; 'parens or default
  5220. (insert login " (")
  5221. (let ((fullname-start (point)))
  5222. (insert fullname)
  5223. (goto-char fullname-start)
  5224. ;; RFC 822 says \ and nonmatching parentheses
  5225. ;; must be escaped in comments.
  5226. ;; Escape every instance of ()\ ...
  5227. (while (re-search-forward "[()\\]" nil 1)
  5228. (replace-match "\\\\\\&" t))
  5229. ;; ... then undo escaping of matching parentheses,
  5230. ;; including matching nested parentheses.
  5231. (goto-char fullname-start)
  5232. (while (re-search-forward
  5233. "\\(\\=\\|[^\\]\\(\\\\\\\\\\)*\\)\\\\(\\(\\([^\\]\\|\\\\\\\\\\)*\\)\\\\)"
  5234. nil 1)
  5235. (replace-match "\\1(\\3)" t)
  5236. (goto-char fullname-start)))
  5237. (insert ")")))
  5238. (buffer-string))))
  5239. (defun message-make-sender ()
  5240. "Return the \"real\" user address.
  5241. This function tries to ignore all user modifications, and
  5242. give as trustworthy answer as possible."
  5243. (concat (user-login-name) "@" (system-name)))
  5244. (defun message-make-address ()
  5245. "Make the address of the user."
  5246. (or (message-user-mail-address)
  5247. (concat (user-login-name) "@" (message-make-domain))))
  5248. (defun message-user-mail-address ()
  5249. "Return the pertinent part of `user-mail-address'."
  5250. (when (and user-mail-address
  5251. (string-match "@.*\\." user-mail-address))
  5252. (if (string-match " " user-mail-address)
  5253. (nth 1 (mail-extract-address-components user-mail-address))
  5254. user-mail-address)))
  5255. (defun message-sendmail-envelope-from ()
  5256. "Return the envelope from."
  5257. (cond ((eq message-sendmail-envelope-from 'header)
  5258. (nth 1 (mail-extract-address-components
  5259. (message-fetch-field "from"))))
  5260. ((stringp message-sendmail-envelope-from)
  5261. message-sendmail-envelope-from)
  5262. (t
  5263. (message-make-address))))
  5264. (defun message-make-fqdn ()
  5265. "Return user's fully qualified domain name."
  5266. (let* ((system-name (system-name))
  5267. (user-mail (message-user-mail-address))
  5268. (user-domain
  5269. (if (and user-mail
  5270. (string-match "@\\(.*\\)\\'" user-mail))
  5271. (match-string 1 user-mail)))
  5272. (case-fold-search t))
  5273. (cond
  5274. ((and message-user-fqdn
  5275. (stringp message-user-fqdn)
  5276. (string-match message-valid-fqdn-regexp message-user-fqdn)
  5277. (not (string-match message-bogus-system-names message-user-fqdn)))
  5278. ;; `message-user-fqdn' seems to be valid
  5279. message-user-fqdn)
  5280. ((and (string-match message-valid-fqdn-regexp system-name)
  5281. (not (string-match message-bogus-system-names system-name)))
  5282. ;; `system-name' returned the right result.
  5283. system-name)
  5284. ;; Try `mail-host-address'.
  5285. ((and (boundp 'mail-host-address)
  5286. (stringp mail-host-address)
  5287. (string-match message-valid-fqdn-regexp mail-host-address)
  5288. (not (string-match message-bogus-system-names mail-host-address)))
  5289. mail-host-address)
  5290. ;; We try `user-mail-address' as a backup.
  5291. ((and user-domain
  5292. (stringp user-domain)
  5293. (string-match message-valid-fqdn-regexp user-domain)
  5294. (not (string-match message-bogus-system-names user-domain)))
  5295. user-domain)
  5296. ;; Default to this bogus thing.
  5297. (t
  5298. (concat system-name
  5299. ".i-did-not-set--mail-host-address--so-tickle-me")))))
  5300. (defun message-make-host-name ()
  5301. "Return the name of the host."
  5302. (let ((fqdn (message-make-fqdn)))
  5303. (string-match "^[^.]+\\." fqdn)
  5304. (substring fqdn 0 (1- (match-end 0)))))
  5305. (defun message-make-domain ()
  5306. "Return the domain name."
  5307. (or mail-host-address
  5308. (message-make-fqdn)))
  5309. (defun message-to-list-only ()
  5310. "Send a message to the list only.
  5311. Remove all addresses but the list address from To and Cc headers."
  5312. (interactive)
  5313. (let ((listaddr (message-make-mail-followup-to t)))
  5314. (when listaddr
  5315. (save-excursion
  5316. (message-remove-header "to")
  5317. (message-remove-header "cc")
  5318. (message-position-on-field "To" "X-Draft-From")
  5319. (insert listaddr)))))
  5320. (defun message-make-mail-followup-to (&optional only-show-subscribed)
  5321. "Return the Mail-Followup-To header.
  5322. If passed the optional argument ONLY-SHOW-SUBSCRIBED only return the
  5323. subscribed address (and not the additional To and Cc header contents)."
  5324. (let* ((case-fold-search t)
  5325. (to (message-fetch-field "To"))
  5326. (cc (message-fetch-field "cc"))
  5327. (msg-recipients (concat to (and to cc ", ") cc))
  5328. (recipients
  5329. (mapcar 'mail-strip-quoted-names
  5330. (message-tokenize-header msg-recipients)))
  5331. (file-regexps
  5332. (if message-subscribed-address-file
  5333. (let (begin end item re)
  5334. (save-excursion
  5335. (with-temp-buffer
  5336. (insert-file-contents message-subscribed-address-file)
  5337. (while (not (eobp))
  5338. (setq begin (point))
  5339. (forward-line 1)
  5340. (setq end (point))
  5341. (if (bolp) (setq end (1- end)))
  5342. (setq item (regexp-quote (buffer-substring begin end)))
  5343. (if re (setq re (concat re "\\|" item))
  5344. (setq re (concat "\\`\\(" item))))
  5345. (and re (list (concat re "\\)\\'"))))))))
  5346. (mft-regexps (apply 'append message-subscribed-regexps
  5347. (mapcar 'regexp-quote
  5348. message-subscribed-addresses)
  5349. file-regexps
  5350. (mapcar 'funcall
  5351. message-subscribed-address-functions))))
  5352. (save-match-data
  5353. (let ((list
  5354. (loop for recipient in recipients
  5355. when (loop for regexp in mft-regexps
  5356. when (string-match regexp recipient) return t)
  5357. return recipient)))
  5358. (when list
  5359. (if only-show-subscribed
  5360. list
  5361. msg-recipients))))))
  5362. (defun message-idna-to-ascii-rhs-1 (header)
  5363. "Interactively potentially IDNA encode domain names in HEADER."
  5364. (let ((field (message-fetch-field header))
  5365. ace)
  5366. (when field
  5367. (dolist (rhs
  5368. (mm-delete-duplicates
  5369. (mapcar (lambda (rhs) (or (cadr (split-string rhs "@")) ""))
  5370. (mapcar 'downcase
  5371. (mapcar
  5372. (lambda (elem)
  5373. (or (cadr elem)
  5374. ""))
  5375. (mail-extract-address-components field t))))))
  5376. ;; Note that `rhs' will be "" if the address does not have
  5377. ;; the domain part, i.e., if it is a local user's address.
  5378. (setq ace (if (string-match "\\`[[:ascii:]]*\\'" rhs)
  5379. rhs
  5380. (downcase (idna-to-ascii rhs))))
  5381. (when (and (not (equal rhs ace))
  5382. (or (not (eq message-use-idna 'ask))
  5383. (y-or-n-p (format "Replace %s with %s in %s:? "
  5384. rhs ace header))))
  5385. (goto-char (point-min))
  5386. (while (re-search-forward (concat "^" header ":") nil t)
  5387. (message-narrow-to-field)
  5388. (while (search-forward (concat "@" rhs) nil t)
  5389. (replace-match (concat "@" ace) t t))
  5390. (goto-char (point-max))
  5391. (widen)))))))
  5392. (defun message-idna-to-ascii-rhs ()
  5393. "Possibly IDNA encode non-ASCII domain names in From:, To: and Cc: headers.
  5394. See `message-idna-encode'."
  5395. (interactive)
  5396. (when message-use-idna
  5397. (save-excursion
  5398. (save-restriction
  5399. ;; `message-narrow-to-head' that recognizes only the first empty
  5400. ;; line as the message header separator used to be used here.
  5401. ;; However, since there is the "--text follows this line--" line
  5402. ;; normally, it failed in narrowing to the headers and potentially
  5403. ;; caused the IDNA encoding on lines that look like headers in
  5404. ;; the message body.
  5405. (message-narrow-to-headers-or-head)
  5406. (message-idna-to-ascii-rhs-1 "From")
  5407. (message-idna-to-ascii-rhs-1 "To")
  5408. (message-idna-to-ascii-rhs-1 "Reply-To")
  5409. (message-idna-to-ascii-rhs-1 "Mail-Reply-To")
  5410. (message-idna-to-ascii-rhs-1 "Mail-Followup-To")
  5411. (message-idna-to-ascii-rhs-1 "Cc")))))
  5412. (defvar Date)
  5413. (defvar Message-ID)
  5414. (defvar Organization)
  5415. (defvar From)
  5416. (defvar Path)
  5417. (defvar Subject)
  5418. (defvar Newsgroups)
  5419. (defvar In-Reply-To)
  5420. (defvar References)
  5421. (defvar To)
  5422. (defvar Distribution)
  5423. (defvar Lines)
  5424. (defvar User-Agent)
  5425. (defvar Expires)
  5426. (defun message-generate-headers (headers)
  5427. "Prepare article HEADERS.
  5428. Headers already prepared in the buffer are not modified."
  5429. (setq headers (append headers message-required-headers))
  5430. (save-restriction
  5431. (message-narrow-to-headers)
  5432. (let* ((Date (message-make-date))
  5433. (Message-ID (message-make-message-id))
  5434. (Organization (message-make-organization))
  5435. (From (message-make-from))
  5436. (Path (message-make-path))
  5437. (Subject nil)
  5438. (Newsgroups nil)
  5439. (In-Reply-To (message-make-in-reply-to))
  5440. (References (message-make-references))
  5441. (To nil)
  5442. (Distribution (message-make-distribution))
  5443. (Lines (message-make-lines))
  5444. (User-Agent message-newsreader)
  5445. (Expires (message-make-expires))
  5446. (case-fold-search t)
  5447. (optionalp nil)
  5448. header value elem header-string)
  5449. ;; First we remove any old generated headers.
  5450. (let ((headers message-deletable-headers))
  5451. (unless (buffer-modified-p)
  5452. (setq headers (delq 'Message-ID (copy-sequence headers))))
  5453. (while headers
  5454. (goto-char (point-min))
  5455. (and (re-search-forward
  5456. (concat "^" (symbol-name (car headers)) ": *") nil t)
  5457. (get-text-property (1+ (match-beginning 0)) 'message-deletable)
  5458. (message-delete-line))
  5459. (pop headers)))
  5460. ;; Go through all the required headers and see if they are in the
  5461. ;; articles already. If they are not, or are empty, they are
  5462. ;; inserted automatically - except for Subject, Newsgroups and
  5463. ;; Distribution.
  5464. (while headers
  5465. (goto-char (point-min))
  5466. (setq elem (pop headers))
  5467. (if (consp elem)
  5468. (if (eq (car elem) 'optional)
  5469. (setq header (cdr elem)
  5470. optionalp t)
  5471. (setq header (car elem)))
  5472. (setq header elem))
  5473. (setq header-string (if (stringp header)
  5474. header
  5475. (symbol-name header)))
  5476. (when (or (not (re-search-forward
  5477. (concat "^"
  5478. (regexp-quote (downcase header-string))
  5479. ":")
  5480. nil t))
  5481. (progn
  5482. ;; The header was found. We insert a space after the
  5483. ;; colon, if there is none.
  5484. (if (/= (char-after) ? ) (insert " ") (forward-char 1))
  5485. ;; Find out whether the header is empty.
  5486. (looking-at "[ \t]*\n[^ \t]")))
  5487. ;; So we find out what value we should insert.
  5488. (setq value
  5489. (cond
  5490. ((and (consp elem)
  5491. (eq (car elem) 'optional)
  5492. (not (member header-string message-inserted-headers)))
  5493. ;; This is an optional header. If the cdr of this
  5494. ;; is something that is nil, then we do not insert
  5495. ;; this header.
  5496. (setq header (cdr elem))
  5497. (or (and (functionp (cdr elem))
  5498. (funcall (cdr elem)))
  5499. (and (boundp (cdr elem))
  5500. (symbol-value (cdr elem)))))
  5501. ((consp elem)
  5502. ;; The element is a cons. Either the cdr is a
  5503. ;; string to be inserted verbatim, or it is a
  5504. ;; function, and we insert the value returned from
  5505. ;; this function.
  5506. (or (and (stringp (cdr elem))
  5507. (cdr elem))
  5508. (and (functionp (cdr elem))
  5509. (funcall (cdr elem)))))
  5510. ((and (boundp header)
  5511. (symbol-value header))
  5512. ;; The element is a symbol. We insert the value
  5513. ;; of this symbol, if any.
  5514. (symbol-value header))
  5515. ((not (message-check-element
  5516. (intern (downcase (symbol-name header)))))
  5517. ;; We couldn't generate a value for this header,
  5518. ;; so we just ask the user.
  5519. (read-from-minibuffer
  5520. (format "Empty header for %s; enter value: " header)))))
  5521. ;; Finally insert the header.
  5522. (when (and value
  5523. (not (equal value "")))
  5524. (save-excursion
  5525. (if (bolp)
  5526. (progn
  5527. ;; This header didn't exist, so we insert it.
  5528. (goto-char (point-max))
  5529. (let ((formatter
  5530. (cdr (assq header message-header-format-alist))))
  5531. (if formatter
  5532. (funcall formatter header value)
  5533. (insert header-string ": " value))
  5534. (push header-string message-inserted-headers)
  5535. (goto-char (message-fill-field))
  5536. ;; We check whether the value was ended by a
  5537. ;; newline. If not, we insert one.
  5538. (unless (bolp)
  5539. (insert "\n"))
  5540. (forward-line -1)))
  5541. ;; The value of this header was empty, so we clear
  5542. ;; totally and insert the new value.
  5543. (delete-region (point) (point-at-eol))
  5544. ;; If the header is optional, and the header was
  5545. ;; empty, we can't insert it anyway.
  5546. (unless optionalp
  5547. (push header-string message-inserted-headers)
  5548. (insert value)
  5549. (message-fill-field)))
  5550. ;; Add the deletable property to the headers that require it.
  5551. (and (memq header message-deletable-headers)
  5552. (progn (beginning-of-line) (looking-at "[^:]+: "))
  5553. (add-text-properties
  5554. (point) (match-end 0)
  5555. '(message-deletable t face italic) (current-buffer)))))))
  5556. ;; Insert new Sender if the From is strange.
  5557. (let ((from (message-fetch-field "from"))
  5558. (sender (message-fetch-field "sender"))
  5559. (secure-sender (message-make-sender)))
  5560. (when (and from
  5561. (not (message-check-element 'sender))
  5562. (not (string=
  5563. (downcase
  5564. (cadr (mail-extract-address-components from)))
  5565. (downcase secure-sender)))
  5566. (or (null sender)
  5567. (not
  5568. (string=
  5569. (downcase
  5570. (cadr (mail-extract-address-components sender)))
  5571. (downcase secure-sender)))))
  5572. (goto-char (point-min))
  5573. ;; Rename any old Sender headers to Original-Sender.
  5574. (when (re-search-forward "^\\(Original-\\)*Sender:" nil t)
  5575. (beginning-of-line)
  5576. (insert "Original-")
  5577. (beginning-of-line))
  5578. (when (or (message-news-p)
  5579. (string-match "@.+\\.." secure-sender))
  5580. (insert "Sender: " secure-sender "\n"))))
  5581. ;; Check for IDNA
  5582. (message-idna-to-ascii-rhs))))
  5583. (defun message-insert-courtesy-copy (message)
  5584. "Insert a courtesy message in mail copies of combined messages."
  5585. (let (newsgroups)
  5586. (save-excursion
  5587. (save-restriction
  5588. (message-narrow-to-headers)
  5589. (when (setq newsgroups (message-fetch-field "newsgroups"))
  5590. (goto-char (point-max))
  5591. (insert "Posted-To: " newsgroups "\n")))
  5592. (forward-line 1)
  5593. (when message
  5594. (cond
  5595. ((string-match "%s" message)
  5596. (insert (format message newsgroups)))
  5597. (t
  5598. (insert message)))))))
  5599. ;;;
  5600. ;;; Setting up a message buffer
  5601. ;;;
  5602. (defun message-skip-to-next-address ()
  5603. (let ((end (save-excursion
  5604. (message-next-header)
  5605. (point)))
  5606. quoted char)
  5607. (when (looking-at ",")
  5608. (forward-char 1))
  5609. (while (and (not (= (point) end))
  5610. (or (not (eq char ?,))
  5611. quoted))
  5612. (skip-chars-forward "^,\"" (point-max))
  5613. (when (eq (setq char (following-char)) ?\")
  5614. (setq quoted (not quoted)))
  5615. (unless (= (point) end)
  5616. (forward-char 1)))
  5617. (skip-chars-forward " \t\n")))
  5618. (defun message-fill-address (header value)
  5619. (insert (capitalize (symbol-name header))
  5620. ": "
  5621. (if (consp value) (car value) value)
  5622. "\n")
  5623. (message-fill-field-address))
  5624. (defun message-split-line ()
  5625. "Split current line, moving portion beyond point vertically down.
  5626. If the current line has `message-yank-prefix', insert it on the new line."
  5627. (interactive "*")
  5628. (condition-case nil
  5629. (split-line message-yank-prefix) ;; Emacs 22.1+ supports arg.
  5630. (error
  5631. (split-line))))
  5632. (defun message-insert-header (header value)
  5633. (insert (capitalize (symbol-name header))
  5634. ": "
  5635. (if (consp value) (car value) value)))
  5636. (defun message-field-name ()
  5637. (save-excursion
  5638. (goto-char (point-min))
  5639. (when (looking-at "\\([^:]+\\):")
  5640. (intern (capitalize (match-string 1))))))
  5641. (defun message-fill-field ()
  5642. (save-excursion
  5643. (save-restriction
  5644. (message-narrow-to-field)
  5645. (let ((field-name (message-field-name)))
  5646. (funcall (or (cadr (assq field-name message-field-fillers))
  5647. 'message-fill-field-general)))
  5648. (point-max))))
  5649. (defun message-fill-field-address ()
  5650. (while (not (eobp))
  5651. (message-skip-to-next-address)
  5652. (let (last)
  5653. (if (and (> (current-column) 78)
  5654. last)
  5655. (progn
  5656. (save-excursion
  5657. (goto-char last)
  5658. (insert "\n\t"))
  5659. (setq last (1+ (point))))
  5660. (setq last (1+ (point)))))))
  5661. (defun message-fill-field-general ()
  5662. (let ((begin (point))
  5663. (fill-column 78)
  5664. (fill-prefix "\t"))
  5665. (while (and (search-forward "\n" nil t)
  5666. (not (eobp)))
  5667. (replace-match " " t t))
  5668. (fill-region-as-paragraph begin (point-max))
  5669. ;; Tapdance around looong Message-IDs.
  5670. (forward-line -1)
  5671. (when (looking-at "[ \t]*$")
  5672. (message-delete-line))
  5673. (goto-char begin)
  5674. (search-forward ":" nil t)
  5675. (when (looking-at "\n[ \t]+")
  5676. (replace-match " " t t))
  5677. (goto-char (point-max))))
  5678. (defun message-shorten-1 (list cut surplus)
  5679. "Cut SURPLUS elements out of LIST, beginning with CUTth one."
  5680. (setcdr (nthcdr (- cut 2) list)
  5681. (nthcdr (+ (- cut 2) surplus 1) list)))
  5682. (defun message-shorten-references (header references)
  5683. "Trim REFERENCES to be 21 Message-ID long or less, and fold them.
  5684. When sending via news, also check that the REFERENCES are less
  5685. than 988 characters long, and if they are not, trim them until
  5686. they are."
  5687. ;; 21 is the number suggested by USAGE.
  5688. (let ((maxcount 21)
  5689. (count 0)
  5690. (cut 2)
  5691. refs)
  5692. (with-temp-buffer
  5693. (insert references)
  5694. (goto-char (point-min))
  5695. ;; Cons a list of valid references. GNKSA says we must not include MIDs
  5696. ;; with whitespace or missing brackets (7.a "Does not propagate broken
  5697. ;; Message-IDs in original References").
  5698. (while (re-search-forward "<[^ <]+@[^ <]+>" nil t)
  5699. (push (match-string 0) refs))
  5700. (setq refs (nreverse refs)
  5701. count (length refs)))
  5702. ;; If the list has more than MAXCOUNT elements, trim it by
  5703. ;; removing the CUTth element and the required number of
  5704. ;; elements that follow.
  5705. (when (> count maxcount)
  5706. (let ((surplus (- count maxcount)))
  5707. (message-shorten-1 refs cut surplus)
  5708. (decf count surplus)))
  5709. ;; When sending via news, make sure the total folded length will
  5710. ;; be less than 998 characters. This is to cater to broken INN
  5711. ;; 2.3 which counts the total number of characters in a header
  5712. ;; rather than the physical line length of each line, as it should.
  5713. ;;
  5714. ;; This hack should be removed when it's believed than INN 2.3 is
  5715. ;; no longer widely used.
  5716. ;;
  5717. ;; At this point the headers have not been generated, thus we use
  5718. ;; message-this-is-news directly.
  5719. (when message-this-is-news
  5720. (while (< 998
  5721. (with-temp-buffer
  5722. (message-insert-header
  5723. header (mapconcat #'identity refs " "))
  5724. (buffer-size)))
  5725. (message-shorten-1 refs cut 1)))
  5726. ;; Finally, collect the references back into a string and insert
  5727. ;; it into the buffer.
  5728. (message-insert-header header (mapconcat #'identity refs " "))))
  5729. (defun message-position-point ()
  5730. "Move point to where the user probably wants to find it."
  5731. (message-narrow-to-headers)
  5732. (cond
  5733. ((re-search-forward "^[^:]+:[ \t]*$" nil t)
  5734. (search-backward ":" )
  5735. (widen)
  5736. (forward-char 1)
  5737. (if (eq (char-after) ? )
  5738. (forward-char 1)
  5739. (insert " ")))
  5740. (t
  5741. (goto-char (point-max))
  5742. (widen)
  5743. (forward-line 1)
  5744. (unless (looking-at "$")
  5745. (forward-line 2)))
  5746. (sit-for 0)))
  5747. (defcustom message-beginning-of-line t
  5748. "Whether \\<message-mode-map>\\[message-beginning-of-line]\
  5749. goes to beginning of header values."
  5750. :version "22.1"
  5751. :group 'message-buffers
  5752. :link '(custom-manual "(message)Movement")
  5753. :type 'boolean)
  5754. (defun message-beginning-of-line (&optional n)
  5755. "Move point to beginning of header value or to beginning of line.
  5756. The prefix argument N is passed directly to `beginning-of-line'.
  5757. This command is identical to `beginning-of-line' if point is
  5758. outside the message header or if the option `message-beginning-of-line'
  5759. is nil.
  5760. If point is in the message header and on a (non-continued) header
  5761. line, move point to the beginning of the header value or the beginning of line,
  5762. whichever is closer. If point is already at beginning of line, move point to
  5763. beginning of header value. Therefore, repeated calls will toggle point
  5764. between beginning of field and beginning of line."
  5765. (interactive "p")
  5766. (let ((zrs 'zmacs-region-stays))
  5767. (when (and (featurep 'xemacs) (interactive-p) (boundp zrs))
  5768. (set zrs t)))
  5769. (if (and message-beginning-of-line
  5770. (message-point-in-header-p))
  5771. (let* ((here (point))
  5772. (bol (progn (beginning-of-line n) (point)))
  5773. (eol (point-at-eol))
  5774. (eoh (re-search-forward ": *" eol t)))
  5775. (goto-char
  5776. (if (and eoh (or (< eoh here) (= bol here)))
  5777. eoh bol)))
  5778. (beginning-of-line n)))
  5779. (defun message-buffer-name (type &optional to group)
  5780. "Return a new (unique) buffer name based on TYPE and TO."
  5781. (cond
  5782. ;; Generate a new buffer name The Message Way.
  5783. ((memq message-generate-new-buffers '(unique t))
  5784. (generate-new-buffer-name
  5785. (concat "*" type
  5786. (if to
  5787. (concat " to "
  5788. (or (car (mail-extract-address-components to))
  5789. to) "")
  5790. "")
  5791. (if (and group (not (string= group ""))) (concat " on " group) "")
  5792. "*")))
  5793. ;; Check whether `message-generate-new-buffers' is a function,
  5794. ;; and if so, call it.
  5795. ((functionp message-generate-new-buffers)
  5796. (funcall message-generate-new-buffers type to group))
  5797. ((eq message-generate-new-buffers 'unsent)
  5798. (generate-new-buffer-name
  5799. (concat "*unsent " type
  5800. (if to
  5801. (concat " to "
  5802. (or (car (mail-extract-address-components to))
  5803. to) "")
  5804. "")
  5805. (if (and group (not (string= group ""))) (concat " on " group) "")
  5806. "*")))
  5807. ;; Search for the existing message buffer with the specified name.
  5808. (t
  5809. (let* ((new (if (eq message-generate-new-buffers 'standard)
  5810. (generate-new-buffer-name (concat "*" type " message*"))
  5811. (let ((message-generate-new-buffers 'unique))
  5812. (message-buffer-name type to group))))
  5813. (regexp (concat "\\`"
  5814. (regexp-quote
  5815. (if (string-match "<[0-9]+>\\'" new)
  5816. (substring new 0 (match-beginning 0))
  5817. new))
  5818. "\\(?:<\\([0-9]+\\)>\\)?\\'"))
  5819. (case-fold-search nil))
  5820. (or (cdar
  5821. (last
  5822. (sort
  5823. (delq nil
  5824. (mapcar
  5825. (lambda (b)
  5826. (when (and (string-match regexp (setq b (buffer-name b)))
  5827. (eq (with-current-buffer b major-mode)
  5828. 'message-mode))
  5829. (cons (string-to-number (or (match-string 1 b) "1"))
  5830. b)))
  5831. (buffer-list)))
  5832. 'car-less-than-car)))
  5833. new)))))
  5834. (defun message-pop-to-buffer (name &optional switch-function)
  5835. "Pop to buffer NAME, and warn if it already exists and is modified."
  5836. (let ((buffer (get-buffer name)))
  5837. (if (and buffer
  5838. (buffer-name buffer))
  5839. (let ((window (get-buffer-window buffer 0)))
  5840. (if window
  5841. ;; Raise the frame already displaying the message buffer.
  5842. (progn
  5843. (gnus-select-frame-set-input-focus (window-frame window))
  5844. (select-window window))
  5845. (funcall (or switch-function #'pop-to-buffer) buffer)
  5846. (set-buffer buffer))
  5847. (when (and (buffer-modified-p)
  5848. (not (prog1
  5849. (y-or-n-p
  5850. "Message already being composed; erase? ")
  5851. (message nil))))
  5852. (error "Message being composed")))
  5853. (funcall (or switch-function
  5854. (if (fboundp #'pop-to-buffer-same-window)
  5855. #'pop-to-buffer-same-window
  5856. #'pop-to-buffer))
  5857. name)
  5858. (set-buffer name))
  5859. (erase-buffer)
  5860. (message-mode)))
  5861. (defun message-do-send-housekeeping ()
  5862. "Kill old message buffers."
  5863. ;; We might have sent this buffer already. Delete it from the
  5864. ;; list of buffers.
  5865. (setq message-buffer-list (delq (current-buffer) message-buffer-list))
  5866. (while (and message-max-buffers
  5867. message-buffer-list
  5868. (>= (length message-buffer-list) message-max-buffers))
  5869. ;; Kill the oldest buffer -- unless it has been changed.
  5870. (let ((buffer (pop message-buffer-list)))
  5871. (when (and (buffer-name buffer)
  5872. (not (buffer-modified-p buffer)))
  5873. (kill-buffer buffer))))
  5874. ;; Rename the buffer.
  5875. (if message-send-rename-function
  5876. (funcall message-send-rename-function)
  5877. (message-default-send-rename-function))
  5878. ;; Push the current buffer onto the list.
  5879. (when message-max-buffers
  5880. (setq message-buffer-list
  5881. (nconc message-buffer-list (list (current-buffer))))))
  5882. (defun message-default-send-rename-function ()
  5883. ;; Note: mail-abbrevs of XEmacs renames buffer name behind Gnus.
  5884. (when (string-match
  5885. "\\`\\*\\(sent \\|unsent \\)?\\(.+\\)\\*[^\\*]*\\|\\`mail to "
  5886. (buffer-name))
  5887. (let ((name (match-string 2 (buffer-name)))
  5888. to group)
  5889. (if (not (or (null name)
  5890. (string-equal name "mail")
  5891. (string-equal name "posting")))
  5892. (setq name (concat "*sent " name "*"))
  5893. (message-narrow-to-headers)
  5894. (setq to (message-fetch-field "to"))
  5895. (setq group (message-fetch-field "newsgroups"))
  5896. (widen)
  5897. (setq name
  5898. (cond
  5899. (to (concat "*sent mail to "
  5900. (or (car (mail-extract-address-components to))
  5901. to) "*"))
  5902. ((and group (not (string= group "")))
  5903. (concat "*sent posting on " group "*"))
  5904. (t "*sent mail*"))))
  5905. (unless (string-equal name (buffer-name))
  5906. (rename-buffer name t)))))
  5907. (defun message-mail-user-agent ()
  5908. (let ((mua (cond
  5909. ((not message-mail-user-agent) nil)
  5910. ((eq message-mail-user-agent t) mail-user-agent)
  5911. (t message-mail-user-agent))))
  5912. (if (memq mua '(message-user-agent gnus-user-agent))
  5913. nil
  5914. mua)))
  5915. ;; YANK-ACTION, if non-nil, can be a buffer or a yank action of the
  5916. ;; form (FUNCTION . ARGS).
  5917. (defun message-setup (headers &optional yank-action actions
  5918. continue switch-function return-action)
  5919. (let ((mua (message-mail-user-agent))
  5920. subject to field)
  5921. (if (not (and message-this-is-mail mua))
  5922. (message-setup-1 headers yank-action actions return-action)
  5923. (setq headers (copy-sequence headers))
  5924. (setq field (assq 'Subject headers))
  5925. (when field
  5926. (setq subject (cdr field))
  5927. (setq headers (delq field headers)))
  5928. (setq field (assq 'To headers))
  5929. (when field
  5930. (setq to (cdr field))
  5931. (setq headers (delq field headers)))
  5932. (let ((mail-user-agent mua))
  5933. (compose-mail to subject
  5934. (mapcar (lambda (item)
  5935. (cons
  5936. (format "%s" (car item))
  5937. (cdr item)))
  5938. headers)
  5939. continue switch-function
  5940. (if (bufferp yank-action)
  5941. (list 'insert-buffer yank-action)
  5942. yank-action)
  5943. actions)))))
  5944. (defun message-headers-to-generate (headers included-headers excluded-headers)
  5945. "Return a list that includes all headers from HEADERS.
  5946. If INCLUDED-HEADERS is a list, just include those headers. If it is
  5947. t, include all headers. In any case, headers from EXCLUDED-HEADERS
  5948. are not included."
  5949. (let ((result nil)
  5950. header-name)
  5951. (dolist (header headers)
  5952. (setq header-name (cond
  5953. ((and (consp header)
  5954. (eq (car header) 'optional))
  5955. ;; On the form (optional . Header)
  5956. (cdr header))
  5957. ((consp header)
  5958. ;; On the form (Header . function)
  5959. (car header))
  5960. (t
  5961. ;; Just a Header.
  5962. header)))
  5963. (when (and (not (memq header-name excluded-headers))
  5964. (or (eq included-headers t)
  5965. (memq header-name included-headers)))
  5966. (push header result)))
  5967. (nreverse result)))
  5968. (defun message-setup-1 (headers &optional yank-action actions return-action)
  5969. (dolist (action actions)
  5970. (condition-case nil
  5971. (add-to-list 'message-send-actions
  5972. `(apply ',(car action) ',(cdr action)))))
  5973. (setq message-return-action return-action)
  5974. (setq message-reply-buffer
  5975. (if (and (consp yank-action)
  5976. (eq (car yank-action) 'insert-buffer))
  5977. (nth 1 yank-action)
  5978. yank-action))
  5979. (goto-char (point-min))
  5980. ;; Insert all the headers.
  5981. (mail-header-format
  5982. (let ((h headers)
  5983. (alist message-header-format-alist))
  5984. (while h
  5985. (unless (assq (caar h) message-header-format-alist)
  5986. (push (list (caar h)) alist))
  5987. (pop h))
  5988. alist)
  5989. headers)
  5990. (delete-region (point) (progn (forward-line -1) (point)))
  5991. (when message-default-headers
  5992. (insert
  5993. (if (functionp message-default-headers)
  5994. (funcall message-default-headers)
  5995. message-default-headers))
  5996. (or (bolp) (insert ?\n)))
  5997. (insert (concat mail-header-separator "\n"))
  5998. (forward-line -1)
  5999. ;; If a crash happens while replying, the auto-save file would *not* have a
  6000. ;; `References:' header if `message-generate-headers-first' was nil.
  6001. ;; Therefore, always generate it first.
  6002. (let ((message-generate-headers-first
  6003. (if (eq message-generate-headers-first t)
  6004. t
  6005. (append message-generate-headers-first '(References)))))
  6006. (when (message-news-p)
  6007. (when message-default-news-headers
  6008. (insert message-default-news-headers)
  6009. (or (bolp) (insert ?\n)))
  6010. (message-generate-headers
  6011. (message-headers-to-generate
  6012. (append message-required-news-headers
  6013. message-required-headers)
  6014. message-generate-headers-first
  6015. '(Lines Subject))))
  6016. (when (message-mail-p)
  6017. (when message-default-mail-headers
  6018. (insert message-default-mail-headers)
  6019. (or (bolp) (insert ?\n)))
  6020. (message-generate-headers
  6021. (message-headers-to-generate
  6022. (append message-required-mail-headers
  6023. message-required-headers)
  6024. message-generate-headers-first
  6025. '(Lines Subject)))))
  6026. (run-hooks 'message-signature-setup-hook)
  6027. (message-insert-signature)
  6028. (save-restriction
  6029. (message-narrow-to-headers)
  6030. (run-hooks 'message-header-setup-hook))
  6031. (setq buffer-undo-list nil)
  6032. (when message-generate-hashcash
  6033. ;; Generate hashcash headers for recipients already known
  6034. (mail-add-payment-async))
  6035. ;; Gnus posting styles are applied via buffer-local `message-setup-hook'
  6036. ;; values.
  6037. (run-hooks 'message-setup-hook)
  6038. ;; Do this last to give it precedence over posting styles, etc.
  6039. (when (message-mail-p)
  6040. (save-restriction
  6041. (message-narrow-to-headers)
  6042. (if message-alternative-emails
  6043. (message-use-alternative-email-as-from))))
  6044. (message-position-point)
  6045. ;; Allow correct handling of `message-checksum' in `message-yank-original':
  6046. (set-buffer-modified-p nil)
  6047. (undo-boundary)
  6048. ;; rmail-start-mail expects message-mail to return t (Bug#9392)
  6049. t)
  6050. (defun message-set-auto-save-file-name ()
  6051. "Associate the message buffer with a file in the drafts directory."
  6052. (when message-auto-save-directory
  6053. (unless (file-directory-p
  6054. (directory-file-name message-auto-save-directory))
  6055. (make-directory message-auto-save-directory t))
  6056. (if (gnus-alive-p)
  6057. (setq message-draft-article
  6058. (nndraft-request-associate-buffer "drafts"))
  6059. ;; If Gnus were alive, draft messages would be saved in the drafts folder.
  6060. ;; But Gnus is not alive, so arrange to save the draft message in a
  6061. ;; regular file in message-auto-save-directory. Append a unique
  6062. ;; time-based suffix to the filename to allow multiple drafts to be saved
  6063. ;; simultaneously without overwriting each other (which mimics the
  6064. ;; functionality of the Gnus drafts folder).
  6065. (setq buffer-file-name (expand-file-name
  6066. (concat
  6067. (if (memq system-type
  6068. '(ms-dos windows-nt cygwin))
  6069. "message"
  6070. "*message*")
  6071. (format-time-string "-%Y%m%d-%H%M%S"))
  6072. message-auto-save-directory))
  6073. (setq buffer-auto-save-file-name (make-auto-save-file-name)))
  6074. (clear-visited-file-modtime)
  6075. (setq buffer-file-coding-system message-draft-coding-system)))
  6076. (defun message-disassociate-draft ()
  6077. "Disassociate the message buffer from the drafts directory."
  6078. (when message-draft-article
  6079. (nndraft-request-expire-articles
  6080. (list message-draft-article) "drafts" nil t)))
  6081. (defun message-insert-headers ()
  6082. "Generate the headers for the article."
  6083. (interactive)
  6084. (save-excursion
  6085. (save-restriction
  6086. (message-narrow-to-headers)
  6087. (when (message-news-p)
  6088. (message-generate-headers
  6089. (delq 'Lines
  6090. (delq 'Subject
  6091. (copy-sequence message-required-news-headers)))))
  6092. (when (message-mail-p)
  6093. (message-generate-headers
  6094. (delq 'Lines
  6095. (delq 'Subject
  6096. (copy-sequence message-required-mail-headers))))))))
  6097. ;;;
  6098. ;;; Commands for interfacing with message
  6099. ;;;
  6100. ;;;###autoload
  6101. (defun message-mail (&optional to subject other-headers continue
  6102. switch-function yank-action send-actions
  6103. return-action &rest ignored)
  6104. "Start editing a mail message to be sent.
  6105. OTHER-HEADERS is an alist of header/value pairs. CONTINUE says whether
  6106. to continue editing a message already being composed. SWITCH-FUNCTION
  6107. is a function used to switch to and display the mail buffer."
  6108. (interactive)
  6109. (let ((message-this-is-mail t))
  6110. (unless (message-mail-user-agent)
  6111. (message-pop-to-buffer
  6112. ;; Search for the existing message buffer if `continue' is non-nil.
  6113. (let ((message-generate-new-buffers
  6114. (when (or (not continue)
  6115. (eq message-generate-new-buffers 'standard)
  6116. (functionp message-generate-new-buffers))
  6117. message-generate-new-buffers)))
  6118. (message-buffer-name "mail" to))
  6119. switch-function))
  6120. (message-setup
  6121. (nconc
  6122. `((To . ,(or to "")) (Subject . ,(or subject "")))
  6123. ;; C-h f compose-mail says that headers should be specified as
  6124. ;; (string . value); however all the rest of message expects
  6125. ;; headers to be symbols, not strings (eg message-header-format-alist).
  6126. ;; http://lists.gnu.org/archive/html/emacs-devel/2011-01/msg00337.html
  6127. ;; We need to convert any string input, eg from rmail-start-mail.
  6128. (dolist (h other-headers other-headers)
  6129. (if (stringp (car h)) (setcar h (intern (capitalize (car h)))))))
  6130. yank-action send-actions continue switch-function
  6131. return-action)))
  6132. ;;;###autoload
  6133. (defun message-news (&optional newsgroups subject)
  6134. "Start editing a news article to be sent."
  6135. (interactive)
  6136. (let ((message-this-is-news t))
  6137. (message-pop-to-buffer (message-buffer-name "posting" nil newsgroups))
  6138. (message-setup `((Newsgroups . ,(or newsgroups ""))
  6139. (Subject . ,(or subject ""))))))
  6140. (defun message-alter-recipients-discard-bogus-full-name (addrcell)
  6141. "Discard mail address in full names.
  6142. When the full name in reply headers contains the mail
  6143. address (e.g. \"foo@bar <foo@bar>\"), discard full name.
  6144. ADDRCELL is a cons cell where the car is the mail address and the
  6145. cdr is the complete address (full name and mail address)."
  6146. (if (string-match (concat (regexp-quote (car addrcell)) ".*"
  6147. (regexp-quote (car addrcell)))
  6148. (cdr addrcell))
  6149. (cons (car addrcell) (car addrcell))
  6150. addrcell))
  6151. (defcustom message-alter-recipients-function nil
  6152. "Function called to allow alteration of reply header structures.
  6153. It is called in `message-get-reply-headers' for each recipient.
  6154. The function is called with one parameter, a cons cell ..."
  6155. :type '(choice (const :tag "None" nil)
  6156. (const :tag "Discard bogus full name"
  6157. message-alter-recipients-discard-bogus-full-name)
  6158. function)
  6159. :version "23.1" ;; No Gnus
  6160. :group 'message-headers)
  6161. (defun message-get-reply-headers (wide &optional to-address address-headers)
  6162. (let (follow-to mct never-mct to cc author mft recipients extra)
  6163. ;; Find all relevant headers we need.
  6164. (save-restriction
  6165. (message-narrow-to-headers-or-head)
  6166. ;; Gmane renames "To". Look at "Original-To", too, if it is present in
  6167. ;; message-header-synonyms.
  6168. (setq to (or (message-fetch-field "to")
  6169. (and (loop for synonym in message-header-synonyms
  6170. when (memq 'Original-To synonym)
  6171. return t)
  6172. (message-fetch-field "original-to")))
  6173. cc (message-fetch-field "cc")
  6174. extra (when message-extra-wide-headers
  6175. (mapconcat 'identity
  6176. (mapcar 'message-fetch-field
  6177. message-extra-wide-headers)
  6178. ", "))
  6179. mct (message-fetch-field "mail-copies-to")
  6180. author (or (message-fetch-field "mail-reply-to")
  6181. (message-fetch-field "reply-to")
  6182. (message-fetch-field "from")
  6183. "")
  6184. mft (and message-use-mail-followup-to
  6185. (message-fetch-field "mail-followup-to"))))
  6186. ;; Handle special values of Mail-Copies-To.
  6187. (when mct
  6188. (cond ((or (equal (downcase mct) "never")
  6189. (equal (downcase mct) "nobody"))
  6190. (setq never-mct t)
  6191. (setq mct nil))
  6192. ((or (equal (downcase mct) "always")
  6193. (equal (downcase mct) "poster"))
  6194. (setq mct author))))
  6195. (save-match-data
  6196. ;; Build (textual) list of new recipient addresses.
  6197. (cond
  6198. (to-address
  6199. (setq recipients (concat ", " to-address))
  6200. ;; If the author explicitly asked for a copy, we don't deny it to them.
  6201. (if mct (setq recipients (concat recipients ", " mct))))
  6202. ((not wide)
  6203. (setq recipients (concat ", " author)))
  6204. (address-headers
  6205. (dolist (header address-headers)
  6206. (let ((value (message-fetch-field header)))
  6207. (when value
  6208. (setq recipients (concat recipients ", " value))))))
  6209. ((and mft
  6210. (string-match "[^ \t,]" mft)
  6211. (or (not (eq message-use-mail-followup-to 'ask))
  6212. (message-y-or-n-p "Obey Mail-Followup-To? " t "\
  6213. You should normally obey the Mail-Followup-To: header. In this
  6214. article, it has the value of
  6215. " mft "
  6216. which directs your response to " (if (string-match "," mft)
  6217. "the specified addresses"
  6218. "that address only") ".
  6219. Most commonly, Mail-Followup-To is used by a mailing list poster to
  6220. express that responses should be sent to just the list, and not the
  6221. poster as well.
  6222. If a message is posted to several mailing lists, Mail-Followup-To may
  6223. also be used to direct the following discussion to one list only,
  6224. because discussions that are spread over several lists tend to be
  6225. fragmented and very difficult to follow.
  6226. Also, some source/announcement lists are not intended for discussion;
  6227. responses here are directed to other addresses.
  6228. You may customize the variable `message-use-mail-followup-to', if you
  6229. want to get rid of this query permanently.")))
  6230. (setq recipients (concat ", " mft)))
  6231. (t
  6232. (setq recipients (if never-mct "" (concat ", " author)))
  6233. (if to (setq recipients (concat recipients ", " to)))
  6234. (if cc (setq recipients (concat recipients ", " cc)))
  6235. (if extra (setq recipients (concat recipients ", " extra)))
  6236. (if mct (setq recipients (concat recipients ", " mct)))))
  6237. (if (>= (length recipients) 2)
  6238. ;; Strip the leading ", ".
  6239. (setq recipients (substring recipients 2)))
  6240. ;; Squeeze whitespace.
  6241. (while (string-match "[ \t][ \t]+" recipients)
  6242. (setq recipients (replace-match " " t t recipients)))
  6243. ;; Remove addresses that match `rmail-dont-reply-to-names'.
  6244. (let ((rmail-dont-reply-to-names (message-dont-reply-to-names)))
  6245. (setq recipients (rmail-dont-reply-to recipients)))
  6246. ;; Perhaps "Mail-Copies-To: never" removed the only address?
  6247. (if (string-equal recipients "")
  6248. (setq recipients author))
  6249. ;; Convert string to a list of (("foo@bar" . "Name <Foo@BAR>") ...).
  6250. (setq recipients
  6251. (mapcar
  6252. (lambda (addr)
  6253. (if message-alter-recipients-function
  6254. (funcall message-alter-recipients-function
  6255. (cons (downcase (mail-strip-quoted-names addr))
  6256. addr))
  6257. (cons (downcase (mail-strip-quoted-names addr)) addr)))
  6258. (message-tokenize-header recipients)))
  6259. ;; Remove all duplicates.
  6260. (let ((s recipients))
  6261. (while s
  6262. (let ((address (car (pop s))))
  6263. (while (assoc address s)
  6264. (setq recipients (delq (assoc address s) recipients)
  6265. s (delq (assoc address s) s))))))
  6266. ;; Remove hierarchical lists that are contained within each other,
  6267. ;; if message-hierarchical-addresses is defined.
  6268. (when message-hierarchical-addresses
  6269. (let ((plain-addrs (mapcar 'car recipients))
  6270. subaddrs recip)
  6271. (while plain-addrs
  6272. (setq subaddrs (assoc (car plain-addrs)
  6273. message-hierarchical-addresses)
  6274. plain-addrs (cdr plain-addrs))
  6275. (when subaddrs
  6276. (setq subaddrs (cdr subaddrs))
  6277. (while subaddrs
  6278. (setq recip (assoc (car subaddrs) recipients)
  6279. subaddrs (cdr subaddrs))
  6280. (if recip
  6281. (setq recipients (delq recip recipients))))))))
  6282. (setq recipients (message-prune-recipients recipients))
  6283. ;; Build the header alist. Allow the user to be asked whether
  6284. ;; or not to reply to all recipients in a wide reply.
  6285. (setq follow-to (list (cons 'To (cdr (pop recipients)))))
  6286. (when (and recipients
  6287. (or (not message-wide-reply-confirm-recipients)
  6288. (y-or-n-p "Reply to all recipients? ")))
  6289. (setq recipients (mapconcat
  6290. (lambda (addr) (cdr addr)) recipients ", "))
  6291. (if (string-match "^ +" recipients)
  6292. (setq recipients (substring recipients (match-end 0))))
  6293. (push (cons 'Cc recipients) follow-to)))
  6294. follow-to))
  6295. (defun message-prune-recipients (recipients)
  6296. (dolist (rule message-prune-recipient-rules)
  6297. (let ((match (car rule))
  6298. dup-match
  6299. address)
  6300. (dolist (recipient recipients)
  6301. (setq address (car recipient))
  6302. (when (string-match match address)
  6303. (setq dup-match (replace-match (cadr rule) nil nil address))
  6304. (dolist (recipient recipients)
  6305. ;; Don't delete the address that triggered this.
  6306. (when (and (not (eq address (car recipient)))
  6307. (string-match dup-match (car recipient)))
  6308. (setq recipients (delq recipient recipients))))))))
  6309. recipients)
  6310. (defcustom message-simplify-subject-functions
  6311. '(message-strip-list-identifiers
  6312. message-strip-subject-re
  6313. message-strip-subject-trailing-was
  6314. message-strip-subject-encoded-words)
  6315. "List of functions taking a string argument that simplify subjects.
  6316. The functions are applied when replying to a message.
  6317. Useful functions to put in this list include:
  6318. `message-strip-list-identifiers', `message-strip-subject-re',
  6319. `message-strip-subject-trailing-was', and
  6320. `message-strip-subject-encoded-words'."
  6321. :version "22.1" ;; Gnus 5.10.9
  6322. :group 'message-various
  6323. :type '(repeat function))
  6324. (defun message-simplify-subject (subject &optional functions)
  6325. "Return simplified SUBJECT."
  6326. (unless functions
  6327. ;; Simplify fully:
  6328. (setq functions message-simplify-subject-functions))
  6329. (when (and (memq 'message-strip-list-identifiers functions)
  6330. gnus-list-identifiers)
  6331. (setq subject (message-strip-list-identifiers subject)))
  6332. (when (memq 'message-strip-subject-re functions)
  6333. (setq subject (concat "Re: " (message-strip-subject-re subject))))
  6334. (when (and (memq 'message-strip-subject-trailing-was functions)
  6335. message-subject-trailing-was-query)
  6336. (setq subject (message-strip-subject-trailing-was subject)))
  6337. (when (memq 'message-strip-subject-encoded-words functions)
  6338. (setq subject (message-strip-subject-encoded-words subject)))
  6339. subject)
  6340. ;;;###autoload
  6341. (defun message-reply (&optional to-address wide switch-function)
  6342. "Start editing a reply to the article in the current buffer."
  6343. (interactive)
  6344. (require 'gnus-sum) ; for gnus-list-identifiers
  6345. (let ((cur (current-buffer))
  6346. from subject date
  6347. references message-id follow-to
  6348. (inhibit-point-motion-hooks t)
  6349. (message-this-is-mail t)
  6350. gnus-warning)
  6351. (save-restriction
  6352. (message-narrow-to-head-1)
  6353. ;; Allow customizations to have their say.
  6354. (if (not wide)
  6355. ;; This is a regular reply.
  6356. (when (functionp message-reply-to-function)
  6357. (save-excursion
  6358. (setq follow-to (funcall message-reply-to-function))))
  6359. ;; This is a followup.
  6360. (when (functionp message-wide-reply-to-function)
  6361. (save-excursion
  6362. (setq follow-to
  6363. (funcall message-wide-reply-to-function)))))
  6364. (setq message-id (message-fetch-field "message-id" t)
  6365. references (message-fetch-field "references")
  6366. date (message-fetch-field "date")
  6367. from (or (message-fetch-field "from") "nobody")
  6368. subject (or (message-fetch-field "subject") "none"))
  6369. ;; Strip list identifiers, "Re: ", and "was:"
  6370. (setq subject (message-simplify-subject subject))
  6371. (when (and (setq gnus-warning (message-fetch-field "gnus-warning"))
  6372. (string-match "<[^>]+>" gnus-warning))
  6373. (setq message-id (match-string 0 gnus-warning)))
  6374. (unless follow-to
  6375. (setq follow-to (message-get-reply-headers wide to-address))))
  6376. (let ((headers
  6377. `((Subject . ,subject)
  6378. ,@follow-to)))
  6379. (unless (message-mail-user-agent)
  6380. (message-pop-to-buffer
  6381. (message-buffer-name
  6382. (if wide "wide reply" "reply") from
  6383. (if wide to-address nil))
  6384. switch-function))
  6385. (setq message-reply-headers
  6386. (vector 0 (cdr (assq 'Subject headers))
  6387. from date message-id references 0 0 ""))
  6388. (message-setup headers cur))))
  6389. ;;;###autoload
  6390. (defun message-wide-reply (&optional to-address)
  6391. "Make a \"wide\" reply to the message in the current buffer."
  6392. (interactive)
  6393. (message-reply to-address t))
  6394. ;;;###autoload
  6395. (defun message-followup (&optional to-newsgroups)
  6396. "Follow up to the message in the current buffer.
  6397. If TO-NEWSGROUPS, use that as the new Newsgroups line."
  6398. (interactive)
  6399. (require 'gnus-sum) ; for gnus-list-identifiers
  6400. (let ((cur (current-buffer))
  6401. from subject date reply-to mrt mct
  6402. references message-id follow-to
  6403. (inhibit-point-motion-hooks t)
  6404. (message-this-is-news t)
  6405. followup-to distribution newsgroups gnus-warning posted-to)
  6406. (save-restriction
  6407. (narrow-to-region
  6408. (goto-char (point-min))
  6409. (if (search-forward "\n\n" nil t)
  6410. (1- (point))
  6411. (point-max)))
  6412. (when (functionp message-followup-to-function)
  6413. (setq follow-to
  6414. (funcall message-followup-to-function)))
  6415. (setq from (message-fetch-field "from")
  6416. date (message-fetch-field "date")
  6417. subject (or (message-fetch-field "subject") "none")
  6418. references (message-fetch-field "references")
  6419. message-id (message-fetch-field "message-id" t)
  6420. followup-to (message-fetch-field "followup-to")
  6421. newsgroups (message-fetch-field "newsgroups")
  6422. posted-to (message-fetch-field "posted-to")
  6423. reply-to (message-fetch-field "reply-to")
  6424. mrt (message-fetch-field "mail-reply-to")
  6425. distribution (message-fetch-field "distribution")
  6426. mct (message-fetch-field "mail-copies-to"))
  6427. (when (and (setq gnus-warning (message-fetch-field "gnus-warning"))
  6428. (string-match "<[^>]+>" gnus-warning))
  6429. (setq message-id (match-string 0 gnus-warning)))
  6430. ;; Remove bogus distribution.
  6431. (when (and (stringp distribution)
  6432. (let ((case-fold-search t))
  6433. (string-match "world" distribution)))
  6434. (setq distribution nil))
  6435. ;; Strip list identifiers, "Re: ", and "was:"
  6436. (setq subject (message-simplify-subject subject))
  6437. (widen))
  6438. (message-pop-to-buffer (message-buffer-name "followup" from newsgroups))
  6439. (setq message-reply-headers
  6440. (vector 0 subject from date message-id references 0 0 ""))
  6441. (message-setup
  6442. `((Subject . ,subject)
  6443. ,@(cond
  6444. (to-newsgroups
  6445. (list (cons 'Newsgroups to-newsgroups)))
  6446. (follow-to follow-to)
  6447. ((and followup-to message-use-followup-to)
  6448. (list
  6449. (cond
  6450. ((equal (downcase followup-to) "poster")
  6451. (if (or (eq message-use-followup-to 'use)
  6452. (message-y-or-n-p "Obey Followup-To: poster? " t "\
  6453. You should normally obey the Followup-To: header.
  6454. `Followup-To: poster' sends your response via e-mail instead of news.
  6455. A typical situation where `Followup-To: poster' is used is when the poster
  6456. does not read the newsgroup, so he wouldn't see any replies sent to it.
  6457. You may customize the variable `message-use-followup-to', if you
  6458. want to get rid of this query permanently."))
  6459. (progn
  6460. (setq message-this-is-news nil)
  6461. (cons 'To (or mrt reply-to from "")))
  6462. (cons 'Newsgroups newsgroups)))
  6463. (t
  6464. (if (or (equal followup-to newsgroups)
  6465. (not (eq message-use-followup-to 'ask))
  6466. (message-y-or-n-p
  6467. (concat "Obey Followup-To: " followup-to "? ") t "\
  6468. You should normally obey the Followup-To: header.
  6469. `Followup-To: " followup-to "'
  6470. directs your response to " (if (string-match "," followup-to)
  6471. "the specified newsgroups"
  6472. "that newsgroup only") ".
  6473. If a message is posted to several newsgroups, Followup-To is often
  6474. used to direct the following discussion to one newsgroup only,
  6475. because discussions that are spread over several newsgroup tend to
  6476. be fragmented and very difficult to follow.
  6477. Also, some source/announcement newsgroups are not intended for discussion;
  6478. responses here are directed to other newsgroups.
  6479. You may customize the variable `message-use-followup-to', if you
  6480. want to get rid of this query permanently."))
  6481. (cons 'Newsgroups followup-to)
  6482. (cons 'Newsgroups newsgroups))))))
  6483. (posted-to
  6484. `((Newsgroups . ,posted-to)))
  6485. (t
  6486. `((Newsgroups . ,newsgroups))))
  6487. ,@(and distribution (list (cons 'Distribution distribution)))
  6488. ,@(when (and mct
  6489. (not (or (equal (downcase mct) "never")
  6490. (equal (downcase mct) "nobody"))))
  6491. (list (cons 'Cc (if (or (equal (downcase mct) "always")
  6492. (equal (downcase mct) "poster"))
  6493. (or mrt reply-to from "")
  6494. mct)))))
  6495. cur)))
  6496. (defun message-is-yours-p ()
  6497. "Non-nil means current article is yours.
  6498. If you have added 'cancel-messages to `message-shoot-gnksa-feet', all articles
  6499. are yours except those that have Cancel-Lock header not belonging to you.
  6500. Instead of shooting GNKSA feet, you should modify `message-alternative-emails'
  6501. regexp to match all of yours addresses."
  6502. ;; Canlock-logic as suggested by Per Abrahamsen
  6503. ;; <abraham@dina.kvl.dk>
  6504. ;;
  6505. ;; IF article has cancel-lock THEN
  6506. ;; IF we can verify it THEN
  6507. ;; issue cancel
  6508. ;; ELSE
  6509. ;; error: cancellock: article is not yours
  6510. ;; ELSE
  6511. ;; Use old rules, comparing sender...
  6512. (save-excursion
  6513. (save-restriction
  6514. (message-narrow-to-head-1)
  6515. (if (and (message-fetch-field "Cancel-Lock")
  6516. (message-gnksa-enable-p 'canlock-verify))
  6517. (if (null (canlock-verify))
  6518. t
  6519. (error "Failed to verify Cancel-lock: This article is not yours"))
  6520. (let (sender from)
  6521. (or
  6522. (message-gnksa-enable-p 'cancel-messages)
  6523. (and (setq sender (message-fetch-field "sender"))
  6524. (string-equal (downcase sender)
  6525. (downcase (message-make-sender))))
  6526. ;; Email address in From field equals to our address
  6527. (and (setq from (message-fetch-field "from"))
  6528. (string-equal
  6529. (downcase (car (mail-header-parse-address from)))
  6530. (downcase (car (mail-header-parse-address
  6531. (message-make-from))))))
  6532. ;; Email address in From field matches
  6533. ;; 'message-alternative-emails' regexp
  6534. (and from
  6535. message-alternative-emails
  6536. (string-match
  6537. message-alternative-emails
  6538. (car (mail-header-parse-address from))))))))))
  6539. ;;;###autoload
  6540. (defun message-cancel-news (&optional arg)
  6541. "Cancel an article you posted.
  6542. If ARG, allow editing of the cancellation message."
  6543. (interactive "P")
  6544. (unless (message-news-p)
  6545. (error "This is not a news article; canceling is impossible"))
  6546. (let (from newsgroups message-id distribution buf)
  6547. (save-excursion
  6548. ;; Get header info from original article.
  6549. (save-restriction
  6550. (message-narrow-to-head-1)
  6551. (setq from (message-fetch-field "from")
  6552. newsgroups (message-fetch-field "newsgroups")
  6553. message-id (message-fetch-field "message-id" t)
  6554. distribution (message-fetch-field "distribution")))
  6555. ;; Make sure that this article was written by the user.
  6556. (unless (message-is-yours-p)
  6557. (error "This article is not yours"))
  6558. (when (yes-or-no-p "Do you really want to cancel this article? ")
  6559. ;; Make control message.
  6560. (if arg
  6561. (message-news)
  6562. (setq buf (set-buffer (get-buffer-create " *message cancel*"))))
  6563. (erase-buffer)
  6564. (insert "Newsgroups: " newsgroups "\n"
  6565. "From: " from "\n"
  6566. "Subject: cmsg cancel " message-id "\n"
  6567. "Control: cancel " message-id "\n"
  6568. (if distribution
  6569. (concat "Distribution: " distribution "\n")
  6570. "")
  6571. mail-header-separator "\n"
  6572. message-cancel-message)
  6573. (run-hooks 'message-cancel-hook)
  6574. (unless arg
  6575. (message "Canceling your article...")
  6576. (if (let ((message-syntax-checks
  6577. 'dont-check-for-anything-just-trust-me))
  6578. (funcall message-send-news-function))
  6579. (message "Canceling your article...done"))
  6580. (kill-buffer buf))))))
  6581. ;;;###autoload
  6582. (defun message-supersede ()
  6583. "Start composing a message to supersede the current message.
  6584. This is done simply by taking the old article and adding a Supersedes
  6585. header line with the old Message-ID."
  6586. (interactive)
  6587. (let ((cur (current-buffer)))
  6588. ;; Check whether the user owns the article that is to be superseded.
  6589. (unless (message-is-yours-p)
  6590. (error "This article is not yours"))
  6591. ;; Get a normal message buffer.
  6592. (message-pop-to-buffer (message-buffer-name "supersede"))
  6593. (insert-buffer-substring cur)
  6594. (mime-to-mml)
  6595. (message-narrow-to-head-1)
  6596. ;; Remove unwanted headers.
  6597. (when message-ignored-supersedes-headers
  6598. (message-remove-header message-ignored-supersedes-headers t))
  6599. (goto-char (point-min))
  6600. (if (not (re-search-forward "^Message-ID: " nil t))
  6601. (error "No Message-ID in this article")
  6602. (replace-match "Supersedes: " t t))
  6603. (goto-char (point-max))
  6604. (insert mail-header-separator)
  6605. (widen)
  6606. (forward-line 1)))
  6607. ;;;###autoload
  6608. (defun message-recover ()
  6609. "Reread contents of current buffer from its last auto-save file."
  6610. (interactive)
  6611. (let ((file-name (make-auto-save-file-name)))
  6612. (cond ((save-window-excursion
  6613. (with-output-to-temp-buffer "*Directory*"
  6614. (with-current-buffer standard-output
  6615. (fundamental-mode)) ; for Emacs 20.4+
  6616. (buffer-disable-undo standard-output)
  6617. (let ((default-directory "/"))
  6618. (call-process
  6619. "ls" nil standard-output nil "-l" file-name)))
  6620. (yes-or-no-p (format "Recover auto save file %s? " file-name)))
  6621. (let ((buffer-read-only nil))
  6622. (erase-buffer)
  6623. (insert-file-contents file-name nil)))
  6624. (t (error "message-recover cancelled")))))
  6625. ;;; Washing Subject:
  6626. (defun message-wash-subject (subject)
  6627. "Remove junk like \"Re:\", \"(fwd)\", etc. added to subject string SUBJECT.
  6628. Previous forwarders, repliers, etc. may add it."
  6629. (with-temp-buffer
  6630. (insert subject)
  6631. (goto-char (point-min))
  6632. ;; strip Re/Fwd stuff off the beginning
  6633. (while (re-search-forward
  6634. "\\([Rr][Ee]:\\|[Ff][Ww][Dd]\\(\\[[0-9]*\\]\\)?:\\|[Ff][Ww]:\\)" nil t)
  6635. (replace-match ""))
  6636. ;; and gnus-style forwards [foo@bar.com] subject
  6637. (goto-char (point-min))
  6638. (while (re-search-forward "\\[[^ \t]*\\(@\\|\\.\\)[^ \t]*\\]" nil t)
  6639. (replace-match ""))
  6640. ;; and off the end
  6641. (goto-char (point-max))
  6642. (while (re-search-backward "([Ff][Ww][Dd])" nil t)
  6643. (replace-match ""))
  6644. ;; and finally, any whitespace that was left-over
  6645. (goto-char (point-min))
  6646. (while (re-search-forward "^[ \t]+" nil t)
  6647. (replace-match ""))
  6648. (goto-char (point-max))
  6649. (while (re-search-backward "[ \t]+$" nil t)
  6650. (replace-match ""))
  6651. (buffer-string)))
  6652. ;;; Forwarding messages.
  6653. (defvar message-forward-decoded-p nil
  6654. "Non-nil means the original message is decoded.")
  6655. (defun message-forward-subject-name-subject (subject)
  6656. "Generate a SUBJECT for a forwarded message.
  6657. The form is: [Source] Subject, where if the original message was mail,
  6658. Source is the name of the sender, and if the original message was
  6659. news, Source is the list of newsgroups is was posted to."
  6660. (let* ((group (message-fetch-field "newsgroups"))
  6661. (from (message-fetch-field "from"))
  6662. (prefix
  6663. (if group
  6664. (gnus-group-decoded-name group)
  6665. (or (and from (or
  6666. (car (gnus-extract-address-components from))
  6667. (cadr (gnus-extract-address-components from))))
  6668. "(nowhere)"))))
  6669. (concat "["
  6670. (if message-forward-decoded-p
  6671. prefix
  6672. (mail-decode-encoded-word-string prefix))
  6673. "] " subject)))
  6674. (defun message-forward-subject-author-subject (subject)
  6675. "Generate a SUBJECT for a forwarded message.
  6676. The form is: [Source] Subject, where if the original message was mail,
  6677. Source is the sender, and if the original message was news, Source is
  6678. the list of newsgroups is was posted to."
  6679. (let* ((group (message-fetch-field "newsgroups"))
  6680. (prefix
  6681. (if group
  6682. (gnus-group-decoded-name group)
  6683. (or (message-fetch-field "from")
  6684. "(nowhere)"))))
  6685. (concat "["
  6686. (if message-forward-decoded-p
  6687. prefix
  6688. (mail-decode-encoded-word-string prefix))
  6689. "] " subject)))
  6690. (defun message-forward-subject-fwd (subject)
  6691. "Generate a SUBJECT for a forwarded message.
  6692. The form is: Fwd: Subject, where Subject is the original subject of
  6693. the message."
  6694. (if (string-match "^Fwd: " subject)
  6695. subject
  6696. (concat "Fwd: " subject)))
  6697. (defun message-make-forward-subject ()
  6698. "Return a Subject header suitable for the message in the current buffer."
  6699. (save-excursion
  6700. (save-restriction
  6701. (message-narrow-to-head-1)
  6702. (let ((funcs message-make-forward-subject-function)
  6703. (subject (message-fetch-field "Subject")))
  6704. (setq subject
  6705. (if subject
  6706. (if message-forward-decoded-p
  6707. subject
  6708. (mail-decode-encoded-word-string subject))
  6709. ""))
  6710. (when message-wash-forwarded-subjects
  6711. (setq subject (message-wash-subject subject)))
  6712. ;; Make sure funcs is a list.
  6713. (and funcs
  6714. (not (listp funcs))
  6715. (setq funcs (list funcs)))
  6716. ;; Apply funcs in order, passing subject generated by previous
  6717. ;; func to the next one.
  6718. (dolist (func funcs)
  6719. (when (functionp func)
  6720. (setq subject (funcall func subject))))
  6721. subject))))
  6722. (defvar gnus-article-decoded-p)
  6723. ;;;###autoload
  6724. (defun message-forward (&optional news digest)
  6725. "Forward the current message via mail.
  6726. Optional NEWS will use news to forward instead of mail.
  6727. Optional DIGEST will use digest to forward."
  6728. (interactive "P")
  6729. (let* ((cur (current-buffer))
  6730. (message-forward-decoded-p
  6731. (if (local-variable-p 'gnus-article-decoded-p (current-buffer))
  6732. gnus-article-decoded-p ;; In an article buffer.
  6733. message-forward-decoded-p))
  6734. (subject (message-make-forward-subject)))
  6735. (if news
  6736. (message-news nil subject)
  6737. (message-mail nil subject))
  6738. (message-forward-make-body cur digest)))
  6739. (defun message-forward-make-body-plain (forward-buffer)
  6740. (insert
  6741. "\n-------------------- Start of forwarded message --------------------\n")
  6742. (let ((b (point))
  6743. (contents (with-current-buffer forward-buffer (buffer-string)))
  6744. e)
  6745. (unless (featurep 'xemacs)
  6746. (unless (mm-multibyte-string-p contents)
  6747. (error "Attempt to insert unibyte string from the buffer \"%s\"\
  6748. to the multibyte buffer \"%s\""
  6749. (if (bufferp forward-buffer)
  6750. (buffer-name forward-buffer)
  6751. forward-buffer)
  6752. (buffer-name))))
  6753. (insert (mm-with-multibyte-buffer
  6754. (insert contents)
  6755. (mime-to-mml)
  6756. (goto-char (point-min))
  6757. (when (looking-at "From ")
  6758. (replace-match "X-From-Line: "))
  6759. (buffer-string)))
  6760. (unless (bolp) (insert "\n"))
  6761. (setq e (point))
  6762. (insert
  6763. "-------------------- End of forwarded message --------------------\n")
  6764. (message-remove-ignored-headers b e)))
  6765. (defun message-remove-ignored-headers (b e)
  6766. (when message-forward-ignored-headers
  6767. (save-restriction
  6768. (narrow-to-region b e)
  6769. (goto-char b)
  6770. (narrow-to-region (point)
  6771. (or (search-forward "\n\n" nil t) (point)))
  6772. (let ((ignored (if (stringp message-forward-ignored-headers)
  6773. (list message-forward-ignored-headers)
  6774. message-forward-ignored-headers)))
  6775. (dolist (elem ignored)
  6776. (message-remove-header elem t))))))
  6777. (defun message-forward-make-body-mime (forward-buffer)
  6778. (let ((b (point)))
  6779. (insert "\n\n<#part type=message/rfc822 disposition=inline raw=t>\n")
  6780. (save-restriction
  6781. (narrow-to-region (point) (point))
  6782. (mml-insert-buffer forward-buffer)
  6783. (goto-char (point-min))
  6784. (when (looking-at "From ")
  6785. (replace-match "X-From-Line: "))
  6786. (goto-char (point-max)))
  6787. (insert "<#/part>\n")
  6788. ;; Consider there is no illegible text.
  6789. (add-text-properties
  6790. b (point)
  6791. `(no-illegible-text t rear-nonsticky t start-open t))))
  6792. (defun message-forward-make-body-mml (forward-buffer)
  6793. (insert "\n\n<#mml type=message/rfc822 disposition=inline>\n")
  6794. (let ((b (point)) e)
  6795. (if (not message-forward-decoded-p)
  6796. (let ((contents (with-current-buffer forward-buffer (buffer-string))))
  6797. (unless (featurep 'xemacs)
  6798. (unless (mm-multibyte-string-p contents)
  6799. (error "Attempt to insert unibyte string from the buffer \"%s\"\
  6800. to the multibyte buffer \"%s\""
  6801. (if (bufferp forward-buffer)
  6802. (buffer-name forward-buffer)
  6803. forward-buffer)
  6804. (buffer-name))))
  6805. (insert (mm-with-multibyte-buffer
  6806. (insert contents)
  6807. (mime-to-mml)
  6808. (goto-char (point-min))
  6809. (when (looking-at "From ")
  6810. (replace-match "X-From-Line: "))
  6811. (buffer-string))))
  6812. (save-restriction
  6813. (narrow-to-region (point) (point))
  6814. (mml-insert-buffer forward-buffer)
  6815. (goto-char (point-min))
  6816. (when (looking-at "From ")
  6817. (replace-match "X-From-Line: "))
  6818. (goto-char (point-max))))
  6819. (setq e (point))
  6820. (insert "<#/mml>\n")
  6821. (when (and (not message-forward-decoded-p)
  6822. message-forward-ignored-headers)
  6823. (message-remove-ignored-headers b e))))
  6824. (defun message-forward-make-body-digest-plain (forward-buffer)
  6825. (insert
  6826. "\n-------------------- Start of forwarded message --------------------\n")
  6827. (mml-insert-buffer forward-buffer)
  6828. (insert
  6829. "\n-------------------- End of forwarded message --------------------\n"))
  6830. (defun message-forward-make-body-digest-mime (forward-buffer)
  6831. (insert "\n<#multipart type=digest>\n")
  6832. (let ((b (point)) e)
  6833. (insert-buffer-substring forward-buffer)
  6834. (setq e (point))
  6835. (insert "<#/multipart>\n")
  6836. (save-restriction
  6837. (narrow-to-region b e)
  6838. (goto-char b)
  6839. (narrow-to-region (point)
  6840. (or (search-forward "\n\n" nil t) (point)))
  6841. (delete-region (point-min) (point-max)))))
  6842. (defun message-forward-make-body-digest (forward-buffer)
  6843. (if message-forward-as-mime
  6844. (message-forward-make-body-digest-mime forward-buffer)
  6845. (message-forward-make-body-digest-plain forward-buffer)))
  6846. (autoload 'mm-uu-dissect-text-parts "mm-uu")
  6847. (autoload 'mm-uu-dissect "mm-uu")
  6848. (defun message-signed-or-encrypted-p (&optional dont-emulate-mime handles)
  6849. "Say whether the current buffer contains signed or encrypted message.
  6850. If DONT-EMULATE-MIME is nil, this function does the MIME emulation on
  6851. messages that don't conform to PGP/MIME described in RFC2015. HANDLES
  6852. is for the internal use."
  6853. (unless handles
  6854. (let ((mm-decrypt-option 'never)
  6855. (mm-verify-option 'never))
  6856. (if (setq handles (mm-dissect-buffer nil t))
  6857. (unless dont-emulate-mime
  6858. (mm-uu-dissect-text-parts handles))
  6859. (unless dont-emulate-mime
  6860. (setq handles (mm-uu-dissect))))))
  6861. ;; Check text/plain message in which there is a signed or encrypted
  6862. ;; body that has been encoded by B or Q.
  6863. (unless (or handles dont-emulate-mime)
  6864. (let ((cur (current-buffer))
  6865. (mm-decrypt-option 'never)
  6866. (mm-verify-option 'never))
  6867. (with-temp-buffer
  6868. (insert-buffer-substring cur)
  6869. (when (setq handles (mm-dissect-buffer t t))
  6870. (if (and (bufferp (car handles))
  6871. (equal (mm-handle-media-type handles) "text/plain"))
  6872. (progn
  6873. (erase-buffer)
  6874. (insert-buffer-substring (car handles))
  6875. (mm-decode-content-transfer-encoding
  6876. (mm-handle-encoding handles))
  6877. (mm-destroy-parts handles)
  6878. (setq handles (mm-uu-dissect)))
  6879. (mm-destroy-parts handles)
  6880. (setq handles nil))))))
  6881. (when handles
  6882. (prog1
  6883. (catch 'found
  6884. (dolist (handle (if (stringp (car handles))
  6885. (if (member (car handles)
  6886. '("multipart/signed"
  6887. "multipart/encrypted"))
  6888. (throw 'found t)
  6889. (cdr handles))
  6890. (list handles)))
  6891. (if (stringp (car handle))
  6892. (when (message-signed-or-encrypted-p dont-emulate-mime handle)
  6893. (throw 'found t))
  6894. (when (and (bufferp (car handle))
  6895. (equal (mm-handle-media-type handle)
  6896. "message/rfc822"))
  6897. (with-current-buffer (mm-handle-buffer handle)
  6898. (when (message-signed-or-encrypted-p dont-emulate-mime)
  6899. (throw 'found t)))))))
  6900. (mm-destroy-parts handles))))
  6901. ;;;###autoload
  6902. (defun message-forward-make-body (forward-buffer &optional digest)
  6903. ;; Put point where we want it before inserting the forwarded
  6904. ;; message.
  6905. (if message-forward-before-signature
  6906. (message-goto-body)
  6907. (goto-char (point-max)))
  6908. (if digest
  6909. (message-forward-make-body-digest forward-buffer)
  6910. (if message-forward-as-mime
  6911. (if (and message-forward-show-mml
  6912. (not (and (eq message-forward-show-mml 'best)
  6913. ;; Use the raw form in the body if it contains
  6914. ;; signed or encrypted message so as not to be
  6915. ;; destroyed by re-encoding.
  6916. (with-current-buffer forward-buffer
  6917. (condition-case nil
  6918. (message-signed-or-encrypted-p)
  6919. (error t))))))
  6920. (message-forward-make-body-mml forward-buffer)
  6921. (message-forward-make-body-mime forward-buffer))
  6922. (message-forward-make-body-plain forward-buffer)))
  6923. (message-position-point))
  6924. (declare-function rmail-toggle-header "rmail" (&optional arg))
  6925. ;;;###autoload
  6926. (defun message-forward-rmail-make-body (forward-buffer)
  6927. (save-window-excursion
  6928. (set-buffer forward-buffer)
  6929. (if (rmail-msg-is-pruned)
  6930. (if (fboundp 'rmail-msg-restore-non-pruned-header)
  6931. (rmail-msg-restore-non-pruned-header) ; Emacs 22
  6932. (rmail-toggle-header 0)))) ; Emacs 23
  6933. (message-forward-make-body forward-buffer))
  6934. ;; Fixme: Should have defcustom.
  6935. ;;;###autoload
  6936. (defun message-insinuate-rmail ()
  6937. "Let RMAIL use message to forward."
  6938. (interactive)
  6939. (setq rmail-enable-mime-composing t)
  6940. (setq rmail-insert-mime-forwarded-message-function
  6941. 'message-forward-rmail-make-body))
  6942. (defvar message-inhibit-body-encoding nil)
  6943. ;;;###autoload
  6944. (defun message-resend (address)
  6945. "Resend the current article to ADDRESS."
  6946. (interactive
  6947. (list (message-read-from-minibuffer "Resend message to: ")))
  6948. (message "Resending message to %s..." address)
  6949. (save-excursion
  6950. (let ((cur (current-buffer))
  6951. beg)
  6952. ;; We first set up a normal mail buffer.
  6953. (unless (message-mail-user-agent)
  6954. (set-buffer (get-buffer-create " *message resend*"))
  6955. (let ((inhibit-read-only t))
  6956. (erase-buffer)))
  6957. (let ((message-this-is-mail t)
  6958. message-generate-hashcash
  6959. message-setup-hook)
  6960. (message-setup `((To . ,address))))
  6961. ;; Insert our usual headers.
  6962. (message-generate-headers '(From Date To Message-ID))
  6963. (message-narrow-to-headers)
  6964. ;; Remove X-Draft-From header etc.
  6965. (message-remove-header message-ignored-mail-headers t)
  6966. ;; Rename them all to "Resent-*".
  6967. (goto-char (point-min))
  6968. (while (re-search-forward "^[A-Za-z]" nil t)
  6969. (forward-char -1)
  6970. (insert "Resent-"))
  6971. (widen)
  6972. (forward-line)
  6973. (let ((inhibit-read-only t))
  6974. (delete-region (point) (point-max)))
  6975. (setq beg (point))
  6976. ;; Insert the message to be resent.
  6977. (insert-buffer-substring cur)
  6978. (goto-char (point-min))
  6979. (search-forward "\n\n")
  6980. (forward-char -1)
  6981. (save-restriction
  6982. (narrow-to-region beg (point))
  6983. (message-remove-header message-ignored-resent-headers t)
  6984. (goto-char (point-max)))
  6985. (insert mail-header-separator)
  6986. ;; Rename all old ("Also-")Resent headers.
  6987. (while (re-search-backward "^\\(Also-\\)*Resent-" beg t)
  6988. (beginning-of-line)
  6989. (insert "Also-"))
  6990. ;; Quote any "From " lines at the beginning.
  6991. (goto-char beg)
  6992. (when (looking-at "From ")
  6993. (replace-match "X-From-Line: "))
  6994. ;; Send it.
  6995. (let ((message-inhibit-body-encoding
  6996. ;; Don't do any further encoding if it looks like the
  6997. ;; message has already been encoded.
  6998. (let ((case-fold-search t))
  6999. (re-search-forward "^mime-version:" nil t)))
  7000. (message-inhibit-ecomplete t)
  7001. message-required-mail-headers
  7002. message-generate-hashcash
  7003. rfc2047-encode-encoded-words)
  7004. (message-send-mail))
  7005. (kill-buffer (current-buffer)))
  7006. (message "Resending message to %s...done" address)))
  7007. ;;;###autoload
  7008. (defun message-bounce ()
  7009. "Re-mail the current message.
  7010. This only makes sense if the current message is a bounce message that
  7011. contains some mail you have written which has been bounced back to
  7012. you."
  7013. (interactive)
  7014. (let ((handles (mm-dissect-buffer t))
  7015. boundary)
  7016. (message-pop-to-buffer (message-buffer-name "bounce"))
  7017. (if (stringp (car handles))
  7018. ;; This is a MIME bounce.
  7019. (mm-insert-part (car (last handles)))
  7020. ;; This is a non-MIME bounce, so we try to remove things
  7021. ;; manually.
  7022. (mm-insert-part handles)
  7023. (undo-boundary)
  7024. (goto-char (point-min))
  7025. (re-search-forward "\n\n+" nil t)
  7026. (setq boundary (point))
  7027. ;; We remove everything before the bounced mail.
  7028. (if (or (re-search-forward message-unsent-separator nil t)
  7029. (progn
  7030. (search-forward "\n\n" nil 'move)
  7031. (re-search-backward "^Return-Path:.*\n" boundary t)))
  7032. (progn
  7033. (forward-line 1)
  7034. (delete-region (point-min)
  7035. (if (re-search-forward "^[^ \n\t]+:" nil t)
  7036. (match-beginning 0)
  7037. (point))))
  7038. (goto-char boundary)
  7039. (when (re-search-backward "^.?From .*\n" nil t)
  7040. (delete-region (match-beginning 0) (match-end 0)))))
  7041. (mime-to-mml)
  7042. (save-restriction
  7043. (message-narrow-to-head-1)
  7044. (message-remove-header message-ignored-bounced-headers t)
  7045. (goto-char (point-max))
  7046. (insert mail-header-separator))
  7047. (message-position-point)))
  7048. ;;;
  7049. ;;; Interactive entry points for new message buffers.
  7050. ;;;
  7051. ;;;###autoload
  7052. (defun message-mail-other-window (&optional to subject)
  7053. "Like `message-mail' command, but display mail buffer in another window."
  7054. (interactive)
  7055. (unless (message-mail-user-agent)
  7056. (message-pop-to-buffer (message-buffer-name "mail" to)
  7057. 'switch-to-buffer-other-window))
  7058. (let ((message-this-is-mail t))
  7059. (message-setup `((To . ,(or to "")) (Subject . ,(or subject "")))
  7060. nil nil nil 'switch-to-buffer-other-window)))
  7061. ;;;###autoload
  7062. (defun message-mail-other-frame (&optional to subject)
  7063. "Like `message-mail' command, but display mail buffer in another frame."
  7064. (interactive)
  7065. (unless (message-mail-user-agent)
  7066. (message-pop-to-buffer (message-buffer-name "mail" to)
  7067. 'switch-to-buffer-other-frame))
  7068. (let ((message-this-is-mail t))
  7069. (message-setup `((To . ,(or to "")) (Subject . ,(or subject "")))
  7070. nil nil nil 'switch-to-buffer-other-frame)))
  7071. ;;;###autoload
  7072. (defun message-news-other-window (&optional newsgroups subject)
  7073. "Start editing a news article to be sent."
  7074. (interactive)
  7075. (message-pop-to-buffer (message-buffer-name "posting" nil newsgroups)
  7076. 'switch-to-buffer-other-window)
  7077. (let ((message-this-is-news t))
  7078. (message-setup `((Newsgroups . ,(or newsgroups ""))
  7079. (Subject . ,(or subject ""))))))
  7080. ;;;###autoload
  7081. (defun message-news-other-frame (&optional newsgroups subject)
  7082. "Start editing a news article to be sent."
  7083. (interactive)
  7084. (message-pop-to-buffer (message-buffer-name "posting" nil newsgroups)
  7085. 'switch-to-buffer-other-frame)
  7086. (let ((message-this-is-news t))
  7087. (message-setup `((Newsgroups . ,(or newsgroups ""))
  7088. (Subject . ,(or subject ""))))))
  7089. ;;; underline.el
  7090. ;; This code should be moved to underline.el (from which it is stolen).
  7091. ;;;###autoload
  7092. (defun message-bold-region (start end)
  7093. "Bold all nonblank characters in the region.
  7094. Works by overstriking characters.
  7095. Called from program, takes two arguments START and END
  7096. which specify the range to operate on."
  7097. (interactive "r")
  7098. (save-excursion
  7099. (let ((end1 (make-marker)))
  7100. (move-marker end1 (max start end))
  7101. (goto-char (min start end))
  7102. (while (< (point) end1)
  7103. (or (looking-at "[_\^@- ]")
  7104. (insert (char-after) "\b"))
  7105. (forward-char 1)))))
  7106. ;;;###autoload
  7107. (defun message-unbold-region (start end)
  7108. "Remove all boldness (overstruck characters) in the region.
  7109. Called from program, takes two arguments START and END
  7110. which specify the range to operate on."
  7111. (interactive "r")
  7112. (save-excursion
  7113. (let ((end1 (make-marker)))
  7114. (move-marker end1 (max start end))
  7115. (goto-char (min start end))
  7116. (while (search-forward "\b" end1 t)
  7117. (if (eq (char-after) (char-after (- (point) 2)))
  7118. (delete-char -2))))))
  7119. (defun message-exchange-point-and-mark ()
  7120. "Exchange point and mark, but don't activate region if it was inactive."
  7121. (goto-char (prog1 (mark t)
  7122. (set-marker (mark-marker) (point)))))
  7123. (defalias 'message-make-overlay 'make-overlay)
  7124. (defalias 'message-delete-overlay 'delete-overlay)
  7125. (defalias 'message-overlay-put 'overlay-put)
  7126. (defun message-kill-all-overlays ()
  7127. (if (featurep 'xemacs)
  7128. (map-extents (lambda (extent ignore) (delete-extent extent)))
  7129. (mapcar #'delete-overlay (overlays-in (point-min) (point-max)))))
  7130. ;; Support for toolbar
  7131. (defvar tool-bar-mode)
  7132. ;; Note: The :set function in the `message-tool-bar*' variables will only
  7133. ;; affect _new_ message buffers. We might add a function that walks thru all
  7134. ;; message-mode buffers and force the update.
  7135. (defun message-tool-bar-update (&optional symbol value)
  7136. "Update message mode toolbar.
  7137. Setter function for custom variables."
  7138. (setq-default message-tool-bar-map nil)
  7139. (when symbol
  7140. ;; When used as ":set" function:
  7141. (set-default symbol value)))
  7142. (defcustom message-tool-bar (if (eq gmm-tool-bar-style 'gnome)
  7143. 'message-tool-bar-gnome
  7144. 'message-tool-bar-retro)
  7145. "Specifies the message mode tool bar.
  7146. It can be either a list or a symbol referring to a list. See
  7147. `gmm-tool-bar-from-list' for the format of the list. The
  7148. default key map is `message-mode-map'.
  7149. Pre-defined symbols include `message-tool-bar-gnome' and
  7150. `message-tool-bar-retro'."
  7151. :type '(repeat gmm-tool-bar-list-item)
  7152. :type '(choice (const :tag "GNOME style" message-tool-bar-gnome)
  7153. (const :tag "Retro look" message-tool-bar-retro)
  7154. (repeat :tag "User defined list" gmm-tool-bar-item)
  7155. (symbol))
  7156. :version "23.1" ;; No Gnus
  7157. :initialize 'custom-initialize-default
  7158. :set 'message-tool-bar-update
  7159. :group 'message)
  7160. (defcustom message-tool-bar-gnome
  7161. '((ispell-message "spell" nil
  7162. :vert-only t
  7163. :visible (or (not (boundp 'flyspell-mode))
  7164. (not flyspell-mode)))
  7165. (flyspell-buffer "spell" t
  7166. :vert-only t
  7167. :visible (and (boundp 'flyspell-mode)
  7168. flyspell-mode)
  7169. :help "Flyspell whole buffer")
  7170. (message-send-and-exit "mail/send" t :label "Send")
  7171. (message-dont-send "mail/save-draft")
  7172. (mml-attach-file "attach" mml-mode-map :vert-only t)
  7173. (mml-preview "mail/preview" mml-mode-map)
  7174. (mml-secure-message-sign-encrypt "lock" mml-mode-map :visible nil)
  7175. (message-insert-importance-high "important" nil :visible nil)
  7176. (message-insert-importance-low "unimportant" nil :visible nil)
  7177. (message-insert-disposition-notification-to "receipt" nil :visible nil))
  7178. "List of items for the message tool bar (GNOME style).
  7179. See `gmm-tool-bar-from-list' for details on the format of the list."
  7180. :type '(repeat gmm-tool-bar-item)
  7181. :version "23.1" ;; No Gnus
  7182. :initialize 'custom-initialize-default
  7183. :set 'message-tool-bar-update
  7184. :group 'message)
  7185. (defcustom message-tool-bar-retro
  7186. '(;; Old Emacs 21 icon for consistency.
  7187. (message-send-and-exit "gnus/mail-send")
  7188. (message-kill-buffer "close")
  7189. (message-dont-send "cancel")
  7190. (mml-attach-file "attach" mml-mode-map)
  7191. (ispell-message "spell")
  7192. (mml-preview "preview" mml-mode-map)
  7193. (message-insert-importance-high "gnus/important")
  7194. (message-insert-importance-low "gnus/unimportant")
  7195. (message-insert-disposition-notification-to "gnus/receipt"))
  7196. "List of items for the message tool bar (retro style).
  7197. See `gmm-tool-bar-from-list' for details on the format of the list."
  7198. :type '(repeat gmm-tool-bar-item)
  7199. :version "23.1" ;; No Gnus
  7200. :initialize 'custom-initialize-default
  7201. :set 'message-tool-bar-update
  7202. :group 'message)
  7203. (defcustom message-tool-bar-zap-list
  7204. '(new-file open-file dired kill-buffer write-file
  7205. print-buffer customize help)
  7206. "List of icon items from the global tool bar.
  7207. These items are not displayed on the message mode tool bar.
  7208. See `gmm-tool-bar-from-list' for the format of the list."
  7209. :type 'gmm-tool-bar-zap-list
  7210. :version "23.1" ;; No Gnus
  7211. :initialize 'custom-initialize-default
  7212. :set 'message-tool-bar-update
  7213. :group 'message)
  7214. (defvar image-load-path)
  7215. (defun message-make-tool-bar (&optional force)
  7216. "Make a message mode tool bar from `message-tool-bar-list'.
  7217. When FORCE, rebuild the tool bar."
  7218. (when (and (not (featurep 'xemacs))
  7219. (boundp 'tool-bar-mode)
  7220. tool-bar-mode
  7221. (or (not message-tool-bar-map) force))
  7222. (setq message-tool-bar-map
  7223. (let* ((load-path
  7224. (gmm-image-load-path-for-library "message"
  7225. "mail/save-draft.xpm"
  7226. nil t))
  7227. (image-load-path (cons (car load-path)
  7228. (when (boundp 'image-load-path)
  7229. image-load-path))))
  7230. (gmm-tool-bar-from-list message-tool-bar
  7231. message-tool-bar-zap-list
  7232. 'message-mode-map))))
  7233. message-tool-bar-map)
  7234. ;;; Group name completion.
  7235. (defcustom message-newgroups-header-regexp
  7236. "^\\(Newsgroups\\|Followup-To\\|Posted-To\\|Gcc\\):"
  7237. "Regexp that match headers that lists groups."
  7238. :group 'message
  7239. :type 'regexp)
  7240. (defcustom message-completion-alist
  7241. (list (cons message-newgroups-header-regexp 'message-expand-group)
  7242. '("^\\(Resent-\\)?\\(To\\|B?Cc\\):" . message-expand-name)
  7243. '("^\\(Reply-To\\|From\\|Mail-Followup-To\\|Mail-Copies-To\\):"
  7244. . message-expand-name)
  7245. '("^\\(Disposition-Notification-To\\|Return-Receipt-To\\):"
  7246. . message-expand-name))
  7247. "Alist of (RE . FUN). Use FUN for completion on header lines matching RE."
  7248. :version "22.1"
  7249. :group 'message
  7250. :type '(alist :key-type regexp :value-type function))
  7251. (defcustom message-expand-name-databases
  7252. '(bbdb eudc)
  7253. "List of databases to try for name completion (`message-expand-name').
  7254. Each element is a symbol and can be `bbdb' or `eudc'."
  7255. :group 'message
  7256. :type '(set (const bbdb) (const eudc)))
  7257. (defcustom message-tab-body-function nil
  7258. "*Function to execute when `message-tab' (TAB) is executed in the body.
  7259. If nil, the function bound in `text-mode-map' or `global-map' is executed."
  7260. :version "22.1"
  7261. :group 'message
  7262. :link '(custom-manual "(message)Various Commands")
  7263. :type '(choice (const nil)
  7264. function))
  7265. (declare-function mail-abbrev-in-expansion-header-p "mailabbrev" ())
  7266. (defun message-tab ()
  7267. "Complete names according to `message-completion-alist'.
  7268. Execute function specified by `message-tab-body-function' when not in
  7269. those headers."
  7270. (interactive)
  7271. (cond
  7272. ((if (and (boundp 'completion-fail-discreetly)
  7273. (fboundp 'completion-at-point))
  7274. (let ((completion-fail-discreetly t)) (completion-at-point))
  7275. (funcall (or (message-completion-function) #'ignore)))
  7276. ;; Completion was performed; nothing else to do.
  7277. nil)
  7278. (message-tab-body-function (funcall message-tab-body-function))
  7279. (t (funcall (or (lookup-key text-mode-map "\t")
  7280. (lookup-key global-map "\t")
  7281. 'indent-relative)))))
  7282. (defvar mail-abbrev-mode-regexp)
  7283. (defun message-completion-function ()
  7284. (let ((alist message-completion-alist))
  7285. (while (and alist
  7286. (let ((mail-abbrev-mode-regexp (caar alist)))
  7287. (not (mail-abbrev-in-expansion-header-p))))
  7288. (setq alist (cdr alist)))
  7289. (when (cdar alist)
  7290. (lexical-let ((fun (cdar alist)))
  7291. ;; Even if completion fails, return a non-nil value, so as to avoid
  7292. ;; falling back to message-tab-body-function.
  7293. (lambda () (funcall fun) 'completion-attempted)))))
  7294. (eval-and-compile
  7295. (condition-case nil
  7296. (with-temp-buffer
  7297. (let ((standard-output (current-buffer)))
  7298. (eval '(display-completion-list nil "")))
  7299. (defalias 'message-display-completion-list 'display-completion-list))
  7300. (error ;; Don't use `wrong-number-of-arguments' here because of XEmacs.
  7301. (defun message-display-completion-list (completions &optional ignore)
  7302. "Display the list of completions, COMPLETIONS, using `standard-output'."
  7303. (display-completion-list completions)))))
  7304. (defun message-expand-group ()
  7305. "Expand the group name under point."
  7306. (let* ((b (save-excursion
  7307. (save-restriction
  7308. (narrow-to-region
  7309. (save-excursion
  7310. (beginning-of-line)
  7311. (skip-chars-forward "^:")
  7312. (1+ (point)))
  7313. (point))
  7314. (skip-chars-backward "^, \t\n") (point))))
  7315. (completion-ignore-case t)
  7316. (e (progn (skip-chars-forward "^,\t\n ") (point)))
  7317. (hashtb (and (boundp 'gnus-active-hashtb) gnus-active-hashtb)))
  7318. (message-completion-in-region e b hashtb)))
  7319. (defalias 'message-completion-in-region
  7320. (if (fboundp 'completion-in-region)
  7321. 'completion-in-region
  7322. (lambda (e b hashtb)
  7323. (let* ((string (buffer-substring b e))
  7324. (completions (all-completions string hashtb))
  7325. comp)
  7326. (delete-region b (point))
  7327. (cond
  7328. ((= (length completions) 1)
  7329. (if (string= (car completions) string)
  7330. (progn
  7331. (insert string)
  7332. (message "Only matching group"))
  7333. (insert (car completions))))
  7334. ((and (setq comp (try-completion string hashtb))
  7335. (not (string= comp string)))
  7336. (insert comp))
  7337. (t
  7338. (insert string)
  7339. (if (not comp)
  7340. (message "No matching groups")
  7341. (save-selected-window
  7342. (pop-to-buffer "*Completions*")
  7343. (buffer-disable-undo)
  7344. (let ((buffer-read-only nil))
  7345. (erase-buffer)
  7346. (let ((standard-output (current-buffer)))
  7347. (message-display-completion-list (sort completions 'string<)
  7348. string))
  7349. (setq buffer-read-only nil)
  7350. (goto-char (point-min))
  7351. (delete-region (point)
  7352. (progn (forward-line 3) (point))))))))))))
  7353. (defun message-expand-name ()
  7354. (cond ((and (memq 'eudc message-expand-name-databases)
  7355. (boundp 'eudc-protocol)
  7356. eudc-protocol)
  7357. (eudc-expand-inline))
  7358. ((and (memq 'bbdb message-expand-name-databases)
  7359. (fboundp 'bbdb-complete-name))
  7360. (let ((starttick (buffer-modified-tick)))
  7361. (or (bbdb-complete-name)
  7362. ;; Apparently, bbdb-complete-name can return nil even when
  7363. ;; completion took place. So let's double check the buffer was
  7364. ;; not modified.
  7365. (/= starttick (buffer-modified-tick)))))
  7366. (t
  7367. (expand-abbrev))))
  7368. ;;; Help stuff.
  7369. (defun message-talkative-question (ask question show &rest text)
  7370. "Call FUNCTION with argument QUESTION; optionally display TEXT... args.
  7371. If SHOW is non-nil, the arguments TEXT... are displayed in a temp buffer.
  7372. The following arguments may contain lists of values."
  7373. (if (and show
  7374. (setq text (message-flatten-list text)))
  7375. (save-window-excursion
  7376. (with-output-to-temp-buffer " *MESSAGE information message*"
  7377. (with-current-buffer " *MESSAGE information message*"
  7378. (fundamental-mode) ; for Emacs 20.4+
  7379. (mapc 'princ text)
  7380. (goto-char (point-min))))
  7381. (funcall ask question))
  7382. (funcall ask question)))
  7383. (defun message-flatten-list (list)
  7384. "Return a new, flat list that contains all elements of LIST.
  7385. \(message-flatten-list '(1 (2 3 (4 5 (6))) 7))
  7386. => (1 2 3 4 5 6 7)"
  7387. (cond ((consp list)
  7388. (apply 'append (mapcar 'message-flatten-list list)))
  7389. (list
  7390. (list list))))
  7391. (defun message-generate-new-buffer-clone-locals (name &optional varstr)
  7392. "Create and return a buffer with name based on NAME using `generate-new-buffer'.
  7393. Then clone the local variables and values from the old buffer to the
  7394. new one, cloning only the locals having a substring matching the
  7395. regexp VARSTR."
  7396. (let ((oldbuf (current-buffer)))
  7397. (with-current-buffer (generate-new-buffer name)
  7398. (message-clone-locals oldbuf varstr)
  7399. (current-buffer))))
  7400. (defun message-clone-locals (buffer &optional varstr)
  7401. "Clone the local variables from BUFFER to the current buffer."
  7402. (let ((locals (with-current-buffer buffer (buffer-local-variables)))
  7403. (regexp "^gnus\\|^nn\\|^message\\|^sendmail\\|^smtp\\|^user-mail-address"))
  7404. (mapcar
  7405. (lambda (local)
  7406. (when (and (consp local)
  7407. (car local)
  7408. (string-match regexp (symbol-name (car local)))
  7409. (or (null varstr)
  7410. (string-match varstr (symbol-name (car local)))))
  7411. (ignore-errors
  7412. (set (make-local-variable (car local))
  7413. (cdr local)))))
  7414. locals)))
  7415. ;;;
  7416. ;;; MIME functions
  7417. ;;;
  7418. (defun message-encode-message-body ()
  7419. (unless message-inhibit-body-encoding
  7420. (let ((mail-parse-charset (or mail-parse-charset
  7421. message-default-charset))
  7422. (case-fold-search t)
  7423. lines content-type-p)
  7424. (message-goto-body)
  7425. (save-restriction
  7426. (narrow-to-region (point) (point-max))
  7427. (let ((new (mml-generate-mime)))
  7428. (when new
  7429. (delete-region (point-min) (point-max))
  7430. (insert new)
  7431. (goto-char (point-min))
  7432. (if (eq (aref new 0) ?\n)
  7433. (delete-char 1)
  7434. (search-forward "\n\n")
  7435. (setq lines (buffer-substring (point-min) (1- (point))))
  7436. (delete-region (point-min) (point))))))
  7437. (save-restriction
  7438. (message-narrow-to-headers-or-head)
  7439. (message-remove-header "Mime-Version")
  7440. (goto-char (point-max))
  7441. (insert "MIME-Version: 1.0\n")
  7442. (when lines
  7443. (insert lines))
  7444. (setq content-type-p
  7445. (or mml-boundary
  7446. (re-search-backward "^Content-Type:" nil t))))
  7447. (save-restriction
  7448. (message-narrow-to-headers-or-head)
  7449. (message-remove-first-header "Content-Type")
  7450. (message-remove-first-header "Content-Transfer-Encoding"))
  7451. ;; We always make sure that the message has a Content-Type
  7452. ;; header. This is because some broken MTAs and MUAs get
  7453. ;; awfully confused when confronted with a message with a
  7454. ;; MIME-Version header and without a Content-Type header. For
  7455. ;; instance, Solaris' /usr/bin/mail.
  7456. (unless content-type-p
  7457. (goto-char (point-min))
  7458. ;; For unknown reason, MIME-Version doesn't exist.
  7459. (when (re-search-forward "^MIME-Version:" nil t)
  7460. (forward-line 1)
  7461. (insert "Content-Type: text/plain; charset=us-ascii\n"))))))
  7462. (defun message-read-from-minibuffer (prompt &optional initial-contents)
  7463. "Read from the minibuffer while providing abbrev expansion."
  7464. (if (fboundp 'mail-abbrevs-setup)
  7465. (let ((minibuffer-setup-hook 'mail-abbrevs-setup)
  7466. (minibuffer-local-map message-minibuffer-local-map))
  7467. (flet ((mail-abbrev-in-expansion-header-p nil t))
  7468. (read-from-minibuffer prompt initial-contents)))
  7469. (let ((minibuffer-setup-hook 'mail-abbrev-minibuffer-setup-hook)
  7470. (minibuffer-local-map message-minibuffer-local-map))
  7471. (read-string prompt initial-contents))))
  7472. (defun message-use-alternative-email-as-from ()
  7473. "Set From field of the outgoing message to the first matching
  7474. address in `message-alternative-emails', looking at To, Cc and
  7475. From headers in the original article."
  7476. (require 'mail-utils)
  7477. (let* ((fields '("To" "Cc" "From"))
  7478. (emails
  7479. (split-string
  7480. (mail-strip-quoted-names
  7481. (mapconcat 'message-fetch-reply-field fields ","))
  7482. "[ \f\t\n\r\v,]+"))
  7483. email)
  7484. (while emails
  7485. (if (string-match message-alternative-emails (car emails))
  7486. (setq email (car emails)
  7487. emails nil))
  7488. (pop emails))
  7489. (unless (or (not email) (equal email user-mail-address))
  7490. (message-remove-header "From")
  7491. (goto-char (point-max))
  7492. (insert "From: " (let ((user-mail-address email)) (message-make-from))
  7493. "\n"))))
  7494. (defun message-options-get (symbol)
  7495. (cdr (assq symbol message-options)))
  7496. (defun message-options-set (symbol value)
  7497. (let ((the-cons (assq symbol message-options)))
  7498. (if the-cons
  7499. (if value
  7500. (setcdr the-cons value)
  7501. (setq message-options (delq the-cons message-options)))
  7502. (and value
  7503. (push (cons symbol value) message-options))))
  7504. value)
  7505. (defun message-options-set-recipient ()
  7506. (save-restriction
  7507. (message-narrow-to-headers-or-head)
  7508. (message-options-set 'message-sender
  7509. (mail-strip-quoted-names
  7510. (message-fetch-field "from")))
  7511. (message-options-set 'message-recipients
  7512. (mail-strip-quoted-names
  7513. (let ((to (message-fetch-field "to"))
  7514. (cc (message-fetch-field "cc"))
  7515. (bcc (message-fetch-field "bcc")))
  7516. (concat
  7517. (or to "")
  7518. (if (and to cc) ", ")
  7519. (or cc "")
  7520. (if (and (or to cc) bcc) ", ")
  7521. (or bcc "")))))))
  7522. (defun message-hide-headers ()
  7523. "Hide headers based on the `message-hidden-headers' variable."
  7524. (let ((regexps (if (stringp message-hidden-headers)
  7525. (list message-hidden-headers)
  7526. message-hidden-headers))
  7527. (inhibit-point-motion-hooks t)
  7528. (after-change-functions nil)
  7529. (end-of-headers (point-min)))
  7530. (when regexps
  7531. (save-excursion
  7532. (save-restriction
  7533. (message-narrow-to-headers)
  7534. (goto-char (point-min))
  7535. (while (not (eobp))
  7536. (if (not (message-hide-header-p regexps))
  7537. (message-next-header)
  7538. (let ((begin (point))
  7539. header header-len)
  7540. (message-next-header)
  7541. (setq header (buffer-substring begin (point))
  7542. header-len (- (point) begin))
  7543. (delete-region begin (point))
  7544. (goto-char end-of-headers)
  7545. (insert header)
  7546. (setq end-of-headers
  7547. (+ end-of-headers header-len))))))))
  7548. (narrow-to-region end-of-headers (point-max))))
  7549. (defun message-hide-header-p (regexps)
  7550. (let ((result nil)
  7551. (reverse nil))
  7552. (when (eq (car regexps) 'not)
  7553. (setq reverse t)
  7554. (pop regexps))
  7555. (dolist (regexp regexps)
  7556. (setq result (or result (looking-at regexp))))
  7557. (if reverse
  7558. (not result)
  7559. result)))
  7560. (declare-function ecomplete-add-item "ecomplete" (type key text))
  7561. (declare-function ecomplete-save "ecomplete" ())
  7562. (defun message-put-addresses-in-ecomplete ()
  7563. (require 'ecomplete)
  7564. (dolist (header '("to" "cc" "from" "reply-to"))
  7565. (let ((value (message-field-value header)))
  7566. (dolist (string (mail-header-parse-addresses value 'raw))
  7567. (setq string
  7568. (gnus-replace-in-string
  7569. (gnus-replace-in-string string "^ +\\| +$" "") "\n" ""))
  7570. (ecomplete-add-item 'mail (car (mail-header-parse-address string))
  7571. string))))
  7572. (ecomplete-save))
  7573. (autoload 'ecomplete-display-matches "ecomplete")
  7574. (defun message-display-abbrev (&optional choose)
  7575. "Display the next possible abbrev for the text before point."
  7576. (interactive (list t))
  7577. (when (and (memq (char-after (point-at-bol)) '(?C ?T ?\t ? ))
  7578. (message-point-in-header-p)
  7579. (save-excursion
  7580. (beginning-of-line)
  7581. (while (and (memq (char-after) '(?\t ? ))
  7582. (zerop (forward-line -1))))
  7583. (looking-at "To:\\|Cc:")))
  7584. (let* ((end (point))
  7585. (start (save-excursion
  7586. (and (re-search-backward "[\n\t ]" nil t)
  7587. (1+ (point)))))
  7588. (word (when start (buffer-substring start end)))
  7589. (match (when (and word
  7590. (not (zerop (length word))))
  7591. (ecomplete-display-matches 'mail word choose))))
  7592. (when (and choose match)
  7593. (delete-region start end)
  7594. (insert match)))))
  7595. ;; To send pre-formatted letters like the example below, you can use
  7596. ;; `message-send-form-letter':
  7597. ;; --8<---------------cut here---------------start------------->8---
  7598. ;; To: alice@invalid.invalid
  7599. ;; Subject: Verification of your contact information
  7600. ;; From: Contact verification <admin@foo.invalid>
  7601. ;; --text follows this line--
  7602. ;; Hi Alice,
  7603. ;; please verify that your contact information is still valid:
  7604. ;; Alice A, A avenue 11, 1111 A town, Austria
  7605. ;; ----------next form letter message follows this line----------
  7606. ;; To: bob@invalid.invalid
  7607. ;; Subject: Verification of your contact information
  7608. ;; From: Contact verification <admin@foo.invalid>
  7609. ;; --text follows this line--
  7610. ;; Hi Bob,
  7611. ;; please verify that your contact information is still valid:
  7612. ;; Bob, B street 22, 22222 Be town, Belgium
  7613. ;; ----------next form letter message follows this line----------
  7614. ;; To: charlie@invalid.invalid
  7615. ;; Subject: Verification of your contact information
  7616. ;; From: Contact verification <admin@foo.invalid>
  7617. ;; --text follows this line--
  7618. ;; Hi Charlie,
  7619. ;; please verify that your contact information is still valid:
  7620. ;; Charlie Chaplin, C plaza 33, 33333 C town, Chile
  7621. ;; --8<---------------cut here---------------end--------------->8---
  7622. ;; FIXME: What is the most common term (circular letter, form letter, serial
  7623. ;; letter, standard letter) for such kind of letter? See also
  7624. ;; <http://en.wikipedia.org/wiki/Form_letter>
  7625. ;; FIXME: Maybe extent message-mode's font-lock support to recognize
  7626. ;; `message-form-letter-separator', i.e. highlight each message like a single
  7627. ;; message.
  7628. (defcustom message-form-letter-separator
  7629. "\n----------next form letter message follows this line----------\n"
  7630. "Separator for `message-send-form-letter'."
  7631. ;; :group 'message-form-letter
  7632. :group 'message-various
  7633. :version "23.1" ;; No Gnus
  7634. :type 'string)
  7635. (defcustom message-send-form-letter-delay 1
  7636. "Delay in seconds when sending a message with `message-send-form-letter'.
  7637. Only used when `message-send-form-letter' is called with non-nil
  7638. argument `force'."
  7639. ;; :group 'message-form-letter
  7640. :group 'message-various
  7641. :version "23.1" ;; No Gnus
  7642. :type 'integer)
  7643. (defun message-send-form-letter (&optional force)
  7644. "Sent all form letter messages from current buffer.
  7645. Unless FORCE, prompt before sending.
  7646. The messages are separated by `message-form-letter-separator'.
  7647. Header and body are separated by `mail-header-separator'."
  7648. (interactive "P")
  7649. (let ((sent 0) (skipped 0)
  7650. start end text
  7651. buff
  7652. to done)
  7653. (goto-char (point-min))
  7654. (while (not done)
  7655. (setq start (point)
  7656. end (if (search-forward message-form-letter-separator nil t)
  7657. (- (point) (length message-form-letter-separator) -1)
  7658. (setq done t)
  7659. (point-max)))
  7660. (setq text
  7661. (buffer-substring-no-properties start end))
  7662. (setq buff (generate-new-buffer "*mail - form letter*"))
  7663. (with-current-buffer buff
  7664. (insert text)
  7665. (message-mode)
  7666. (setq to (message-fetch-field "To"))
  7667. (switch-to-buffer buff)
  7668. (when force
  7669. (sit-for message-send-form-letter-delay))
  7670. (if (or force
  7671. (y-or-n-p (format "Send message to `%s'? " to)))
  7672. (progn
  7673. (setq sent (1+ sent))
  7674. (message-send-and-exit))
  7675. (message (format "Message to `%s' skipped." to))
  7676. (setq skipped (1+ skipped)))
  7677. (when (buffer-live-p buff)
  7678. (kill-buffer buff))))
  7679. (message "%s message(s) sent, %s skipped." sent skipped)))
  7680. (defun message-replace-header (header new-value &optional after force)
  7681. "Remove HEADER and insert the NEW-VALUE.
  7682. If AFTER, insert after this header. If FORCE, insert new field
  7683. even if NEW-VALUE is empty."
  7684. ;; Similar to `nnheader-replace-header' but for message buffers.
  7685. (save-excursion
  7686. (save-restriction
  7687. (message-narrow-to-headers)
  7688. (message-remove-header header))
  7689. (when (or force (> (length new-value) 0))
  7690. (if after
  7691. (message-position-on-field header after)
  7692. (message-position-on-field header))
  7693. (insert new-value))))
  7694. (defcustom message-recipients-without-full-name
  7695. (list "ding@gnus.org"
  7696. "bugs@gnus.org"
  7697. "emacs-devel@gnu.org"
  7698. "emacs-pretest-bug@gnu.org"
  7699. "bug-gnu-emacs@gnu.org")
  7700. "Mail addresses that have no full name.
  7701. Used in `message-simplify-recipients'."
  7702. ;; Maybe the addresses could be extracted from
  7703. ;; `gnus-parameter-to-list-alist'?
  7704. :type '(choice (const :tag "None" nil)
  7705. (repeat string))
  7706. :version "23.1" ;; No Gnus
  7707. :group 'message-headers)
  7708. (defun message-simplify-recipients ()
  7709. (interactive)
  7710. (dolist (hdr '("Cc" "To"))
  7711. (message-replace-header
  7712. hdr
  7713. (mapconcat
  7714. (lambda (addrcomp)
  7715. (if (and message-recipients-without-full-name
  7716. (string-match
  7717. (regexp-opt message-recipients-without-full-name)
  7718. (cadr addrcomp)))
  7719. (cadr addrcomp)
  7720. (if (car addrcomp)
  7721. (message-make-from (car addrcomp) (cadr addrcomp))
  7722. (cadr addrcomp))))
  7723. (when (message-fetch-field hdr)
  7724. (mail-extract-address-components
  7725. (message-fetch-field hdr) t))
  7726. ", "))))
  7727. (when (featurep 'xemacs)
  7728. (require 'messagexmas)
  7729. (message-xmas-redefine))
  7730. (provide 'message)
  7731. (run-hooks 'message-load-hook)
  7732. ;; Local Variables:
  7733. ;; coding: iso-8859-1
  7734. ;; End:
  7735. ;;; message.el ends here