12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672867386748675867686778678867986808681868286838684868586868687868886898690869186928693869486958696869786988699870087018702870387048705870687078708870987108711871287138714871587168717871887198720872187228723872487258726872787288729873087318732873387348735873687378738873987408741874287438744874587468747874887498750875187528753875487558756875787588759876087618762876387648765876687678768876987708771877287738774877587768777877887798780878187828783878487858786878787888789879087918792879387948795879687978798879988008801880288038804880588068807880888098810881188128813881488158816881788188819882088218822882388248825882688278828882988308831883288338834883588368837883888398840884188428843884488458846884788488849885088518852885388548855885688578858885988608861886288638864886588668867886888698870887188728873887488758876887788788879888088818882888388848885888688878888888988908891889288938894889588968897889888998900890189028903890489058906890789088909891089118912891389148915891689178918891989208921892289238924892589268927892889298930893189328933893489358936893789388939894089418942894389448945894689478948894989508951895289538954895589568957895889598960896189628963896489658966896789688969897089718972897389748975897689778978897989808981898289838984898589868987898889898990899189928993899489958996899789988999900090019002900390049005900690079008900990109011901290139014901590169017901890199020902190229023902490259026902790289029903090319032903390349035903690379038903990409041904290439044904590469047904890499050905190529053905490559056905790589059906090619062906390649065906690679068906990709071907290739074907590769077907890799080908190829083908490859086908790889089909090919092909390949095909690979098909991009101910291039104910591069107910891099110911191129113911491159116911791189119912091219122912391249125912691279128912991309131913291339134913591369137913891399140914191429143914491459146914791489149915091519152915391549155915691579158915991609161916291639164916591669167916891699170917191729173917491759176917791789179918091819182918391849185918691879188918991909191919291939194919591969197919891999200920192029203920492059206920792089209921092119212921392149215921692179218921992209221922292239224922592269227922892299230923192329233923492359236923792389239924092419242924392449245924692479248924992509251925292539254925592569257925892599260926192629263926492659266926792689269927092719272927392749275927692779278927992809281928292839284928592869287928892899290929192929293929492959296929792989299930093019302930393049305930693079308930993109311931293139314931593169317931893199320932193229323932493259326932793289329933093319332933393349335933693379338933993409341934293439344934593469347934893499350935193529353935493559356935793589359936093619362936393649365936693679368936993709371937293739374937593769377937893799380938193829383938493859386938793889389939093919392939393949395939693979398939994009401940294039404940594069407940894099410941194129413941494159416941794189419942094219422942394249425942694279428942994309431943294339434943594369437943894399440944194429443944494459446944794489449945094519452945394549455945694579458945994609461946294639464946594669467946894699470947194729473947494759476947794789479948094819482948394849485948694879488948994909491949294939494949594969497949894999500950195029503950495059506950795089509951095119512951395149515951695179518951995209521952295239524952595269527952895299530953195329533953495359536953795389539954095419542954395449545954695479548954995509551955295539554955595569557955895599560956195629563956495659566956795689569957095719572957395749575957695779578957995809581958295839584958595869587958895899590959195929593959495959596959795989599960096019602960396049605960696079608960996109611961296139614961596169617961896199620962196229623962496259626962796289629963096319632963396349635963696379638963996409641964296439644964596469647964896499650965196529653965496559656965796589659966096619662966396649665966696679668966996709671967296739674967596769677967896799680968196829683968496859686968796889689969096919692969396949695969696979698969997009701970297039704970597069707970897099710971197129713971497159716971797189719972097219722972397249725972697279728972997309731973297339734973597369737973897399740974197429743974497459746974797489749975097519752975397549755975697579758975997609761976297639764976597669767976897699770977197729773977497759776977797789779978097819782978397849785978697879788978997909791979297939794979597969797979897999800980198029803980498059806980798089809981098119812981398149815981698179818981998209821982298239824982598269827982898299830983198329833983498359836983798389839984098419842984398449845984698479848984998509851985298539854985598569857985898599860986198629863986498659866986798689869987098719872987398749875987698779878987998809881988298839884988598869887988898899890989198929893989498959896989798989899990099019902990399049905990699079908990999109911991299139914991599169917991899199920992199229923992499259926992799289929993099319932993399349935993699379938993999409941994299439944994599469947994899499950995199529953995499559956995799589959996099619962996399649965996699679968996999709971997299739974997599769977997899799980998199829983998499859986998799889989999099919992999399949995999699979998999910000100011000210003100041000510006100071000810009100101001110012100131001410015100161001710018100191002010021100221002310024100251002610027100281002910030100311003210033100341003510036100371003810039100401004110042100431004410045100461004710048100491005010051100521005310054100551005610057100581005910060100611006210063100641006510066100671006810069100701007110072100731007410075100761007710078100791008010081100821008310084100851008610087100881008910090100911009210093100941009510096100971009810099101001010110102101031010410105101061010710108101091011010111101121011310114101151011610117101181011910120101211012210123101241012510126101271012810129101301013110132101331013410135101361013710138101391014010141101421014310144101451014610147101481014910150101511015210153101541015510156101571015810159101601016110162101631016410165101661016710168101691017010171101721017310174101751017610177101781017910180101811018210183101841018510186101871018810189101901019110192101931019410195101961019710198101991020010201102021020310204102051020610207102081020910210102111021210213102141021510216102171021810219102201022110222102231022410225102261022710228102291023010231102321023310234102351023610237102381023910240102411024210243102441024510246102471024810249102501025110252102531025410255102561025710258102591026010261102621026310264102651026610267102681026910270102711027210273102741027510276102771027810279102801028110282102831028410285102861028710288102891029010291102921029310294102951029610297102981029910300103011030210303103041030510306103071030810309103101031110312103131031410315103161031710318103191032010321103221032310324103251032610327103281032910330103311033210333103341033510336103371033810339103401034110342103431034410345103461034710348103491035010351103521035310354103551035610357103581035910360103611036210363103641036510366103671036810369103701037110372103731037410375103761037710378103791038010381103821038310384103851038610387103881038910390103911039210393103941039510396103971039810399104001040110402104031040410405104061040710408104091041010411104121041310414104151041610417104181041910420104211042210423104241042510426104271042810429104301043110432104331043410435104361043710438104391044010441104421044310444104451044610447104481044910450104511045210453104541045510456104571045810459104601046110462104631046410465104661046710468104691047010471104721047310474104751047610477104781047910480104811048210483104841048510486104871048810489104901049110492104931049410495104961049710498104991050010501105021050310504105051050610507105081050910510105111051210513105141051510516105171051810519105201052110522105231052410525105261052710528105291053010531105321053310534105351053610537105381053910540105411054210543105441054510546105471054810549105501055110552105531055410555105561055710558105591056010561105621056310564105651056610567105681056910570105711057210573105741057510576105771057810579105801058110582105831058410585105861058710588105891059010591105921059310594105951059610597105981059910600106011060210603106041060510606106071060810609106101061110612106131061410615106161061710618106191062010621106221062310624106251062610627106281062910630106311063210633106341063510636106371063810639106401064110642106431064410645106461064710648106491065010651106521065310654106551065610657106581065910660106611066210663106641066510666106671066810669106701067110672106731067410675106761067710678106791068010681106821068310684106851068610687106881068910690106911069210693106941069510696106971069810699107001070110702107031070410705107061070710708107091071010711107121071310714107151071610717107181071910720107211072210723107241072510726107271072810729107301073110732107331073410735107361073710738107391074010741107421074310744107451074610747107481074910750107511075210753107541075510756107571075810759107601076110762107631076410765107661076710768107691077010771107721077310774107751077610777107781077910780107811078210783107841078510786107871078810789107901079110792107931079410795107961079710798107991080010801108021080310804108051080610807108081080910810108111081210813108141081510816108171081810819108201082110822108231082410825108261082710828108291083010831108321083310834108351083610837108381083910840108411084210843108441084510846108471084810849108501085110852108531085410855108561085710858108591086010861108621086310864108651086610867108681086910870108711087210873108741087510876108771087810879108801088110882108831088410885108861088710888108891089010891108921089310894108951089610897108981089910900109011090210903109041090510906109071090810909109101091110912109131091410915109161091710918109191092010921109221092310924109251092610927109281092910930109311093210933109341093510936109371093810939109401094110942109431094410945109461094710948109491095010951109521095310954109551095610957109581095910960109611096210963109641096510966109671096810969109701097110972109731097410975109761097710978109791098010981109821098310984109851098610987109881098910990109911099210993109941099510996109971099810999110001100111002110031100411005110061100711008110091101011011110121101311014110151101611017110181101911020110211102211023110241102511026110271102811029110301103111032110331103411035110361103711038110391104011041110421104311044110451104611047110481104911050110511105211053110541105511056110571105811059110601106111062110631106411065110661106711068110691107011071110721107311074110751107611077110781107911080110811108211083110841108511086110871108811089110901109111092110931109411095110961109711098110991110011101111021110311104111051110611107111081110911110111111111211113111141111511116111171111811119111201112111122111231112411125111261112711128111291113011131111321113311134111351113611137111381113911140111411114211143111441114511146111471114811149111501115111152111531115411155111561115711158111591116011161111621116311164111651116611167111681116911170111711117211173111741117511176111771117811179111801118111182111831118411185111861118711188111891119011191111921119311194111951119611197111981119911200112011120211203112041120511206112071120811209112101121111212112131121411215112161121711218112191122011221112221122311224112251122611227112281122911230112311123211233112341123511236112371123811239112401124111242112431124411245112461124711248112491125011251112521125311254112551125611257112581125911260112611126211263112641126511266112671126811269112701127111272112731127411275112761127711278112791128011281112821128311284112851128611287112881128911290112911129211293112941129511296112971129811299113001130111302113031130411305113061130711308113091131011311113121131311314113151131611317113181131911320113211132211323113241132511326113271132811329113301133111332113331133411335113361133711338113391134011341113421134311344113451134611347113481134911350113511135211353113541135511356113571135811359113601136111362113631136411365113661136711368113691137011371113721137311374113751137611377113781137911380113811138211383113841138511386113871138811389113901139111392113931139411395113961139711398113991140011401114021140311404114051140611407114081140911410114111141211413114141141511416114171141811419114201142111422114231142411425114261142711428114291143011431114321143311434114351143611437114381143911440114411144211443114441144511446114471144811449114501145111452114531145411455114561145711458114591146011461114621146311464114651146611467114681146911470114711147211473114741147511476114771147811479114801148111482114831148411485114861148711488114891149011491114921149311494114951149611497114981149911500115011150211503115041150511506115071150811509115101151111512115131151411515115161151711518115191152011521115221152311524115251152611527115281152911530115311153211533115341153511536115371153811539115401154111542115431154411545115461154711548115491155011551115521155311554115551155611557115581155911560115611156211563115641156511566115671156811569115701157111572115731157411575115761157711578115791158011581115821158311584115851158611587115881158911590115911159211593115941159511596115971159811599116001160111602116031160411605116061160711608116091161011611116121161311614116151161611617116181161911620116211162211623116241162511626116271162811629116301163111632116331163411635116361163711638116391164011641116421164311644116451164611647116481164911650116511165211653116541165511656116571165811659116601166111662116631166411665116661166711668116691167011671116721167311674116751167611677116781167911680116811168211683116841168511686116871168811689116901169111692116931169411695116961169711698116991170011701117021170311704117051170611707117081170911710117111171211713117141171511716117171171811719117201172111722117231172411725117261172711728117291173011731117321173311734117351173611737117381173911740117411174211743117441174511746117471174811749117501175111752117531175411755117561175711758117591176011761117621176311764117651176611767117681176911770117711177211773117741177511776117771177811779117801178111782117831178411785117861178711788117891179011791117921179311794117951179611797117981179911800118011180211803118041180511806118071180811809118101181111812118131181411815118161181711818118191182011821118221182311824118251182611827118281182911830118311183211833118341183511836118371183811839118401184111842118431184411845118461184711848118491185011851118521185311854118551185611857118581185911860118611186211863118641186511866118671186811869118701187111872118731187411875118761187711878118791188011881118821188311884118851188611887118881188911890118911189211893118941189511896118971189811899119001190111902119031190411905119061190711908119091191011911119121191311914119151191611917119181191911920119211192211923119241192511926119271192811929119301193111932119331193411935119361193711938119391194011941119421194311944119451194611947119481194911950119511195211953119541195511956119571195811959119601196111962119631196411965119661196711968119691197011971119721197311974119751197611977119781197911980119811198211983119841198511986119871198811989119901199111992119931199411995119961199711998119991200012001120021200312004120051200612007120081200912010120111201212013120141201512016120171201812019120201202112022120231202412025120261202712028120291203012031120321203312034120351203612037120381203912040120411204212043120441204512046120471204812049120501205112052120531205412055120561205712058120591206012061120621206312064120651206612067120681206912070120711207212073120741207512076120771207812079120801208112082120831208412085120861208712088120891209012091120921209312094120951209612097120981209912100121011210212103121041210512106121071210812109121101211112112121131211412115121161211712118121191212012121121221212312124121251212612127121281212912130121311213212133121341213512136121371213812139121401214112142121431214412145121461214712148121491215012151121521215312154121551215612157121581215912160121611216212163121641216512166121671216812169121701217112172121731217412175121761217712178121791218012181121821218312184121851218612187121881218912190121911219212193121941219512196121971219812199122001220112202122031220412205122061220712208122091221012211122121221312214122151221612217122181221912220122211222212223122241222512226122271222812229122301223112232122331223412235122361223712238122391224012241122421224312244122451224612247122481224912250122511225212253122541225512256122571225812259122601226112262122631226412265122661226712268122691227012271122721227312274122751227612277122781227912280122811228212283122841228512286122871228812289122901229112292122931229412295122961229712298122991230012301123021230312304123051230612307123081230912310123111231212313123141231512316123171231812319123201232112322123231232412325123261232712328123291233012331123321233312334123351233612337123381233912340123411234212343123441234512346123471234812349123501235112352123531235412355123561235712358123591236012361123621236312364123651236612367123681236912370123711237212373123741237512376123771237812379123801238112382123831238412385123861238712388123891239012391123921239312394123951239612397123981239912400124011240212403124041240512406124071240812409124101241112412124131241412415124161241712418124191242012421124221242312424124251242612427124281242912430124311243212433124341243512436124371243812439124401244112442124431244412445124461244712448124491245012451124521245312454124551245612457124581245912460124611246212463124641246512466124671246812469124701247112472124731247412475124761247712478124791248012481124821248312484124851248612487124881248912490124911249212493124941249512496124971249812499125001250112502125031250412505125061250712508125091251012511125121251312514125151251612517125181251912520125211252212523125241252512526125271252812529125301253112532125331253412535125361253712538125391254012541125421254312544125451254612547125481254912550125511255212553125541255512556125571255812559125601256112562125631256412565125661256712568125691257012571125721257312574125751257612577125781257912580125811258212583125841258512586125871258812589125901259112592125931259412595125961259712598125991260012601126021260312604126051260612607126081260912610126111261212613126141261512616126171261812619126201262112622126231262412625126261262712628126291263012631126321263312634126351263612637126381263912640126411264212643126441264512646126471264812649126501265112652126531265412655126561265712658126591266012661126621266312664126651266612667126681266912670126711267212673126741267512676126771267812679126801268112682126831268412685126861268712688126891269012691126921269312694126951269612697126981269912700127011270212703127041270512706127071270812709127101271112712127131271412715127161271712718127191272012721127221272312724127251272612727127281272912730127311273212733127341273512736127371273812739127401274112742127431274412745127461274712748127491275012751127521275312754127551275612757127581275912760127611276212763127641276512766127671276812769127701277112772127731277412775127761277712778127791278012781127821278312784127851278612787127881278912790127911279212793127941279512796127971279812799128001280112802128031280412805128061280712808128091281012811128121281312814128151281612817128181281912820128211282212823128241282512826128271282812829128301283112832128331283412835128361283712838128391284012841128421284312844128451284612847128481284912850128511285212853128541285512856128571285812859128601286112862128631286412865128661286712868128691287012871128721287312874128751287612877128781287912880128811288212883128841288512886128871288812889128901289112892128931289412895128961289712898128991290012901129021290312904129051290612907129081290912910129111291212913129141291512916129171291812919129201292112922129231292412925129261292712928129291293012931129321293312934129351293612937129381293912940129411294212943129441294512946129471294812949129501295112952129531295412955129561295712958129591296012961129621296312964129651296612967129681296912970129711297212973129741297512976129771297812979129801298112982129831298412985129861298712988129891299012991129921299312994129951299612997129981299913000130011300213003130041300513006130071300813009130101301113012130131301413015130161301713018130191302013021130221302313024130251302613027130281302913030130311303213033130341303513036130371303813039130401304113042130431304413045130461304713048130491305013051130521305313054130551305613057130581305913060130611306213063130641306513066130671306813069130701307113072130731307413075130761307713078130791308013081130821308313084130851308613087130881308913090130911309213093130941309513096130971309813099131001310113102131031310413105131061310713108131091311013111131121311313114131151311613117131181311913120131211312213123131241312513126 |
- ;;; gnus-sum.el --- summary mode commands for Gnus
- ;; Copyright (C) 1996-2015 Free Software Foundation, Inc.
- ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
- ;; Keywords: news
- ;; This file is part of GNU Emacs.
- ;; GNU Emacs is free software: you can redistribute it and/or modify
- ;; it under the terms of the GNU General Public License as published by
- ;; the Free Software Foundation, either version 3 of the License, or
- ;; (at your option) any later version.
- ;; GNU Emacs is distributed in the hope that it will be useful,
- ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
- ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ;; GNU General Public License for more details.
- ;; You should have received a copy of the GNU General Public License
- ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
- ;;; Commentary:
- ;;; Code:
- (eval-when-compile
- (require 'cl))
- (eval-when-compile
- (when (featurep 'xemacs)
- (require 'easy-mmode))) ; for `define-minor-mode'
- (defvar tool-bar-mode)
- (defvar gnus-tmp-header)
- (require 'gnus)
- (require 'gnus-group)
- (require 'gnus-spec)
- (require 'gnus-range)
- (require 'gnus-int)
- (require 'gnus-undo)
- (require 'gnus-util)
- (require 'gmm-utils)
- (require 'mm-decode)
- (require 'nnoo)
- (autoload 'gnus-summary-limit-include-cached "gnus-cache" nil t)
- (autoload 'gnus-cache-write-active "gnus-cache")
- (autoload 'gnus-mailing-list-insinuate "gnus-ml" nil t)
- (autoload 'turn-on-gnus-mailing-list-mode "gnus-ml" nil t)
- (autoload 'gnus-pick-line-number "gnus-salt" nil t)
- (autoload 'mm-uu-dissect "mm-uu")
- (autoload 'gnus-article-outlook-deuglify-article "deuglify"
- "Deuglify broken Outlook (Express) articles and redisplay."
- t)
- (autoload 'gnus-article-outlook-unwrap-lines "deuglify" nil t)
- (autoload 'gnus-article-outlook-repair-attribution "deuglify" nil t)
- (autoload 'gnus-article-outlook-rearrange-citation "deuglify" nil t)
- (autoload 'nnir-article-rsv "nnir" nil nil 'macro)
- (autoload 'nnir-article-group "nnir" nil nil 'macro)
- (defcustom gnus-kill-summary-on-exit t
- "*If non-nil, kill the summary buffer when you exit from it.
- If nil, the summary will become a \"*Dead Summary*\" buffer, and
- it will be killed sometime later."
- :group 'gnus-summary-exit
- :type 'boolean)
- (defcustom gnus-summary-next-group-on-exit t
- "If non-nil, go to the next unread newsgroup on summary exit.
- See `gnus-group-goto-unread'."
- :link '(custom-manual "(gnus)Group Maneuvering")
- :group 'gnus-summary-exit
- :version "23.1" ;; No Gnus
- :type 'boolean)
- (defcustom gnus-summary-stop-at-end-of-message nil
- "If non-nil, don't select the next message when using `SPC'."
- :link '(custom-manual "(gnus)Group Maneuvering")
- :group 'gnus-summary-maneuvering
- :version "24.1"
- :type 'boolean)
- (defcustom gnus-fetch-old-headers nil
- "*Non-nil means that Gnus will try to build threads by grabbing old headers.
- If an unread article in the group refers to an older, already
- read (or just marked as read) article, the old article will not
- normally be displayed in the Summary buffer. If this variable is
- t, Gnus will attempt to grab the headers to the old articles, and
- thereby build complete threads. If it has the value `some', all
- old headers will be fetched but only enough headers to connect
- otherwise loose threads will be displayed. This variable can
- also be a number. In that case, no more than that number of old
- headers will be fetched. If it has the value `invisible', all
- old headers will be fetched, but none will be displayed.
- The server has to support NOV for any of this to work.
- This feature can seriously impact performance it ignores all
- locally cached header entries. Setting it to t for groups for a
- server that doesn't expire articles (such as news.gmane.org),
- leads to very slow summary generation."
- :group 'gnus-thread
- :type '(choice (const :tag "off" nil)
- (const :tag "on" t)
- (const some)
- (const invisible)
- number
- (sexp :menu-tag "other" t)))
- (defcustom gnus-refer-thread-limit 500
- "*The number of old headers to fetch when doing \\<gnus-summary-mode-map>\\[gnus-summary-refer-thread].
- If t, fetch all the available old headers."
- :group 'gnus-thread
- :type '(choice number
- (sexp :menu-tag "other" t)))
- (defcustom gnus-refer-thread-use-nnir nil
- "*Use nnir to search an entire server when referring threads. A
- nil value will only search for thread-related articles in the
- current group."
- :version "24.1"
- :group 'gnus-thread
- :type 'boolean)
- (defcustom gnus-summary-make-false-root 'adopt
- "*nil means that Gnus won't gather loose threads.
- If the root of a thread has expired or been read in a previous
- session, the information necessary to build a complete thread has been
- lost. Instead of having many small sub-threads from this original thread
- scattered all over the summary buffer, Gnus can gather them.
- If non-nil, Gnus will try to gather all loose sub-threads from an
- original thread into one large thread.
- If this variable is non-nil, it should be one of `none', `adopt',
- `dummy' or `empty'.
- If this variable is `none', Gnus will not make a false root, but just
- present the sub-threads after another.
- If this variable is `dummy', Gnus will create a dummy root that will
- have all the sub-threads as children.
- If this variable is `adopt', Gnus will make one of the \"children\"
- the parent and mark all the step-children as such.
- If this variable is `empty', the \"children\" are printed with empty
- subject fields. (Or rather, they will be printed with a string
- given by the `gnus-summary-same-subject' variable.)"
- :group 'gnus-thread
- :type '(choice (const :tag "off" nil)
- (const none)
- (const dummy)
- (const adopt)
- (const empty)))
- (defcustom gnus-summary-make-false-root-always nil
- "Always make a false dummy root."
- :version "22.1"
- :group 'gnus-thread
- :type 'boolean)
- (defcustom gnus-summary-gather-exclude-subject "^ *$\\|^(none)$"
- "*A regexp to match subjects to be excluded from loose thread gathering.
- As loose thread gathering is done on subjects only, that means that
- there can be many false gatherings performed. By rooting out certain
- common subjects, gathering might become saner."
- :group 'gnus-thread
- :type 'regexp)
- (defcustom gnus-summary-gather-subject-limit nil
- "*Maximum length of subject comparisons when gathering loose threads.
- Use nil to compare full subjects. Setting this variable to a low
- number will help gather threads that have been corrupted by
- newsreaders chopping off subject lines, but it might also mean that
- unrelated articles that have subject that happen to begin with the
- same few characters will be incorrectly gathered.
- If this variable is `fuzzy', Gnus will use a fuzzy algorithm when
- comparing subjects."
- :group 'gnus-thread
- :type '(choice (const :tag "off" nil)
- (const fuzzy)
- (sexp :menu-tag "on" t)))
- (defcustom gnus-simplify-subject-functions nil
- "List of functions taking a string argument that simplify subjects.
- The functions are applied recursively.
- Useful functions to put in this list include:
- `gnus-simplify-subject-re', `gnus-simplify-subject-fuzzy',
- `gnus-simplify-whitespace', and `gnus-simplify-all-whitespace'."
- :group 'gnus-thread
- :type '(repeat function))
- (defcustom gnus-simplify-ignored-prefixes nil
- "*Remove matches for this regexp from subject lines when simplifying fuzzily."
- :group 'gnus-thread
- :type '(choice (const :tag "off" nil)
- regexp))
- (defcustom gnus-build-sparse-threads nil
- "*If non-nil, fill in the gaps in threads.
- If `some', only fill in the gaps that are needed to tie loose threads
- together. If `more', fill in all leaf nodes that Gnus can find. If
- non-nil and non-`some', fill in all gaps that Gnus manages to guess."
- :group 'gnus-thread
- :type '(choice (const :tag "off" nil)
- (const some)
- (const more)
- (sexp :menu-tag "all" t)))
- (defcustom gnus-summary-thread-gathering-function
- 'gnus-gather-threads-by-subject
- "*Function used for gathering loose threads.
- There are two pre-defined functions: `gnus-gather-threads-by-subject',
- which only takes Subjects into consideration; and
- `gnus-gather-threads-by-references', which compared the References
- headers of the articles to find matches."
- :group 'gnus-thread
- :type '(radio (function-item gnus-gather-threads-by-subject)
- (function-item gnus-gather-threads-by-references)
- (function :tag "other")))
- (defcustom gnus-summary-same-subject ""
- "*String indicating that the current article has the same subject as the previous.
- This variable will only be used if the value of
- `gnus-summary-make-false-root' is `empty'."
- :group 'gnus-summary-format
- :type 'string)
- (defcustom gnus-summary-goto-unread nil
- "*If t, many commands will go to the next unread article.
- This applies to marking commands as well as other commands that
- \"naturally\" select the next article, like, for instance, `SPC' at
- the end of an article.
- If nil, the marking commands do NOT go to the next unread article
- \(they go to the next article instead). If `never', commands that
- usually go to the next unread article, will go to the next article,
- whether it is read or not."
- :version "24.1"
- :group 'gnus-summary-marks
- :link '(custom-manual "(gnus)Setting Marks")
- :type '(choice (const :tag "off" nil)
- (const never)
- (sexp :menu-tag "on" t)))
- (defcustom gnus-summary-default-score 0
- "*Default article score level.
- All scores generated by the score files will be added to this score.
- If this variable is nil, scoring will be disabled."
- :group 'gnus-score-default
- :type '(choice (const :tag "disable")
- integer))
- (defcustom gnus-summary-default-high-score 0
- "*Default threshold for a high scored article.
- An article will be highlighted as high scored if its score is greater
- than this score."
- :version "22.1"
- :group 'gnus-score-default
- :type 'integer)
- (defcustom gnus-summary-default-low-score 0
- "*Default threshold for a low scored article.
- An article will be highlighted as low scored if its score is smaller
- than this score."
- :version "22.1"
- :group 'gnus-score-default
- :type 'integer)
- (defcustom gnus-summary-zcore-fuzz 0
- "*Fuzziness factor for the zcore in the summary buffer.
- Articles with scores closer than this to `gnus-summary-default-score'
- will not be marked."
- :group 'gnus-summary-format
- :type 'integer)
- (defcustom gnus-simplify-subject-fuzzy-regexp nil
- "*Strings to be removed when doing fuzzy matches.
- This can either be a regular expression or list of regular expressions
- that will be removed from subject strings if fuzzy subject
- simplification is selected."
- :group 'gnus-thread
- :type '(repeat regexp))
- (defcustom gnus-show-threads t
- "*If non-nil, display threads in summary mode."
- :group 'gnus-thread
- :type 'boolean)
- (defcustom gnus-thread-hide-subtree nil
- "*If non-nil, hide all threads initially.
- This can be a predicate specifier which says which threads to hide.
- If threads are hidden, you have to run the command
- `gnus-summary-show-thread' by hand or select an article."
- :group 'gnus-thread
- :type '(radio (sexp :format "Non-nil\n"
- :match (lambda (widget value)
- (not (or (consp value) (functionp value))))
- :value t)
- (const nil)
- (sexp :tag "Predicate specifier")))
- (defcustom gnus-thread-hide-killed t
- "*If non-nil, hide killed threads automatically."
- :group 'gnus-thread
- :type 'boolean)
- (defcustom gnus-thread-ignore-subject t
- "*If non-nil, which is the default, ignore subjects and do all threading based on the Reference header.
- If nil, articles that have different subjects from their parents will
- start separate threads."
- :group 'gnus-thread
- :type 'boolean)
- (defcustom gnus-thread-operation-ignore-subject t
- "*If non-nil, subjects will be ignored when doing thread commands.
- This affects commands like `gnus-summary-kill-thread' and
- `gnus-summary-lower-thread'.
- If this variable is nil, articles in the same thread with different
- subjects will not be included in the operation in question. If this
- variable is `fuzzy', only articles that have subjects that are fuzzily
- equal will be included."
- :group 'gnus-thread
- :type '(choice (const :tag "off" nil)
- (const fuzzy)
- (sexp :tag "on" t)))
- (defcustom gnus-thread-indent-level 4
- "*Number that says how much each sub-thread should be indented."
- :group 'gnus-thread
- :type 'integer)
- (defcustom gnus-auto-extend-newsgroup t
- "*If non-nil, extend newsgroup forward and backward when requested."
- :group 'gnus-summary-choose
- :type 'boolean)
- (defcustom gnus-auto-select-first t
- "If non-nil, select an article on group entry.
- An article is selected automatically when entering a group
- e.g. with \\<gnus-group-mode-map>\\[gnus-group-read-group], or via `gnus-summary-next-page' or
- `gnus-summary-catchup-and-goto-next-group'.
- Which article is selected is controlled by the variable
- `gnus-auto-select-subject'.
- If you want to prevent automatic selection of articles in some
- newsgroups, set the variable to nil in `gnus-select-group-hook'."
- ;; Commands include...
- ;; \\<gnus-group-mode-map>\\[gnus-group-read-group]
- ;; \\<gnus-summary-mode-map>\\[gnus-summary-next-page]
- ;; \\<gnus-summary-mode-map>\\[gnus-summary-catchup-and-goto-next-group]
- :group 'gnus-group-select
- :type '(choice (const :tag "none" nil)
- (sexp :menu-tag "first" t)))
- (defcustom gnus-auto-select-subject 'unseen-or-unread
- "*Says what subject to place under point when entering a group.
- This variable can either be the symbols `first' (place point on the
- first subject), `unread' (place point on the subject line of the first
- unread article), `best' (place point on the subject line of the
- highest-scored article), `unseen' (place point on the subject line of
- the first unseen article), `unseen-or-unread' (place point on the subject
- line of the first unseen article or, if all articles have been seen, on the
- subject line of the first unread article), or a function to be called to
- place point on some subject line."
- :version "24.1"
- :group 'gnus-group-select
- :type '(choice (const best)
- (const unread)
- (const first)
- (const unseen)
- (const unseen-or-unread)
- (function :tag "Function to call")))
- (defcustom gnus-auto-select-next t
- "*If non-nil, offer to go to the next group from the end of the previous.
- If the value is t and the next newsgroup is empty, Gnus will exit
- summary mode and go back to group mode. If the value is neither nil
- nor t, Gnus will select the following unread newsgroup. In
- particular, if the value is the symbol `quietly', the next unread
- newsgroup will be selected without any confirmation, and if it is
- `almost-quietly', the next group will be selected without any
- confirmation if you are located on the last article in the group.
- Finally, if this variable is `slightly-quietly', the `\\<gnus-summary-mode-map>\\[gnus-summary-catchup-and-goto-next-group]' command
- will go to the next group without confirmation."
- :group 'gnus-summary-maneuvering
- :type '(choice (const :tag "off" nil)
- (const quietly)
- (const almost-quietly)
- (const slightly-quietly)
- (sexp :menu-tag "on" t)))
- (defcustom gnus-auto-select-same nil
- "*If non-nil, select the next article with the same subject.
- If there are no more articles with the same subject, go to
- the first unread article."
- :group 'gnus-summary-maneuvering
- :type 'boolean)
- (defcustom gnus-auto-select-on-ephemeral-exit 'next-noselect
- "What article should be selected after exiting an ephemeral group.
- Valid values include:
- `next'
- Select the next article.
- `next-unread'
- Select the next unread article.
- `next-noselect'
- Move the cursor to the next article. This is the default.
- `next-unread-noselect'
- Move the cursor to the next unread article.
- If it has any other value or there is no next (unread) article, the
- article selected before entering to the ephemeral group will appear."
- :version "23.1" ;; No Gnus
- :group 'gnus-summary-maneuvering
- :type '(choice :format "%{%t%}:\n %[Value Menu%] %v"
- (const next) (const next-unread)
- (const next-noselect) (const next-unread-noselect)
- (sexp :tag "other" :value nil)))
- (defcustom gnus-auto-goto-ignores 'unfetched
- "*Says how to handle unfetched articles when maneuvering.
- This variable can either be the symbols nil (maneuver to any
- article), `undownloaded' (maneuvering while unplugged ignores articles
- that have not been fetched), `always-undownloaded' (maneuvering always
- ignores articles that have not been fetched), `unfetched' (maneuvering
- ignores articles whose headers have not been fetched).
- NOTE: The list of unfetched articles will always be nil when plugged
- and, when unplugged, a subset of the undownloaded article list."
- :version "22.1"
- :group 'gnus-summary-maneuvering
- :type '(choice (const :tag "None" nil)
- (const :tag "Undownloaded when unplugged" undownloaded)
- (const :tag "Undownloaded" always-undownloaded)
- (const :tag "Unfetched" unfetched)))
- (defcustom gnus-summary-check-current nil
- "*If non-nil, consider the current article when moving.
- The \"unread\" movement commands will stay on the same line if the
- current article is unread."
- :group 'gnus-summary-maneuvering
- :type 'boolean)
- (defcustom gnus-auto-center-summary
- (max (or (bound-and-true-p scroll-margin) 0) 2)
- "*If non-nil, always center the current summary buffer.
- In particular, if `vertical' do only vertical recentering. If non-nil
- and non-`vertical', do both horizontal and vertical recentering."
- :group 'gnus-summary-maneuvering
- :type '(choice (const :tag "none" nil)
- (const vertical)
- (integer :tag "height")
- (sexp :menu-tag "both" t)))
- (defcustom gnus-auto-center-group t
- "If non-nil, always center the group buffer."
- :group 'gnus-summary-maneuvering
- :type 'boolean)
- (defcustom gnus-show-all-headers nil
- "*If non-nil, don't hide any headers."
- :group 'gnus-article-hiding
- :group 'gnus-article-headers
- :type 'boolean)
- (defcustom gnus-summary-ignore-duplicates nil
- "*If non-nil, ignore articles with identical Message-ID headers."
- :group 'gnus-summary
- :type 'boolean)
- (defcustom gnus-single-article-buffer nil
- "*If non-nil, display all articles in the same buffer.
- If nil, each group will get its own article buffer."
- :version "24.1"
- :group 'gnus-article-various
- :type 'boolean)
- (defcustom gnus-widen-article-window nil
- "If non-nil, selecting the article buffer will display only the article buffer."
- :version "24.1"
- :group 'gnus-article-various
- :type 'boolean)
- (defcustom gnus-break-pages t
- "*If non-nil, do page breaking on articles.
- The page delimiter is specified by the `gnus-page-delimiter'
- variable."
- :group 'gnus-article-various
- :type 'boolean)
- (defcustom gnus-move-split-methods nil
- "*Variable used to suggest where articles are to be moved to.
- It uses the same syntax as the `gnus-split-methods' variable.
- However, whereas `gnus-split-methods' specifies file names as targets,
- this variable specifies group names."
- :group 'gnus-summary-mail
- :type '(repeat (choice (list :value (fun) function)
- (cons :value ("" "") regexp (repeat string))
- (sexp :value nil))))
- (defcustom gnus-move-group-prefix-function 'gnus-group-real-prefix
- "Function used to compute default prefix for article move/copy/etc prompts.
- The function should take one argument, a group name, and return a
- string with the suggested prefix."
- :group 'gnus-summary-mail
- :type 'function)
- ;; FIXME: Although the custom type is `character' for the following variables,
- ;; using multibyte characters (Latin-1, UTF-8) doesn't work. -- rs
- (defcustom gnus-unread-mark ? ;Whitespace
- "*Mark used for unread articles."
- :group 'gnus-summary-marks
- :type 'character)
- (defcustom gnus-ticked-mark ?!
- "*Mark used for ticked articles."
- :group 'gnus-summary-marks
- :type 'character)
- (defcustom gnus-dormant-mark ??
- "*Mark used for dormant articles."
- :group 'gnus-summary-marks
- :type 'character)
- (defcustom gnus-del-mark ?r
- "*Mark used for del'd articles."
- :group 'gnus-summary-marks
- :type 'character)
- (defcustom gnus-read-mark ?R
- "*Mark used for read articles."
- :group 'gnus-summary-marks
- :type 'character)
- (defcustom gnus-expirable-mark ?E
- "*Mark used for expirable articles."
- :group 'gnus-summary-marks
- :type 'character)
- (defcustom gnus-killed-mark ?K
- "*Mark used for killed articles."
- :group 'gnus-summary-marks
- :type 'character)
- (defcustom gnus-spam-mark ?$
- "*Mark used for spam articles."
- :version "22.1"
- :group 'gnus-summary-marks
- :type 'character)
- (defcustom gnus-kill-file-mark ?X
- "*Mark used for articles killed by kill files."
- :group 'gnus-summary-marks
- :type 'character)
- (defcustom gnus-low-score-mark ?Y
- "*Mark used for articles with a low score."
- :group 'gnus-summary-marks
- :type 'character)
- (defcustom gnus-catchup-mark ?C
- "*Mark used for articles that are caught up."
- :group 'gnus-summary-marks
- :type 'character)
- (defcustom gnus-replied-mark ?A
- "*Mark used for articles that have been replied to."
- :group 'gnus-summary-marks
- :type 'character)
- (defcustom gnus-forwarded-mark ?F
- "*Mark used for articles that have been forwarded."
- :version "22.1"
- :group 'gnus-summary-marks
- :type 'character)
- (defcustom gnus-recent-mark ?N
- "*Mark used for articles that are recent."
- :version "22.1"
- :group 'gnus-summary-marks
- :type 'character)
- (defcustom gnus-cached-mark ?*
- "*Mark used for articles that are in the cache."
- :group 'gnus-summary-marks
- :type 'character)
- (defcustom gnus-saved-mark ?S
- "*Mark used for articles that have been saved."
- :group 'gnus-summary-marks
- :type 'character)
- (defcustom gnus-unseen-mark ?.
- "*Mark used for articles that haven't been seen."
- :version "22.1"
- :group 'gnus-summary-marks
- :type 'character)
- (defcustom gnus-no-mark ? ;Whitespace
- "*Mark used for articles that have no other secondary mark."
- :version "22.1"
- :group 'gnus-summary-marks
- :type 'character)
- (defcustom gnus-ancient-mark ?O
- "*Mark used for ancient articles."
- :group 'gnus-summary-marks
- :type 'character)
- (defcustom gnus-sparse-mark ?Q
- "*Mark used for sparsely reffed articles."
- :group 'gnus-summary-marks
- :type 'character)
- (defcustom gnus-canceled-mark ?G
- "*Mark used for canceled articles."
- :group 'gnus-summary-marks
- :type 'character)
- (defcustom gnus-duplicate-mark ?M
- "*Mark used for duplicate articles."
- :group 'gnus-summary-marks
- :type 'character)
- (defcustom gnus-undownloaded-mark ?-
- "*Mark used for articles that weren't downloaded."
- :version "22.1"
- :group 'gnus-summary-marks
- :type 'character)
- (defcustom gnus-downloaded-mark ?+
- "*Mark used for articles that were downloaded."
- :group 'gnus-summary-marks
- :type 'character)
- (defcustom gnus-downloadable-mark ?%
- "*Mark used for articles that are to be downloaded."
- :group 'gnus-summary-marks
- :type 'character)
- (defcustom gnus-unsendable-mark ?=
- "*Mark used for articles that won't be sent."
- :group 'gnus-summary-marks
- :type 'character)
- (defcustom gnus-score-over-mark ?+
- "*Score mark used for articles with high scores."
- :group 'gnus-summary-marks
- :type 'character)
- (defcustom gnus-score-below-mark ?-
- "*Score mark used for articles with low scores."
- :group 'gnus-summary-marks
- :type 'character)
- (defcustom gnus-empty-thread-mark ? ;Whitespace
- "*There is no thread under the article."
- :group 'gnus-summary-marks
- :type 'character)
- (defcustom gnus-not-empty-thread-mark ?=
- "*There is a thread under the article."
- :group 'gnus-summary-marks
- :type 'character)
- (defcustom gnus-view-pseudo-asynchronously nil
- "*If non-nil, Gnus will view pseudo-articles asynchronously."
- :group 'gnus-extract-view
- :type 'boolean)
- (defcustom gnus-auto-expirable-marks
- (list gnus-killed-mark gnus-del-mark gnus-catchup-mark
- gnus-low-score-mark gnus-ancient-mark gnus-read-mark
- gnus-duplicate-mark)
- "*The list of marks converted into expiration if a group is auto-expirable."
- :version "24.1"
- :group 'gnus-summary
- :type '(repeat character))
- (defcustom gnus-inhibit-user-auto-expire t
- "*If non-nil, user marking commands will not mark an article as expirable, even if the group has auto-expire turned on."
- :version "21.1"
- :group 'gnus-summary
- :type 'boolean)
- (defcustom gnus-mark-copied-or-moved-articles-as-expirable nil
- "If non-nil, mark articles copied or moved to auto-expire group as expirable.
- If nil, the expirable marks will be unchanged except that the marks
- will be removed when copying or moving articles to a group that has
- not turned auto-expire on. If non-nil, articles that have been read
- will be marked as expirable when being copied or moved to a group in
- which auto-expire is turned on."
- :version "23.2"
- :type 'boolean
- :group 'gnus-summary-marks)
- (defcustom gnus-view-pseudos nil
- "*If `automatic', pseudo-articles will be viewed automatically.
- If `not-confirm', pseudos will be viewed automatically, and the user
- will not be asked to confirm the command."
- :group 'gnus-extract-view
- :type '(choice (const :tag "off" nil)
- (const automatic)
- (const not-confirm)))
- (defcustom gnus-view-pseudos-separately t
- "*If non-nil, one pseudo-article will be created for each file to be viewed.
- If nil, all files that use the same viewing command will be given as a
- list of parameters to that command."
- :group 'gnus-extract-view
- :type 'boolean)
- (defcustom gnus-insert-pseudo-articles t
- "*If non-nil, insert pseudo-articles when decoding articles."
- :group 'gnus-extract-view
- :type 'boolean)
- (defcustom gnus-summary-dummy-line-format
- " %(: :%) %S\n"
- "*The format specification for the dummy roots in the summary buffer.
- It works along the same lines as a normal formatting string,
- with some simple extensions.
- %S The subject
- General format specifiers can also be used.
- See `(gnus)Formatting Variables'."
- :link '(custom-manual "(gnus)Formatting Variables")
- :group 'gnus-threading
- :type 'string)
- (defcustom gnus-summary-mode-line-format "Gnus: %g [%A] %Z"
- "*The format specification for the summary mode line.
- It works along the same lines as a normal formatting string,
- with some simple extensions:
- %G Group name
- %p Unprefixed group name
- %A Current article number
- %z Current article score
- %V Gnus version
- %U Number of unread articles in the group
- %e Number of unselected articles in the group
- %Z A string with unread/unselected article counts
- %g Shortish group name
- %S Subject of the current article
- %u User-defined spec
- %s Current score file name
- %d Number of dormant articles
- %r Number of articles that have been marked as read in this session
- %E Number of articles expunged by the score files"
- :group 'gnus-summary-format
- :type 'string)
- (defcustom gnus-list-identifiers nil
- "Regexp that matches list identifiers to be removed from subject.
- This can also be a list of regexps."
- :version "21.1"
- :group 'gnus-summary-format
- :group 'gnus-article-hiding
- :type '(choice (const :tag "none" nil)
- (regexp :value ".*")
- (repeat :value (".*") regexp)))
- (defcustom gnus-summary-mark-below 0
- "*Mark all articles with a score below this variable as read.
- This variable is local to each summary buffer and usually set by the
- score file."
- :group 'gnus-score-default
- :type 'integer)
- (defun gnus-widget-reversible-match (widget value)
- "Ignoring WIDGET, convert VALUE to internal form.
- VALUE should have the form `FOO' or `(not FOO)', where FOO is an symbol."
- ;; (debug value)
- (or (symbolp value)
- (and (listp value)
- (eq (length value) 2)
- (eq (nth 0 value) 'not)
- (symbolp (nth 1 value)))))
- (defun gnus-widget-reversible-to-internal (widget value)
- "Ignoring WIDGET, convert VALUE to internal form.
- VALUE should have the form `FOO' or `(not FOO)', where FOO is an atom.
- FOO is converted to (FOO nil) and (not FOO) is converted to (FOO t)."
- ;; (debug value)
- (if (atom value)
- (list value nil)
- (list (nth 1 value) t)))
- (defun gnus-widget-reversible-to-external (widget value)
- "Ignoring WIDGET, convert VALUE to external form.
- VALUE should have the form `(FOO nil)' or `(FOO t)', where FOO is an atom.
- \(FOO nil) is converted to FOO and (FOO t) is converted to (not FOO)."
- ;; (debug value)
- (if (nth 1 value)
- (list 'not (nth 0 value))
- (nth 0 value)))
- (define-widget 'gnus-widget-reversible 'group
- "A `group' that convert values."
- :match 'gnus-widget-reversible-match
- :value-to-internal 'gnus-widget-reversible-to-internal
- :value-to-external 'gnus-widget-reversible-to-external)
- (defcustom gnus-article-sort-functions '(gnus-article-sort-by-number)
- "*List of functions used for sorting articles in the summary buffer.
- Each function takes two articles and returns non-nil if the first
- article should be sorted before the other. If you use more than one
- function, the primary sort function should be the last. You should
- probably always include `gnus-article-sort-by-number' in the list of
- sorting functions -- preferably first. Also note that sorting by date
- is often much slower than sorting by number, and the sorting order is
- very similar. (Sorting by date means sorting by the time the message
- was sent, sorting by number means sorting by arrival time.)
- Each item can also be a list `(not F)' where F is a function;
- this reverses the sort order.
- Ready-made functions include `gnus-article-sort-by-number',
- `gnus-article-sort-by-author', `gnus-article-sort-by-subject',
- `gnus-article-sort-by-date', `gnus-article-sort-by-random'
- and `gnus-article-sort-by-score'.
- When threading is turned on, the variable `gnus-thread-sort-functions'
- controls how articles are sorted."
- :group 'gnus-summary-sort
- :type '(repeat (gnus-widget-reversible
- (choice (function-item gnus-article-sort-by-number)
- (function-item gnus-article-sort-by-author)
- (function-item gnus-article-sort-by-subject)
- (function-item gnus-article-sort-by-date)
- (function-item gnus-article-sort-by-score)
- (function-item gnus-article-sort-by-random)
- (function :tag "other"))
- (boolean :tag "Reverse order"))))
- (defcustom gnus-thread-sort-functions '(gnus-thread-sort-by-number)
- "*List of functions used for sorting threads in the summary buffer.
- By default, threads are sorted by article number.
- Each function takes two threads and returns non-nil if the first
- thread should be sorted before the other. If you use more than one
- function, the primary sort function should be the last. You should
- probably always include `gnus-thread-sort-by-number' in the list of
- sorting functions -- preferably first. Also note that sorting by date
- is often much slower than sorting by number, and the sorting order is
- very similar. (Sorting by date means sorting by the time the message
- was sent, sorting by number means sorting by arrival time.)
- Each list item can also be a list `(not F)' where F is a
- function; this specifies reversed sort order.
- Ready-made functions include `gnus-thread-sort-by-number',
- `gnus-thread-sort-by-author', `gnus-thread-sort-by-recipient'
- `gnus-thread-sort-by-subject', `gnus-thread-sort-by-date',
- `gnus-thread-sort-by-score', `gnus-thread-sort-by-most-recent-number',
- `gnus-thread-sort-by-most-recent-date', `gnus-thread-sort-by-random',
- and `gnus-thread-sort-by-total-score' (see
- `gnus-thread-score-function').
- When threading is turned off, the variable
- `gnus-article-sort-functions' controls how articles are sorted.
- By default, threads and their subthreads are sorted according to
- the value of this variable. To use a different sorting order for
- subthreads, customize `gnus-subthread-sort-functions'."
- :group 'gnus-summary-sort
- :type '(repeat
- (gnus-widget-reversible
- (choice (function-item gnus-thread-sort-by-number)
- (function-item gnus-thread-sort-by-author)
- (function-item gnus-thread-sort-by-recipient)
- (function-item gnus-thread-sort-by-subject)
- (function-item gnus-thread-sort-by-date)
- (function-item gnus-thread-sort-by-score)
- (function-item gnus-thread-sort-by-most-recent-number)
- (function-item gnus-thread-sort-by-most-recent-date)
- (function-item gnus-thread-sort-by-random)
- (function-item gnus-thread-sort-by-total-score)
- (function :tag "other"))
- (boolean :tag "Reverse order"))))
- (defcustom gnus-subthread-sort-functions 'gnus-thread-sort-functions
- "*List of functions used for sorting subthreads in the summary buffer.
- By default, subthreads are sorted the same as threads, i.e.,
- according to the value of `gnus-thread-sort-functions'."
- :version "24.4"
- :group 'gnus-summary-sort
- :type '(choice
- (const :tag "Sort subthreads like threads" gnus-thread-sort-functions)
- (repeat
- (gnus-widget-reversible
- (choice (function-item gnus-thread-sort-by-number)
- (function-item gnus-thread-sort-by-author)
- (function-item gnus-thread-sort-by-recipient)
- (function-item gnus-thread-sort-by-subject)
- (function-item gnus-thread-sort-by-date)
- (function-item gnus-thread-sort-by-score)
- (function-item gnus-thread-sort-by-most-recent-number)
- (function-item gnus-thread-sort-by-most-recent-date)
- (function-item gnus-thread-sort-by-random)
- (function-item gnus-thread-sort-by-total-score)
- (function :tag "other"))
- (boolean :tag "Reverse order")))))
- (defcustom gnus-thread-score-function '+
- "*Function used for calculating the total score of a thread.
- The function is called with the scores of the article and each
- subthread and should then return the score of the thread.
- Some functions you can use are `+', `max', or `min'."
- :group 'gnus-summary-sort
- :type 'function)
- (defcustom gnus-summary-expunge-below nil
- "All articles that have a score less than this variable will be expunged.
- This variable is local to the summary buffers."
- :group 'gnus-score-default
- :type '(choice (const :tag "off" nil)
- integer))
- (defcustom gnus-thread-expunge-below nil
- "All threads that have a total score less than this variable will be expunged.
- See `gnus-thread-score-function' for en explanation of what a
- \"thread score\" is.
- This variable is local to the summary buffers."
- :group 'gnus-threading
- :group 'gnus-score-default
- :type '(choice (const :tag "off" nil)
- integer))
- (defcustom gnus-summary-mode-hook nil
- "*A hook for Gnus summary mode.
- This hook is run before any variables are set in the summary buffer."
- :options '(turn-on-gnus-mailing-list-mode gnus-pick-mode)
- :group 'gnus-summary-various
- :type 'hook)
- ;; Extracted from gnus-xmas-redefine in order to preserve user settings
- (when (featurep 'xemacs)
- (add-hook 'gnus-summary-mode-hook 'gnus-xmas-summary-menu-add)
- (add-hook 'gnus-summary-mode-hook 'gnus-xmas-setup-summary-toolbar)
- (add-hook 'gnus-summary-mode-hook
- 'gnus-xmas-switch-horizontal-scrollbar-off))
- (defcustom gnus-summary-menu-hook nil
- "*Hook run after the creation of the summary mode menu."
- :group 'gnus-summary-visual
- :type 'hook)
- (defcustom gnus-summary-exit-hook nil
- "*A hook called on exit from the summary buffer.
- It will be called with point in the group buffer."
- :group 'gnus-summary-exit
- :type 'hook)
- (defcustom gnus-summary-prepare-hook nil
- "*A hook called after the summary buffer has been generated.
- If you want to modify the summary buffer, you can use this hook."
- :group 'gnus-summary-various
- :type 'hook)
- (defcustom gnus-summary-prepared-hook nil
- "*A hook called as the last thing after the summary buffer has been generated."
- :group 'gnus-summary-various
- :type 'hook)
- (defcustom gnus-summary-generate-hook nil
- "*A hook run just before generating the summary buffer.
- This hook is commonly used to customize threading variables and the
- like."
- :group 'gnus-summary-various
- :type 'hook)
- (defcustom gnus-select-group-hook nil
- "*A hook called when a newsgroup is selected.
- If you'd like to simplify subjects like the
- `gnus-summary-next-same-subject' command does, you can use the
- following hook:
- (add-hook gnus-select-group-hook
- (lambda ()
- (mapcar (lambda (header)
- (mail-header-set-subject
- header
- (gnus-simplify-subject
- (mail-header-subject header) 're-only)))
- gnus-newsgroup-headers)))"
- :group 'gnus-group-select
- :type 'hook)
- (defcustom gnus-select-article-hook nil
- "*A hook called when an article is selected."
- :group 'gnus-summary-choose
- :options '(gnus-agent-fetch-selected-article)
- :type 'hook)
- (defcustom gnus-visual-mark-article-hook
- (list 'gnus-highlight-selected-summary)
- "*Hook run after selecting an article in the summary buffer.
- It is meant to be used for highlighting the article in some way. It
- is not run if `gnus-visual' is nil."
- :group 'gnus-summary-visual
- :type 'hook)
- (defcustom gnus-parse-headers-hook nil
- "*A hook called before parsing the headers."
- :group 'gnus-various
- :type 'hook)
- (defcustom gnus-exit-group-hook nil
- "*A hook called when exiting summary mode.
- This hook is not called from the non-updating exit commands like `Q'."
- :group 'gnus-various
- :type 'hook)
- (defcustom gnus-summary-update-hook nil
- "*A hook called when a summary line is changed.
- The hook will not be called if `gnus-visual' is nil.
- The default function `gnus-summary-highlight-line' will
- highlight the line according to the `gnus-summary-highlight'
- variable."
- :group 'gnus-summary-visual
- :type 'hook)
- (defcustom gnus-mark-article-hook '(gnus-summary-mark-read-and-unread-as-read)
- "*A hook called when an article is selected for the first time.
- The hook is intended to mark an article as read (or unread)
- automatically when it is selected."
- :group 'gnus-summary-choose
- :type 'hook)
- (defcustom gnus-group-no-more-groups-hook nil
- "*A hook run when returning to group mode having no more (unread) groups."
- :group 'gnus-group-select
- :type 'hook)
- (defcustom gnus-ps-print-hook nil
- "*A hook run before ps-printing something from Gnus."
- :group 'gnus-summary
- :type 'hook)
- (defcustom gnus-summary-article-move-hook nil
- "*A hook called after an article is moved, copied, respooled, or crossposted."
- :version "22.1"
- :group 'gnus-summary
- :type 'hook)
- (defcustom gnus-summary-article-delete-hook nil
- "*A hook called after an article is deleted."
- :version "22.1"
- :group 'gnus-summary
- :type 'hook)
- (defcustom gnus-summary-article-expire-hook nil
- "*A hook called after an article is expired."
- :version "22.1"
- :group 'gnus-summary
- :type 'hook)
- (defcustom gnus-summary-display-arrow
- (and (fboundp 'display-graphic-p)
- (display-graphic-p))
- "*If non-nil, display an arrow highlighting the current article."
- :version "22.1"
- :group 'gnus-summary
- :type 'boolean)
- (defcustom gnus-summary-selected-face 'gnus-summary-selected
- "Face used for highlighting the current article in the summary buffer."
- :group 'gnus-summary-visual
- :type 'face)
- (defvar gnus-tmp-downloaded nil)
- (defcustom gnus-summary-highlight
- '(((eq mark gnus-canceled-mark)
- . gnus-summary-cancelled)
- ((and uncached (> score default-high))
- . gnus-summary-high-undownloaded)
- ((and uncached (< score default-low))
- . gnus-summary-low-undownloaded)
- (uncached
- . gnus-summary-normal-undownloaded)
- ((and (> score default-high)
- (or (eq mark gnus-dormant-mark)
- (eq mark gnus-ticked-mark)))
- . gnus-summary-high-ticked)
- ((and (< score default-low)
- (or (eq mark gnus-dormant-mark)
- (eq mark gnus-ticked-mark)))
- . gnus-summary-low-ticked)
- ((or (eq mark gnus-dormant-mark)
- (eq mark gnus-ticked-mark))
- . gnus-summary-normal-ticked)
- ((and (> score default-high) (eq mark gnus-ancient-mark))
- . gnus-summary-high-ancient)
- ((and (< score default-low) (eq mark gnus-ancient-mark))
- . gnus-summary-low-ancient)
- ((eq mark gnus-ancient-mark)
- . gnus-summary-normal-ancient)
- ((and (> score default-high) (eq mark gnus-unread-mark))
- . gnus-summary-high-unread)
- ((and (< score default-low) (eq mark gnus-unread-mark))
- . gnus-summary-low-unread)
- ((eq mark gnus-unread-mark)
- . gnus-summary-normal-unread)
- ((> score default-high)
- . gnus-summary-high-read)
- ((< score default-low)
- . gnus-summary-low-read)
- (t
- . gnus-summary-normal-read))
- "*Controls the highlighting of summary buffer lines.
- A list of (FORM . FACE) pairs. When deciding how a particular
- summary line should be displayed, each form is evaluated. The content
- of the face field after the first true form is used. You can change
- how those summary lines are displayed, by editing the face field.
- You can use the following variables in the FORM field.
- score: The article's score.
- default: The default article score.
- default-high: The default score for high scored articles.
- default-low: The default score for low scored articles.
- mark: The article's mark.
- uncached: Non-nil if the article is uncached."
- :group 'gnus-summary-visual
- :type '(repeat (cons (sexp :tag "Form" nil)
- face)))
- (put 'gnus-summary-highlight 'risky-local-variable t)
- (defcustom gnus-alter-header-function nil
- "Function called to allow alteration of article header structures.
- The function is called with one parameter, the article header vector,
- which it may alter in any way."
- :type '(choice (const :tag "None" nil)
- function)
- :group 'gnus-summary)
- (defvar gnus-decode-encoded-word-function 'mail-decode-encoded-word-string
- "Function used to decode a string with encoded words.")
- (defvar gnus-decode-encoded-address-function
- 'mail-decode-encoded-address-string
- "Function used to decode addresses with encoded words.")
- (defcustom gnus-extra-headers '(To Cc Keywords Gcc Newsgroups X-GM-LABELS)
- "*Extra headers to parse."
- :version "25.1"
- :group 'gnus-summary
- :type '(repeat symbol))
- (defcustom gnus-ignored-from-addresses
- (and user-mail-address
- (not (string= user-mail-address ""))
- (regexp-quote user-mail-address))
- "*From headers that may be suppressed in favor of To headers.
- This can be a regexp or a list of regexps."
- :version "21.1"
- :group 'gnus-summary
- :type '(choice regexp
- (repeat :tag "Regexp List" regexp)))
- (defsubst gnus-ignored-from-addresses ()
- (gmm-regexp-concat gnus-ignored-from-addresses))
- (defcustom gnus-summary-to-prefix "-> "
- "*String prefixed to the To field in the summary line when
- using `gnus-ignored-from-addresses'."
- :version "22.1"
- :group 'gnus-summary
- :type 'string)
- (defcustom gnus-summary-newsgroup-prefix "=> "
- "*String prefixed to the Newsgroup field in the summary
- line when using the option `gnus-ignored-from-addresses'."
- :version "22.1"
- :group 'gnus-summary
- :type 'string)
- (defcustom gnus-newsgroup-ignored-charsets '(unknown-8bit x-unknown)
- "List of charsets that should be ignored.
- When these charsets are used in the \"charset\" parameter, the
- default charset will be used instead."
- :version "21.1"
- :type '(repeat symbol)
- :group 'gnus-charset)
- (defcustom gnus-newsgroup-maximum-articles nil
- "The maximum number of articles a newsgroup.
- If this is a number, old articles in a newsgroup exceeding this number
- are silently ignored. If it is nil, no article is ignored. Note that
- setting this variable to a number might prevent you from reading very
- old articles."
- :group 'gnus-group-select
- :version "22.2"
- :type '(choice (const :tag "No limit" nil)
- integer))
- (gnus-define-group-parameter
- ignored-charsets
- :type list
- :function-document
- "Return the ignored charsets of GROUP."
- :variable gnus-group-ignored-charsets-alist
- :variable-default
- '(("alt\\.chinese\\.text" iso-8859-1))
- :variable-document
- "Alist of regexps (to match group names) and charsets that should be ignored.
- When these charsets are used in the \"charset\" parameter, the
- default charset will be used instead."
- :variable-group gnus-charset
- :variable-type '(repeat (cons (regexp :tag "Group")
- (repeat symbol)))
- :parameter-type '(choice :tag "Ignored charsets"
- :value nil
- (repeat (symbol)))
- :parameter-document "\
- List of charsets that should be ignored.
- When these charsets are used in the \"charset\" parameter, the
- default charset will be used instead.")
- (defcustom gnus-group-highlight-words-alist nil
- "Alist of group regexps and highlight regexps.
- This variable uses the same syntax as `gnus-emphasis-alist'."
- :version "21.1"
- :type '(repeat (cons (regexp :tag "Group")
- (repeat (list (regexp :tag "Highlight regexp")
- (number :tag "Group for entire word" 0)
- (number :tag "Group for displayed part" 0)
- (symbol :tag "Face"
- gnus-emphasis-highlight-words)))))
- :group 'gnus-summary-visual)
- (defcustom gnus-summary-show-article-charset-alist
- nil
- "Alist of number and charset.
- The article will be shown with the charset corresponding to the
- numbered argument.
- For example: ((1 . cn-gb-2312) (2 . big5))."
- :version "21.1"
- :type '(repeat (cons (number :tag "Argument" 1)
- (symbol :tag "Charset")))
- :group 'gnus-charset)
- (defcustom gnus-preserve-marks t
- "Whether marks are preserved when moving, copying and respooling messages."
- :version "21.1"
- :type 'boolean
- :group 'gnus-summary-marks)
- (defcustom gnus-alter-articles-to-read-function nil
- "Function to be called to alter the list of articles to be selected."
- :type '(choice (const nil) function)
- :group 'gnus-summary)
- (defcustom gnus-orphan-score nil
- "*All orphans get this score added. Set in the score file."
- :group 'gnus-score-default
- :type '(choice (const nil)
- integer))
- (defcustom gnus-summary-save-parts-default-mime "image/.*"
- "*A regexp to match MIME parts when saving multiple parts of a
- message with `gnus-summary-save-parts' (\\<gnus-summary-mode-map>\\[gnus-summary-save-parts]).
- This regexp will be used by default when prompting the user for which
- type of files to save."
- :group 'gnus-summary
- :type 'regexp)
- (defcustom gnus-read-all-available-headers nil
- "Whether Gnus should parse all headers made available to it.
- This is mostly relevant for slow back ends where the user may
- wish to widen the summary buffer to include all headers
- that were fetched."
- :version "22.1"
- :group 'gnus-summary
- :type '(choice boolean regexp))
- (defcustom gnus-summary-pipe-output-default-command nil
- "Command (and optional arguments) used to pipe article to subprocess.
- This will be used as the default command if it is non-nil. The value
- will be updated if you modify it when executing the command
- `gnus-summary-pipe-output' or the function `gnus-summary-save-in-pipe'."
- :version "23.1" ;; No Gnus
- :group 'gnus-summary
- :type '(radio (const :tag "None" nil) (string :tag "Command")))
- (defcustom gnus-summary-muttprint-program "muttprint"
- "Command (and optional arguments) used to run Muttprint.
- The value will be updated if you modify it when executing the command
- `gnus-summary-muttprint'."
- :version "22.1"
- :group 'gnus-summary
- :type 'string)
- (defcustom gnus-article-loose-mime t
- "If non-nil, don't require MIME-Version header.
- Some brain-damaged MUA/MTA, e.g. Lotus Domino 5.0.6 clients, does not
- supply the MIME-Version header or deliberately strip it from the mail.
- If non-nil (the default), Gnus will treat some articles as MIME
- even if the MIME-Version header is missing."
- :version "22.1"
- :type 'boolean
- :group 'gnus-article-mime)
- (defcustom gnus-article-emulate-mime t
- "If non-nil, use MIME emulation for uuencode and the like.
- This means that Gnus will search message bodies for text that look
- like uuencoded bits, yEncoded bits, and so on, and present that using
- the normal Gnus MIME machinery."
- :version "22.1"
- :type 'boolean
- :group 'gnus-article-mime)
- ;;; Internal variables
- (defvar gnus-summary-display-cache nil)
- (defvar gnus-article-mime-handles nil)
- (defvar gnus-article-decoded-p nil)
- (defvar gnus-article-charset nil)
- (defvar gnus-article-ignored-charsets nil)
- (defvar gnus-scores-exclude-files nil)
- (defvar gnus-page-broken nil)
- (defvar gnus-original-article nil)
- (defvar gnus-article-internal-prepare-hook nil)
- (defvar gnus-newsgroup-process-stack nil)
- (defvar gnus-thread-indent-array nil)
- (defvar gnus-thread-indent-array-level gnus-thread-indent-level)
- (defvar gnus-sort-gathered-threads-function 'gnus-thread-sort-by-number
- "Function called to sort the articles within a thread after it has been gathered together.")
- (defvar gnus-summary-save-parts-type-history nil)
- (defvar gnus-summary-save-parts-last-directory mm-default-directory)
- ;; Avoid highlighting in kill files.
- (defvar gnus-summary-inhibit-highlight nil)
- (defvar gnus-newsgroup-selected-overlay nil)
- (defvar gnus-inhibit-limiting nil)
- (defvar gnus-newsgroup-adaptive-score-file nil)
- (defvar gnus-current-score-file nil)
- (defvar gnus-current-move-group nil)
- (defvar gnus-current-copy-group nil)
- (defvar gnus-current-crosspost-group nil)
- (defvar gnus-newsgroup-display nil)
- (defvar gnus-newsgroup-dependencies nil)
- (defvar gnus-newsgroup-adaptive nil)
- (defvar gnus-summary-display-article-function nil)
- (defvar gnus-summary-highlight-line-function nil
- "Function called after highlighting a summary line.")
- (defvar gnus-summary-line-format-alist
- `((?N ,(macroexpand '(mail-header-number gnus-tmp-header)) ?d)
- (?S ,(macroexpand '(mail-header-subject gnus-tmp-header)) ?s)
- (?s gnus-tmp-subject-or-nil ?s)
- (?n gnus-tmp-name ?s)
- (?A (car (cdr (funcall gnus-extract-address-components gnus-tmp-from)))
- ?s)
- (?a (or (car (funcall gnus-extract-address-components gnus-tmp-from))
- gnus-tmp-from) ?s)
- (?F gnus-tmp-from ?s)
- (?x ,(macroexpand '(mail-header-xref gnus-tmp-header)) ?s)
- (?D ,(macroexpand '(mail-header-date gnus-tmp-header)) ?s)
- (?d (gnus-dd-mmm (mail-header-date gnus-tmp-header)) ?s)
- (?o (gnus-date-iso8601 (mail-header-date gnus-tmp-header)) ?s)
- (?M ,(macroexpand '(mail-header-id gnus-tmp-header)) ?s)
- (?r ,(macroexpand '(mail-header-references gnus-tmp-header)) ?s)
- (?c (or (mail-header-chars gnus-tmp-header) 0) ?d)
- (?k (gnus-summary-line-message-size gnus-tmp-header) ?s)
- (?L gnus-tmp-lines ?s)
- (?Z (or (nnir-article-rsv (mail-header-number gnus-tmp-header))
- 0) ?d)
- (?G (or (nnir-article-group (mail-header-number gnus-tmp-header))
- "") ?s)
- (?g (or (gnus-group-short-name
- (nnir-article-group (mail-header-number gnus-tmp-header)))
- "") ?s)
- (?O gnus-tmp-downloaded ?c)
- (?I gnus-tmp-indentation ?s)
- (?T (if (= gnus-tmp-level 0) "" (make-string (frame-width) ? )) ?s)
- (?R gnus-tmp-replied ?c)
- (?\[ gnus-tmp-opening-bracket ?c)
- (?\] gnus-tmp-closing-bracket ?c)
- (?\> (make-string gnus-tmp-level ? ) ?s)
- (?\< (make-string (max 0 (- 20 gnus-tmp-level)) ? ) ?s)
- (?i gnus-tmp-score ?d)
- (?z gnus-tmp-score-char ?c)
- (?V (gnus-thread-total-score (and (boundp 'thread) (car thread))) ?d)
- (?U gnus-tmp-unread ?c)
- (?f (gnus-summary-from-or-to-or-newsgroups gnus-tmp-header gnus-tmp-from)
- ?s)
- (?t (gnus-summary-number-of-articles-in-thread
- (and (boundp 'thread) (car thread)) gnus-tmp-level)
- ?d)
- (?e (gnus-summary-number-of-articles-in-thread
- (and (boundp 'thread) (car thread)) gnus-tmp-level t)
- ?c)
- (?u gnus-tmp-user-defined ?s)
- (?P (gnus-pick-line-number) ?d)
- (?B gnus-tmp-thread-tree-header-string ?s)
- (user-date (gnus-user-date
- ,(macroexpand '(mail-header-date gnus-tmp-header))) ?s))
- "An alist of format specifications that can appear in summary lines.
- These are paired with what variables they correspond with, along with
- the type of the variable (string, integer, character, etc).")
- (defvar gnus-summary-dummy-line-format-alist
- `((?S gnus-tmp-subject ?s)
- (?N gnus-tmp-number ?d)
- (?u gnus-tmp-user-defined ?s)))
- (defvar gnus-summary-mode-line-format-alist
- `((?G gnus-tmp-group-name ?s)
- (?g (gnus-short-group-name gnus-tmp-group-name) ?s)
- (?p (gnus-group-real-name gnus-tmp-group-name) ?s)
- (?A gnus-tmp-article-number ?d)
- (?Z gnus-tmp-unread-and-unselected ?s)
- (?V gnus-version ?s)
- (?U gnus-tmp-unread-and-unticked ?d)
- (?S gnus-tmp-subject ?s)
- (?e gnus-tmp-unselected ?d)
- (?u gnus-tmp-user-defined ?s)
- (?d (length gnus-newsgroup-dormant) ?d)
- (?t (length gnus-newsgroup-marked) ?d)
- (?h (length gnus-newsgroup-spam-marked) ?d)
- (?r (length gnus-newsgroup-reads) ?d)
- (?z (gnus-summary-article-score gnus-tmp-article-number) ?d)
- (?E gnus-newsgroup-expunged-tally ?d)
- (?s (gnus-current-score-file-nondirectory) ?s)))
- ;; This is here rather than in gnus-art for compilation reasons.
- (defvar gnus-article-mode-line-format-alist
- (nconc '((?w (gnus-article-wash-status) ?s)
- (?m (gnus-article-mime-part-status) ?s))
- gnus-summary-mode-line-format-alist))
- (defvar gnus-last-search-regexp nil
- "Default regexp for article search command.")
- (defvar gnus-last-shell-command nil
- "Default shell command on article.")
- (defvar gnus-newsgroup-agentized nil
- "Locally bound in each summary buffer to indicate whether the server has been agentized.")
- (defvar gnus-newsgroup-begin nil)
- (defvar gnus-newsgroup-end nil)
- (defvar gnus-newsgroup-last-rmail nil)
- (defvar gnus-newsgroup-last-mail nil)
- (defvar gnus-newsgroup-last-folder nil)
- (defvar gnus-newsgroup-last-file nil)
- (defvar gnus-newsgroup-last-directory nil)
- (defvar gnus-newsgroup-auto-expire nil)
- (defvar gnus-newsgroup-active nil)
- (defvar gnus-newsgroup-highest nil)
- (defvar gnus-newsgroup-data nil)
- (defvar gnus-newsgroup-data-reverse nil)
- (defvar gnus-newsgroup-limit nil)
- (defvar gnus-newsgroup-limits nil)
- (defvar gnus-summary-use-undownloaded-faces nil)
- (defvar gnus-newsgroup-unreads nil
- "Sorted list of unread articles in the current newsgroup.")
- (defvar gnus-newsgroup-unselected nil
- "Sorted list of unselected unread articles in the current newsgroup.")
- (defvar gnus-newsgroup-reads nil
- "Alist of read articles and article marks in the current newsgroup.")
- (defvar gnus-newsgroup-expunged-tally nil)
- (defvar gnus-newsgroup-marked nil
- "Sorted list of ticked articles in the current newsgroup (a subset of unread art).")
- (defvar gnus-newsgroup-spam-marked nil
- "List of ranges of articles that have been marked as spam.")
- (defvar gnus-newsgroup-killed nil
- "List of ranges of articles that have been through the scoring process.")
- (defvar gnus-newsgroup-cached nil
- "Sorted list of articles that come from the article cache.")
- (defvar gnus-newsgroup-saved nil
- "List of articles that have been saved.")
- (defvar gnus-newsgroup-kill-headers nil)
- (defvar gnus-newsgroup-replied nil
- "List of articles that have been replied to in the current newsgroup.")
- (defvar gnus-newsgroup-forwarded nil
- "List of articles that have been forwarded in the current newsgroup.")
- (defvar gnus-newsgroup-expirable nil
- "Sorted list of articles in the current newsgroup that can be expired.")
- (defvar gnus-newsgroup-processable nil
- "List of articles in the current newsgroup that can be processed.")
- (defvar gnus-newsgroup-downloadable nil
- "Sorted list of articles in the current newsgroup that can be processed.")
- (defvar gnus-newsgroup-unfetched nil
- "Sorted list of articles in the current newsgroup whose headers have
- not been fetched into the agent.
- This list will always be a subset of gnus-newsgroup-undownloaded.")
- (defvar gnus-newsgroup-undownloaded nil
- "List of articles in the current newsgroup that haven't been downloaded.")
- (defvar gnus-newsgroup-unsendable nil
- "List of articles in the current newsgroup that won't be sent.")
- (defvar gnus-newsgroup-bookmarks nil
- "List of articles in the current newsgroup that have bookmarks.")
- (defvar gnus-newsgroup-dormant nil
- "Sorted list of dormant articles in the current newsgroup.")
- (defvar gnus-newsgroup-unseen nil
- "List of unseen articles in the current newsgroup.")
- (defvar gnus-newsgroup-seen nil
- "Range of seen articles in the current newsgroup.")
- (defvar gnus-newsgroup-unexist nil
- "Range of unexisting articles in the current newsgroup.")
- (defvar gnus-newsgroup-articles nil
- "List of articles in the current newsgroup.")
- (defvar gnus-newsgroup-scored nil
- "List of scored articles in the current newsgroup.")
- (defvar gnus-newsgroup-headers nil
- "List of article headers in the current newsgroup.")
- (defvar gnus-newsgroup-threads nil)
- (defvar gnus-newsgroup-prepared nil
- "Whether the current group has been prepared properly.")
- (defvar gnus-newsgroup-ancient nil
- "List of `gnus-fetch-old-headers' articles in the current newsgroup.")
- (defvar gnus-newsgroup-sparse nil)
- (defvar gnus-current-article nil)
- (defvar gnus-article-current nil)
- (defvar gnus-current-headers nil)
- (defvar gnus-have-all-headers nil)
- (defvar gnus-last-article nil)
- (defvar gnus-newsgroup-history nil)
- (defvar gnus-newsgroup-charset nil)
- (defvar gnus-newsgroup-ephemeral-charset nil)
- (defvar gnus-newsgroup-ephemeral-ignored-charsets nil)
- (defvar gnus-article-before-search nil)
- (defvar gnus-summary-local-variables
- '(gnus-newsgroup-name
- ;; Marks lists
- gnus-newsgroup-unreads
- gnus-newsgroup-unselected
- gnus-newsgroup-marked
- gnus-newsgroup-spam-marked
- gnus-newsgroup-reads
- gnus-newsgroup-saved
- gnus-newsgroup-replied
- gnus-newsgroup-forwarded
- gnus-newsgroup-expirable
- gnus-newsgroup-killed
- gnus-newsgroup-unseen
- gnus-newsgroup-seen
- gnus-newsgroup-unexist
- gnus-newsgroup-cached
- gnus-newsgroup-downloadable
- gnus-newsgroup-undownloaded
- gnus-newsgroup-unsendable
- gnus-newsgroup-begin gnus-newsgroup-end
- gnus-newsgroup-last-rmail gnus-newsgroup-last-mail
- gnus-newsgroup-last-folder gnus-newsgroup-last-file
- gnus-newsgroup-last-directory
- gnus-newsgroup-auto-expire
- gnus-newsgroup-processable
- gnus-newsgroup-unfetched
- gnus-newsgroup-articles
- gnus-newsgroup-bookmarks gnus-newsgroup-dormant
- gnus-newsgroup-headers gnus-newsgroup-threads
- gnus-newsgroup-prepared gnus-summary-highlight-line-function
- gnus-current-article gnus-current-headers gnus-have-all-headers
- gnus-last-article gnus-article-internal-prepare-hook
- (gnus-summary-article-delete-hook . global)
- (gnus-summary-article-move-hook . global)
- gnus-newsgroup-dependencies gnus-newsgroup-selected-overlay
- gnus-newsgroup-scored gnus-newsgroup-kill-headers
- gnus-thread-expunge-below
- gnus-score-alist gnus-current-score-file
- (gnus-summary-expunge-below . global)
- (gnus-summary-mark-below . global)
- (gnus-orphan-score . global)
- gnus-newsgroup-active gnus-scores-exclude-files
- gnus-newsgroup-highest
- gnus-newsgroup-history gnus-newsgroup-ancient
- gnus-newsgroup-sparse gnus-newsgroup-process-stack
- (gnus-newsgroup-adaptive . gnus-use-adaptive-scoring)
- gnus-newsgroup-adaptive-score-file (gnus-reffed-article-number . -1)
- (gnus-newsgroup-expunged-tally . 0)
- gnus-cache-removable-articles
- gnus-newsgroup-data gnus-newsgroup-data-reverse
- gnus-newsgroup-limit gnus-newsgroup-limits
- gnus-newsgroup-charset gnus-newsgroup-display
- gnus-summary-use-undownloaded-faces)
- "Variables that are buffer-local to the summary buffers.")
- (defvar gnus-newsgroup-variables nil
- "A list of variables that have separate values in different newsgroups.
- A list of newsgroup (summary buffer) local variables, or cons of
- variables and their default expressions to be evalled (when the default
- values are not nil), that should be made global while the summary buffer
- is active.
- Note: The default expressions will be evaluated (using function `eval')
- before assignment to the local variable rather than just assigned to it.
- If the default expression is the symbol `global', that symbol will not
- be evaluated but the global value of the local variable will be used
- instead.
- These variables can be used to set variables in the group parameters
- while still allowing them to affect operations done in other buffers.
- For example:
- \(setq gnus-newsgroup-variables
- '(message-use-followup-to
- (gnus-visible-headers .
- \"^From:\\\\|^Newsgroups:\\\\|^Subject:\\\\|^Date:\\\\|^To:\")))
- ")
- (eval-when-compile
- ;; Bind features so that require will believe that gnus-sum has
- ;; already been loaded (avoids infinite recursion)
- (let ((features (cons 'gnus-sum features)))
- (require 'gnus-art)))
- ;; MIME stuff.
- (defvar gnus-decode-encoded-word-methods
- '(mail-decode-encoded-word-string)
- "List of methods used to decode encoded words.
- This variable is a list of FUNCTION or (REGEXP . FUNCTION). If item
- is FUNCTION, FUNCTION will be apply to all newsgroups. If item is a
- \(REGEXP . FUNCTION), FUNCTION will be applied only to the newsgroups
- whose names match REGEXP.
- For example:
- \((\"chinese\" . gnus-decode-encoded-word-string-by-guess)
- mail-decode-encoded-word-string
- (\"chinese\" . rfc1843-decode-string))")
- (defvar gnus-decode-encoded-word-methods-cache nil)
- (defun gnus-multi-decode-encoded-word-string (string)
- "Apply the functions from `gnus-encoded-word-methods' that match."
- (unless (and gnus-decode-encoded-word-methods-cache
- (eq gnus-newsgroup-name
- (car gnus-decode-encoded-word-methods-cache)))
- (setq gnus-decode-encoded-word-methods-cache (list gnus-newsgroup-name))
- (dolist (method gnus-decode-encoded-word-methods)
- (if (symbolp method)
- (nconc gnus-decode-encoded-word-methods-cache (list method))
- (if (and gnus-newsgroup-name
- (string-match (car method) gnus-newsgroup-name))
- (nconc gnus-decode-encoded-word-methods-cache
- (list (cdr method)))))))
- (dolist (method (cdr gnus-decode-encoded-word-methods-cache) string)
- (setq string (funcall method string))))
- ;; Subject simplification.
- (defun gnus-simplify-whitespace (str)
- "Remove excessive whitespace from STR."
- ;; Multiple spaces.
- (while (string-match "[ \t][ \t]+" str)
- (setq str (concat (substring str 0 (match-beginning 0))
- " "
- (substring str (match-end 0)))))
- ;; Leading spaces.
- (when (string-match "^[ \t]+" str)
- (setq str (substring str (match-end 0))))
- ;; Trailing spaces.
- (when (string-match "[ \t]+$" str)
- (setq str (substring str 0 (match-beginning 0))))
- str)
- (defun gnus-simplify-all-whitespace (str)
- "Remove all whitespace from STR."
- (while (string-match "[ \t\n]+" str)
- (setq str (replace-match "" nil nil str)))
- str)
- (defsubst gnus-simplify-subject-re (subject)
- "Remove \"Re:\" from subject lines."
- (if (string-match message-subject-re-regexp subject)
- (substring subject (match-end 0))
- subject))
- (defun gnus-simplify-subject (subject &optional re-only)
- "Remove `Re:' and words in parentheses.
- If RE-ONLY is non-nil, strip leading `Re:'s only."
- (let ((case-fold-search t)) ;Ignore case.
- ;; Remove `Re:', `Re^N:', `Re(n)', and `Re[n]:'.
- (when (string-match "\\`\\(re\\([[(^][0-9]+[])]?\\)?:[ \t]*\\)+" subject)
- (setq subject (substring subject (match-end 0))))
- ;; Remove uninteresting prefixes.
- (when (and (not re-only)
- gnus-simplify-ignored-prefixes
- (string-match gnus-simplify-ignored-prefixes subject))
- (setq subject (substring subject (match-end 0))))
- ;; Remove words in parentheses from end.
- (unless re-only
- (while (string-match "[ \t\n]*([^()]*)[ \t\n]*\\'" subject)
- (setq subject (substring subject 0 (match-beginning 0)))))
- ;; Return subject string.
- subject))
- ;; Remove any leading "re:"s, any trailing paren phrases, and simplify
- ;; all whitespace.
- (defsubst gnus-simplify-buffer-fuzzy-step (regexp &optional newtext)
- (goto-char (point-min))
- (while (re-search-forward regexp nil t)
- (replace-match (or newtext ""))))
- (defun gnus-simplify-buffer-fuzzy (regexp)
- "Simplify string in the buffer fuzzily.
- The string in the accessible portion of the current buffer is simplified.
- It is assumed to be a single-line subject.
- Whitespace is generally cleaned up, and miscellaneous leading/trailing
- matter is removed. Additional things can be deleted by setting
- `gnus-simplify-subject-fuzzy-regexp'."
- (let ((case-fold-search t)
- (modified-tick))
- (gnus-simplify-buffer-fuzzy-step "\t" " ")
- (while (not (eq modified-tick (buffer-modified-tick)))
- (setq modified-tick (buffer-modified-tick))
- (cond
- ((listp regexp)
- (mapc 'gnus-simplify-buffer-fuzzy-step regexp))
- (regexp
- (gnus-simplify-buffer-fuzzy-step regexp)))
- (gnus-simplify-buffer-fuzzy-step "^ *\\[[-+?*!][-+?*!]\\] *")
- (gnus-simplify-buffer-fuzzy-step
- "^ *\\(re\\|fw\\|fwd\\)[[{(^0-9]*[])}]?[:;] *")
- (gnus-simplify-buffer-fuzzy-step "^[[].*:\\( .*\\)[]]$" "\\1"))
- (gnus-simplify-buffer-fuzzy-step " *[[{(][^()\n]*[]})] *$")
- (gnus-simplify-buffer-fuzzy-step " +" " ")
- (gnus-simplify-buffer-fuzzy-step " $")
- (gnus-simplify-buffer-fuzzy-step "^ +")))
- (defun gnus-simplify-subject-fuzzy (subject)
- "Simplify a subject string fuzzily.
- See `gnus-simplify-buffer-fuzzy' for details."
- (save-excursion
- (let ((regexp gnus-simplify-subject-fuzzy-regexp))
- (gnus-set-work-buffer)
- (let ((case-fold-search t))
- ;; Remove uninteresting prefixes.
- (when (and gnus-simplify-ignored-prefixes
- (string-match gnus-simplify-ignored-prefixes subject))
- (setq subject (substring subject (match-end 0))))
- (insert subject)
- (inline (gnus-simplify-buffer-fuzzy regexp))
- (buffer-string)))))
- (defsubst gnus-simplify-subject-fully (subject)
- "Simplify a subject string according to `gnus-summary-gather-subject-limit'."
- (cond
- (gnus-simplify-subject-functions
- (gnus-map-function gnus-simplify-subject-functions subject))
- ((null gnus-summary-gather-subject-limit)
- (gnus-simplify-subject-re subject))
- ((eq gnus-summary-gather-subject-limit 'fuzzy)
- (gnus-simplify-subject-fuzzy subject))
- ((numberp gnus-summary-gather-subject-limit)
- (truncate-string-to-width (gnus-simplify-subject-re subject)
- gnus-summary-gather-subject-limit))
- (t
- subject)))
- (defsubst gnus-subject-equal (s1 s2 &optional simple-first)
- "Check whether two subjects are equal.
- If optional argument SIMPLE-FIRST is t, first argument is already
- simplified."
- (cond
- ((null simple-first)
- (equal (gnus-simplify-subject-fully s1)
- (gnus-simplify-subject-fully s2)))
- (t
- (equal s1
- (gnus-simplify-subject-fully s2)))))
- (defun gnus-summary-bubble-group ()
- "Increase the score of the current group.
- This is a handy function to add to `gnus-summary-exit-hook' to
- increase the score of each group you read."
- (gnus-group-add-score gnus-newsgroup-name))
- ;;;
- ;;; Gnus summary mode
- ;;;
- (put 'gnus-summary-mode 'mode-class 'special)
- (defvar gnus-article-commands-menu)
- ;; Non-orthogonal keys
- (gnus-define-keys gnus-summary-mode-map
- " " gnus-summary-next-page
- [?\S-\ ] gnus-summary-prev-page
- "\177" gnus-summary-prev-page
- [delete] gnus-summary-prev-page
- "\r" gnus-summary-scroll-up
- "\M-\r" gnus-summary-scroll-down
- "n" gnus-summary-next-unread-article
- "p" gnus-summary-prev-unread-article
- "N" gnus-summary-next-article
- "P" gnus-summary-prev-article
- "\M-\C-n" gnus-summary-next-same-subject
- "\M-\C-p" gnus-summary-prev-same-subject
- "\M-n" gnus-summary-next-unread-subject
- "\M-p" gnus-summary-prev-unread-subject
- "." gnus-summary-first-unread-article
- "," gnus-summary-best-unread-article
- "\M-s" gnus-summary-search-article-forward
- "\M-r" gnus-summary-search-article-backward
- "\M-S" gnus-summary-repeat-search-article-forward
- "\M-R" gnus-summary-repeat-search-article-backward
- "<" gnus-summary-beginning-of-article
- ">" gnus-summary-end-of-article
- "j" gnus-summary-goto-article
- "^" gnus-summary-refer-parent-article
- "\M-^" gnus-summary-refer-article
- "u" gnus-summary-tick-article-forward
- "!" gnus-summary-tick-article-forward
- "U" gnus-summary-tick-article-backward
- "d" gnus-summary-mark-as-read-forward
- "D" gnus-summary-mark-as-read-backward
- "E" gnus-summary-mark-as-expirable
- "\M-u" gnus-summary-clear-mark-forward
- "\M-U" gnus-summary-clear-mark-backward
- "k" gnus-summary-kill-same-subject-and-select
- "\C-k" gnus-summary-kill-same-subject
- "\M-\C-k" gnus-summary-kill-thread
- "\M-\C-l" gnus-summary-lower-thread
- "e" gnus-summary-edit-article
- "#" gnus-summary-mark-as-processable
- "\M-#" gnus-summary-unmark-as-processable
- "\M-\C-t" gnus-summary-toggle-threads
- "\M-\C-s" gnus-summary-show-thread
- "\M-\C-h" gnus-summary-hide-thread
- "\M-\C-f" gnus-summary-next-thread
- "\M-\C-b" gnus-summary-prev-thread
- [(meta down)] gnus-summary-next-thread
- [(meta up)] gnus-summary-prev-thread
- "\M-\C-u" gnus-summary-up-thread
- "\M-\C-d" gnus-summary-down-thread
- "&" gnus-summary-execute-command
- "c" gnus-summary-catchup-and-exit
- "\C-w" gnus-summary-mark-region-as-read
- "\C-t" gnus-summary-toggle-truncation
- "?" gnus-summary-mark-as-dormant
- "\C-c\M-\C-s" gnus-summary-limit-include-expunged
- "\C-c\C-s\C-n" gnus-summary-sort-by-number
- "\C-c\C-s\C-m\C-n" gnus-summary-sort-by-most-recent-number
- "\C-c\C-s\C-l" gnus-summary-sort-by-lines
- "\C-c\C-s\C-c" gnus-summary-sort-by-chars
- "\C-c\C-s\C-a" gnus-summary-sort-by-author
- "\C-c\C-s\C-t" gnus-summary-sort-by-recipient
- "\C-c\C-s\C-s" gnus-summary-sort-by-subject
- "\C-c\C-s\C-d" gnus-summary-sort-by-date
- "\C-c\C-s\C-m\C-d" gnus-summary-sort-by-most-recent-date
- "\C-c\C-s\C-i" gnus-summary-sort-by-score
- "\C-c\C-s\C-o" gnus-summary-sort-by-original
- "\C-c\C-s\C-r" gnus-summary-sort-by-random
- "=" gnus-summary-expand-window
- "\C-x\C-s" gnus-summary-reselect-current-group
- "\M-g" gnus-summary-rescan-group
- "\C-c\C-r" gnus-summary-caesar-message
- "f" gnus-summary-followup
- "F" gnus-summary-followup-with-original
- "C" gnus-summary-cancel-article
- "r" gnus-summary-reply
- "R" gnus-summary-reply-with-original
- "\C-c\C-f" gnus-summary-mail-forward
- "o" gnus-summary-save-article
- "\C-o" gnus-summary-save-article-mail
- "|" gnus-summary-pipe-output
- "\M-k" gnus-summary-edit-local-kill
- "\M-K" gnus-summary-edit-global-kill
- ;; "V" gnus-version
- "\C-c\C-d" gnus-summary-describe-group
- "q" gnus-summary-exit
- "Q" gnus-summary-exit-no-update
- "\C-c\C-i" gnus-info-find-node
- gnus-mouse-2 gnus-mouse-pick-article
- [follow-link] mouse-face
- "m" gnus-summary-mail-other-window
- "a" gnus-summary-post-news
- "x" gnus-summary-limit-to-unread
- "s" gnus-summary-isearch-article
- "\t" gnus-summary-widget-forward
- [backtab] gnus-summary-widget-backward
- "t" gnus-summary-toggle-header
- "g" gnus-summary-show-article
- "l" gnus-summary-goto-last-article
- "\C-c\C-v\C-v" gnus-uu-decode-uu-view
- "\C-d" gnus-summary-enter-digest-group
- "\M-\C-d" gnus-summary-read-document
- "\M-\C-e" gnus-summary-edit-parameters
- "\M-\C-a" gnus-summary-customize-parameters
- "\C-c\C-b" gnus-bug
- "*" gnus-cache-enter-article
- "\M-*" gnus-cache-remove-article
- "\M-&" gnus-summary-universal-argument
- "\C-l" gnus-recenter
- "I" gnus-summary-increase-score
- "L" gnus-summary-lower-score
- "\M-i" gnus-symbolic-argument
- "h" gnus-summary-select-article-buffer
- "b" gnus-article-view-part
- "\M-t" gnus-summary-toggle-display-buttonized
- "V" gnus-summary-score-map
- "X" gnus-uu-extract-map
- "S" gnus-summary-send-map)
- ;; Sort of orthogonal keymap
- (gnus-define-keys (gnus-summary-mark-map "M" gnus-summary-mode-map)
- "t" gnus-summary-tick-article-forward
- "!" gnus-summary-tick-article-forward
- "d" gnus-summary-mark-as-read-forward
- "r" gnus-summary-mark-as-read-forward
- "c" gnus-summary-clear-mark-forward
- " " gnus-summary-clear-mark-forward
- "e" gnus-summary-mark-as-expirable
- "x" gnus-summary-mark-as-expirable
- "?" gnus-summary-mark-as-dormant
- "b" gnus-summary-set-bookmark
- "B" gnus-summary-remove-bookmark
- "#" gnus-summary-mark-as-processable
- "\M-#" gnus-summary-unmark-as-processable
- "S" gnus-summary-limit-include-expunged
- "C" gnus-summary-catchup
- "H" gnus-summary-catchup-to-here
- "h" gnus-summary-catchup-from-here
- "\C-c" gnus-summary-catchup-all
- "k" gnus-summary-kill-same-subject-and-select
- "K" gnus-summary-kill-same-subject
- "P" gnus-uu-mark-map)
- (gnus-define-keys (gnus-summary-mscore-map "V" gnus-summary-mark-map)
- "c" gnus-summary-clear-above
- "u" gnus-summary-tick-above
- "m" gnus-summary-mark-above
- "k" gnus-summary-kill-below)
- (gnus-define-keys (gnus-summary-limit-map "/" gnus-summary-mode-map)
- "/" gnus-summary-limit-to-subject
- "n" gnus-summary-limit-to-articles
- "b" gnus-summary-limit-to-bodies
- "h" gnus-summary-limit-to-headers
- "w" gnus-summary-pop-limit
- "s" gnus-summary-limit-to-subject
- "a" gnus-summary-limit-to-author
- "u" gnus-summary-limit-to-unread
- "m" gnus-summary-limit-to-marks
- "M" gnus-summary-limit-exclude-marks
- "v" gnus-summary-limit-to-score
- "*" gnus-summary-limit-include-cached
- "D" gnus-summary-limit-include-dormant
- "T" gnus-summary-limit-include-thread
- "d" gnus-summary-limit-exclude-dormant
- "t" gnus-summary-limit-to-age
- "." gnus-summary-limit-to-unseen
- "x" gnus-summary-limit-to-extra
- "p" gnus-summary-limit-to-display-predicate
- "E" gnus-summary-limit-include-expunged
- "c" gnus-summary-limit-exclude-childless-dormant
- "C" gnus-summary-limit-mark-excluded-as-read
- "o" gnus-summary-insert-old-articles
- "N" gnus-summary-insert-new-articles
- "S" gnus-summary-limit-to-singletons
- "r" gnus-summary-limit-to-replied
- "R" gnus-summary-limit-to-recipient
- "A" gnus-summary-limit-to-address)
- (gnus-define-keys (gnus-summary-goto-map "G" gnus-summary-mode-map)
- "n" gnus-summary-next-unread-article
- "p" gnus-summary-prev-unread-article
- "N" gnus-summary-next-article
- "P" gnus-summary-prev-article
- "\C-n" gnus-summary-next-same-subject
- "\C-p" gnus-summary-prev-same-subject
- "\M-n" gnus-summary-next-unread-subject
- "\M-p" gnus-summary-prev-unread-subject
- "f" gnus-summary-first-unread-article
- "b" gnus-summary-best-unread-article
- "j" gnus-summary-goto-article
- "g" gnus-summary-goto-subject
- "l" gnus-summary-goto-last-article
- "o" gnus-summary-pop-article)
- (gnus-define-keys (gnus-summary-thread-map "T" gnus-summary-mode-map)
- "k" gnus-summary-kill-thread
- "E" gnus-summary-expire-thread
- "l" gnus-summary-lower-thread
- "i" gnus-summary-raise-thread
- "T" gnus-summary-toggle-threads
- "t" gnus-summary-rethread-current
- "^" gnus-summary-reparent-thread
- "\M-^" gnus-summary-reparent-children
- "s" gnus-summary-show-thread
- "S" gnus-summary-show-all-threads
- "h" gnus-summary-hide-thread
- "H" gnus-summary-hide-all-threads
- "n" gnus-summary-next-thread
- "p" gnus-summary-prev-thread
- "u" gnus-summary-up-thread
- "o" gnus-summary-top-thread
- "d" gnus-summary-down-thread
- "#" gnus-uu-mark-thread
- "\M-#" gnus-uu-unmark-thread)
- (gnus-define-keys (gnus-summary-buffer-map "Y" gnus-summary-mode-map)
- "g" gnus-summary-prepare
- "c" gnus-summary-insert-cached-articles
- "d" gnus-summary-insert-dormant-articles
- "t" gnus-summary-insert-ticked-articles)
- (gnus-define-keys (gnus-summary-exit-map "Z" gnus-summary-mode-map)
- "c" gnus-summary-catchup-and-exit
- "C" gnus-summary-catchup-all-and-exit
- "E" gnus-summary-exit-no-update
- "Q" gnus-summary-exit
- "Z" gnus-summary-exit
- "n" gnus-summary-catchup-and-goto-next-group
- "p" gnus-summary-catchup-and-goto-prev-group
- "R" gnus-summary-reselect-current-group
- "G" gnus-summary-rescan-group
- "N" gnus-summary-next-group
- "s" gnus-summary-save-newsrc
- "P" gnus-summary-prev-group)
- (gnus-define-keys (gnus-summary-article-map "A" gnus-summary-mode-map)
- " " gnus-summary-next-page
- "n" gnus-summary-next-page
- [?\S-\ ] gnus-summary-prev-page
- "\177" gnus-summary-prev-page
- [delete] gnus-summary-prev-page
- "p" gnus-summary-prev-page
- "\r" gnus-summary-scroll-up
- "\M-\r" gnus-summary-scroll-down
- "<" gnus-summary-beginning-of-article
- ">" gnus-summary-end-of-article
- "b" gnus-summary-beginning-of-article
- "e" gnus-summary-end-of-article
- "^" gnus-summary-refer-parent-article
- "r" gnus-summary-refer-parent-article
- "C" gnus-summary-show-complete-article
- "D" gnus-summary-enter-digest-group
- "R" gnus-summary-refer-references
- "T" gnus-summary-refer-thread
- "W" gnus-warp-to-article
- "g" gnus-summary-show-article
- "s" gnus-summary-isearch-article
- "\t" gnus-summary-widget-forward
- [backtab] gnus-summary-widget-backward
- "P" gnus-summary-print-article
- "S" gnus-sticky-article
- "M" gnus-mailing-list-insinuate
- "t" gnus-article-babel)
- (gnus-define-keys (gnus-summary-wash-map "W" gnus-summary-mode-map)
- "b" gnus-article-add-buttons
- "B" gnus-article-add-buttons-to-head
- "o" gnus-article-treat-overstrike
- "e" gnus-article-emphasize
- "w" gnus-article-fill-cited-article
- "Q" gnus-article-fill-long-lines
- "L" gnus-article-toggle-truncate-lines
- "C" gnus-article-capitalize-sentences
- "c" gnus-article-remove-cr
- "q" gnus-article-de-quoted-unreadable
- "6" gnus-article-de-base64-unreadable
- "Z" gnus-article-decode-HZ
- "A" gnus-article-treat-ansi-sequences
- "h" gnus-article-wash-html
- "u" gnus-article-unsplit-urls
- "s" gnus-summary-force-verify-and-decrypt
- "f" gnus-article-display-x-face
- "l" gnus-summary-stop-page-breaking
- "r" gnus-summary-caesar-message
- "m" gnus-summary-morse-message
- "t" gnus-summary-toggle-header
- "g" gnus-treat-smiley
- "v" gnus-summary-verbose-headers
- "a" gnus-article-strip-headers-in-body ;; mnemonic: wash archive
- "p" gnus-article-verify-x-pgp-sig
- "d" gnus-article-treat-dumbquotes
- "U" gnus-article-treat-non-ascii
- "i" gnus-summary-idna-message)
- (gnus-define-keys (gnus-summary-wash-deuglify-map "Y" gnus-summary-wash-map)
- ;; mnemonic: deuglif*Y*
- "u" gnus-article-outlook-unwrap-lines
- "a" gnus-article-outlook-repair-attribution
- "c" gnus-article-outlook-rearrange-citation
- "f" gnus-article-outlook-deuglify-article) ;; mnemonic: full deuglify
- (gnus-define-keys (gnus-summary-wash-hide-map "W" gnus-summary-wash-map)
- "a" gnus-article-hide
- "h" gnus-article-hide-headers
- "b" gnus-article-hide-boring-headers
- "s" gnus-article-hide-signature
- "c" gnus-article-hide-citation
- "C" gnus-article-hide-citation-in-followups
- "l" gnus-article-hide-list-identifiers
- "B" gnus-article-strip-banner
- "P" gnus-article-hide-pem
- "\C-c" gnus-article-hide-citation-maybe)
- (gnus-define-keys (gnus-summary-wash-highlight-map "H" gnus-summary-wash-map)
- "a" gnus-article-highlight
- "h" gnus-article-highlight-headers
- "c" gnus-article-highlight-citation
- "s" gnus-article-highlight-signature)
- (gnus-define-keys (gnus-summary-wash-header-map "G" gnus-summary-wash-map)
- "f" gnus-article-treat-fold-headers
- "u" gnus-article-treat-unfold-headers
- "n" gnus-article-treat-fold-newsgroups)
- (gnus-define-keys (gnus-summary-wash-display-map "D" gnus-summary-wash-map)
- "x" gnus-article-display-x-face
- "d" gnus-article-display-face
- "s" gnus-treat-smiley
- "D" gnus-article-remove-images
- "W" gnus-article-show-images
- "f" gnus-treat-from-picon
- "m" gnus-treat-mail-picon
- "n" gnus-treat-newsgroups-picon
- "g" gnus-treat-from-gravatar
- "h" gnus-treat-mail-gravatar)
- (gnus-define-keys (gnus-summary-wash-mime-map "M" gnus-summary-wash-map)
- "w" gnus-article-decode-mime-words
- "c" gnus-article-decode-charset
- "h" gnus-mime-buttonize-attachments-in-header
- "v" gnus-mime-view-all-parts
- "b" gnus-article-view-part)
- (gnus-define-keys (gnus-summary-wash-time-map "T" gnus-summary-wash-map)
- "z" gnus-article-date-ut
- "u" gnus-article-date-ut
- "l" gnus-article-date-local
- "p" gnus-article-date-english
- "e" gnus-article-date-lapsed
- "o" gnus-article-date-original
- "i" gnus-article-date-iso8601
- "s" gnus-article-date-user)
- (gnus-define-keys (gnus-summary-wash-empty-map "E" gnus-summary-wash-map)
- "t" gnus-article-remove-trailing-blank-lines
- "l" gnus-article-strip-leading-blank-lines
- "m" gnus-article-strip-multiple-blank-lines
- "a" gnus-article-strip-blank-lines
- "A" gnus-article-strip-all-blank-lines
- "s" gnus-article-strip-leading-space
- "e" gnus-article-strip-trailing-space
- "w" gnus-article-remove-leading-whitespace)
- (gnus-define-keys (gnus-summary-help-map "H" gnus-summary-mode-map)
- "v" gnus-version
- "d" gnus-summary-describe-group
- "h" gnus-summary-describe-briefly
- "i" gnus-info-find-node)
- (gnus-define-keys (gnus-summary-backend-map "B" gnus-summary-mode-map)
- "e" gnus-summary-expire-articles
- "\M-\C-e" gnus-summary-expire-articles-now
- "\177" gnus-summary-delete-article
- [delete] gnus-summary-delete-article
- "m" gnus-summary-move-article
- "r" gnus-summary-respool-article
- "w" gnus-summary-edit-article
- "c" gnus-summary-copy-article
- "B" gnus-summary-crosspost-article
- "q" gnus-summary-respool-query
- "t" gnus-summary-respool-trace
- "i" gnus-summary-import-article
- "I" gnus-summary-create-article
- "p" gnus-summary-article-posted-p)
- (gnus-define-keys (gnus-summary-save-map "O" gnus-summary-mode-map)
- "o" gnus-summary-save-article
- "m" gnus-summary-save-article-mail
- "F" gnus-summary-write-article-file
- "r" gnus-summary-save-article-rmail
- "f" gnus-summary-save-article-file
- "b" gnus-summary-save-article-body-file
- "B" gnus-summary-write-article-body-file
- "h" gnus-summary-save-article-folder
- "v" gnus-summary-save-article-vm
- "p" gnus-summary-pipe-output
- "P" gnus-summary-muttprint)
- (gnus-define-keys (gnus-summary-mime-map "K" gnus-summary-mode-map)
- "b" gnus-summary-display-buttonized
- "m" gnus-summary-repair-multipart
- "v" gnus-article-view-part
- "o" gnus-article-save-part
- "O" gnus-article-save-part-and-strip
- "r" gnus-article-replace-part
- "d" gnus-article-delete-part
- "t" gnus-article-view-part-as-type
- "j" gnus-article-jump-to-part
- "c" gnus-article-copy-part
- "C" gnus-article-view-part-as-charset
- "e" gnus-article-view-part-externally
- "H" gnus-article-browse-html-article
- "E" gnus-article-encrypt-body
- "i" gnus-article-inline-part
- "|" gnus-article-pipe-part)
- (gnus-define-keys (gnus-uu-mark-map "P" gnus-summary-mark-map)
- "p" gnus-summary-mark-as-processable
- "u" gnus-summary-unmark-as-processable
- "U" gnus-summary-unmark-all-processable
- "v" gnus-uu-mark-over
- "s" gnus-uu-mark-series
- "r" gnus-uu-mark-region
- "g" gnus-uu-unmark-region
- "R" gnus-uu-mark-by-regexp
- "G" gnus-uu-unmark-by-regexp
- "t" gnus-uu-mark-thread
- "T" gnus-uu-unmark-thread
- "a" gnus-uu-mark-all
- "b" gnus-uu-mark-buffer
- "S" gnus-uu-mark-sparse
- "k" gnus-summary-kill-process-mark
- "y" gnus-summary-yank-process-mark
- "w" gnus-summary-save-process-mark
- "i" gnus-uu-invert-processable)
- (gnus-define-keys (gnus-uu-extract-map "X" gnus-summary-mode-map)
- ;;"x" gnus-uu-extract-any
- "m" gnus-summary-save-parts
- "u" gnus-uu-decode-uu
- "U" gnus-uu-decode-uu-and-save
- "s" gnus-uu-decode-unshar
- "S" gnus-uu-decode-unshar-and-save
- "o" gnus-uu-decode-save
- "O" gnus-uu-decode-save
- "b" gnus-uu-decode-binhex
- "B" gnus-uu-decode-binhex
- "Y" gnus-uu-decode-yenc
- "p" gnus-uu-decode-postscript
- "P" gnus-uu-decode-postscript-and-save)
- (gnus-define-keys
- (gnus-uu-extract-view-map "v" gnus-uu-extract-map)
- "u" gnus-uu-decode-uu-view
- "U" gnus-uu-decode-uu-and-save-view
- "s" gnus-uu-decode-unshar-view
- "S" gnus-uu-decode-unshar-and-save-view
- "o" gnus-uu-decode-save-view
- "O" gnus-uu-decode-save-view
- "b" gnus-uu-decode-binhex-view
- "B" gnus-uu-decode-binhex-view
- "p" gnus-uu-decode-postscript-view
- "P" gnus-uu-decode-postscript-and-save-view)
- (defvar gnus-article-post-menu nil)
- (defconst gnus-summary-menu-maxlen 20)
- (defun gnus-summary-menu-split (menu)
- ;; If we have lots of elements, divide them into groups of 20
- ;; and make a pane (or submenu) for each one.
- (if (> (length menu) (/ (* gnus-summary-menu-maxlen 3) 2))
- (let ((menu menu) sublists next
- (i 1))
- (while menu
- ;; Pull off the next gnus-summary-menu-maxlen elements
- ;; and make them the next element of sublist.
- (setq next (nthcdr gnus-summary-menu-maxlen menu))
- (if next
- (setcdr (nthcdr (1- gnus-summary-menu-maxlen) menu)
- nil))
- (setq sublists (cons (cons (format "%s ... %s" (aref (car menu) 0)
- (aref (car (last menu)) 0)) menu)
- sublists))
- (setq i (1+ i))
- (setq menu next))
- (nreverse sublists))
- ;; Few elements--put them all in one pane.
- menu))
- (defun gnus-summary-make-menu-bar ()
- (gnus-turn-off-edit-menu 'summary)
- (unless (boundp 'gnus-summary-misc-menu)
- (easy-menu-define
- gnus-summary-kill-menu gnus-summary-mode-map ""
- (cons
- "Score"
- (nconc
- (list
- ["Customize" gnus-score-customize t])
- (gnus-make-score-map 'increase)
- (gnus-make-score-map 'lower)
- '(("Mark"
- ["Kill below" gnus-summary-kill-below t]
- ["Mark above" gnus-summary-mark-above t]
- ["Tick above" gnus-summary-tick-above t]
- ["Clear above" gnus-summary-clear-above t])
- ["Current article score" gnus-summary-current-score t]
- ["Current thread score" (gnus-summary-current-score 'total) t]
- ["Set score" gnus-summary-set-score t]
- ["Switch current score file..." gnus-score-change-score-file t]
- ["Set mark below..." gnus-score-set-mark-below t]
- ["Set expunge below..." gnus-score-set-expunge-below t]
- ["Edit current score file" gnus-score-edit-current-scores t]
- ["Edit score file..." gnus-score-edit-file t]
- ["Trace score" gnus-score-find-trace t]
- ["Find words" gnus-score-find-favourite-words t]
- ["Rescore buffer" gnus-summary-rescore t]
- ["Increase score..." gnus-summary-increase-score t]
- ["Lower score..." gnus-summary-lower-score t]))))
- ;; Define both the Article menu in the summary buffer and the
- ;; equivalent Commands menu in the article buffer here for
- ;; consistency.
- (let ((innards
- `(("Hide"
- ["All" gnus-article-hide t]
- ["Headers" gnus-article-hide-headers t]
- ["Signature" gnus-article-hide-signature t]
- ["Citation" gnus-article-hide-citation t]
- ["List identifiers" gnus-article-hide-list-identifiers t]
- ["Banner" gnus-article-strip-banner t]
- ["Boring headers" gnus-article-hide-boring-headers t])
- ("Highlight"
- ["All" gnus-article-highlight t]
- ["Headers" gnus-article-highlight-headers t]
- ["Signature" gnus-article-highlight-signature t]
- ["Citation" gnus-article-highlight-citation t])
- ("MIME"
- ["Words" gnus-article-decode-mime-words t]
- ["Charset" gnus-article-decode-charset t]
- ["QP" gnus-article-de-quoted-unreadable t]
- ["Base64" gnus-article-de-base64-unreadable t]
- ["View MIME buttons" gnus-summary-display-buttonized t]
- ["View MIME buttons in header"
- gnus-mime-buttonize-attachments-in-header t]
- ["View all" gnus-mime-view-all-parts t]
- ["Verify and Decrypt" gnus-summary-force-verify-and-decrypt t]
- ["Encrypt body" gnus-article-encrypt-body
- :active (not (gnus-group-read-only-p))
- ,@(if (featurep 'xemacs) nil
- '(:help "Encrypt the message body on disk"))]
- ["Extract all parts..." gnus-summary-save-parts t]
- ("Multipart"
- ["Repair multipart" gnus-summary-repair-multipart t]
- ["Pipe part..." gnus-article-pipe-part t]
- ["Inline part" gnus-article-inline-part t]
- ["View part as type..." gnus-article-view-part-as-type t]
- ["Encrypt body" gnus-article-encrypt-body
- :active (not (gnus-group-read-only-p))
- ,@(if (featurep 'xemacs) nil
- '(:help "Encrypt the message body on disk"))]
- ["View part externally" gnus-article-view-part-externally t]
- ["View HTML parts in browser" gnus-article-browse-html-article t]
- ["View part with charset..." gnus-article-view-part-as-charset t]
- ["Copy part" gnus-article-copy-part t]
- ["Save part..." gnus-article-save-part t]
- ["View part" gnus-article-view-part t]))
- ("Date"
- ["Local" gnus-article-date-local t]
- ["ISO8601" gnus-article-date-iso8601 t]
- ["UT" gnus-article-date-ut t]
- ["Original" gnus-article-date-original t]
- ["Lapsed" gnus-article-date-lapsed t]
- ["User-defined" gnus-article-date-user t])
- ("Display"
- ["Display HTML images" gnus-article-show-images t]
- ["Remove images" gnus-article-remove-images t]
- ["Toggle smiley" gnus-treat-smiley t]
- ["Show X-Face" gnus-article-display-x-face t]
- ["Show picons in From" gnus-treat-from-picon t]
- ["Show picons in mail headers" gnus-treat-mail-picon t]
- ["Show picons in news headers" gnus-treat-newsgroups-picon t]
- ["Show Gravatars in From" gnus-treat-from-gravatar t]
- ["Show Gravatars in mail headers" gnus-treat-mail-gravatar t]
- ("View as different encoding"
- ,@(gnus-summary-menu-split
- (mapcar
- (lambda (cs)
- ;; Since easymenu under Emacs doesn't allow
- ;; lambda forms for menu commands, we should
- ;; provide intern'ed function symbols.
- (let ((command (intern (format "\
- gnus-summary-show-article-from-menu-as-charset-%s" cs))))
- (fset command
- `(lambda ()
- (interactive)
- (let ((gnus-summary-show-article-charset-alist
- '((1 . ,cs))))
- (gnus-summary-show-article 1))))
- `[,(symbol-name cs) ,command t]))
- (sort (if (fboundp 'coding-system-list)
- (coding-system-list)
- (mapcar 'car mm-mime-mule-charset-alist))
- 'string<)))))
- ("Washing"
- ("Remove Blanks"
- ["Leading" gnus-article-strip-leading-blank-lines t]
- ["Multiple" gnus-article-strip-multiple-blank-lines t]
- ["Trailing" gnus-article-remove-trailing-blank-lines t]
- ["All of the above" gnus-article-strip-blank-lines t]
- ["All" gnus-article-strip-all-blank-lines t]
- ["Leading space" gnus-article-strip-leading-space t]
- ["Trailing space" gnus-article-strip-trailing-space t]
- ["Leading space in headers"
- gnus-article-remove-leading-whitespace t])
- ["Overstrike" gnus-article-treat-overstrike t]
- ["Dumb quotes" gnus-article-treat-dumbquotes t]
- ["Non-ASCII" gnus-article-treat-non-ascii t]
- ["Emphasis" gnus-article-emphasize t]
- ["Word wrap" gnus-article-fill-cited-article t]
- ["Fill long lines" gnus-article-fill-long-lines t]
- ["Toggle truncate long lines" gnus-article-toggle-truncate-lines t]
- ["Capitalize sentences" gnus-article-capitalize-sentences t]
- ["Remove CR" gnus-article-remove-cr t]
- ["Quoted-Printable" gnus-article-de-quoted-unreadable t]
- ["Base64" gnus-article-de-base64-unreadable t]
- ["Rot 13" gnus-summary-caesar-message
- ,@(if (featurep 'xemacs) '(t)
- '(:help "\"Caesar rotate\" article by 13"))]
- ["De-IDNA" gnus-summary-idna-message t]
- ["Morse decode" gnus-summary-morse-message t]
- ["Unix pipe..." gnus-summary-pipe-message t]
- ["Add buttons" gnus-article-add-buttons t]
- ["Add buttons to head" gnus-article-add-buttons-to-head t]
- ["Stop page breaking" gnus-summary-stop-page-breaking t]
- ["Verbose header" gnus-summary-verbose-headers t]
- ["Toggle header" gnus-summary-toggle-header t]
- ["Unfold headers" gnus-article-treat-unfold-headers t]
- ["Fold newsgroups" gnus-article-treat-fold-newsgroups t]
- ["Html" gnus-article-wash-html t]
- ["Unsplit URLs" gnus-article-unsplit-urls t]
- ["Verify X-PGP-Sig" gnus-article-verify-x-pgp-sig t]
- ["Decode HZ" gnus-article-decode-HZ t]
- ["ANSI sequences" gnus-article-treat-ansi-sequences t]
- ("(Outlook) Deuglify"
- ["Unwrap lines" gnus-article-outlook-unwrap-lines t]
- ["Repair attribution" gnus-article-outlook-repair-attribution t]
- ["Rearrange citation" gnus-article-outlook-rearrange-citation t]
- ["Full (Outlook) deuglify"
- gnus-article-outlook-deuglify-article t])
- )
- ("Output"
- ["Save in default format..." gnus-summary-save-article
- ,@(if (featurep 'xemacs) '(t)
- '(:help "Save article using default method"))]
- ["Save in file..." gnus-summary-save-article-file
- ,@(if (featurep 'xemacs) '(t)
- '(:help "Save article in file"))]
- ["Save in Unix mail format..." gnus-summary-save-article-mail t]
- ["Save in MH folder..." gnus-summary-save-article-folder t]
- ["Save in VM folder..." gnus-summary-save-article-vm t]
- ["Save in RMAIL mbox..." gnus-summary-save-article-rmail t]
- ["Save body in file..." gnus-summary-save-article-body-file t]
- ["Pipe through a filter..." gnus-summary-pipe-output t]
- ["Print with Muttprint..." gnus-summary-muttprint t]
- ["Print" gnus-summary-print-article
- ,@(if (featurep 'xemacs) '(t)
- '(:help "Generate and print a PostScript image"))])
- ("Copy, move,... (Backend)"
- ,@(if (featurep 'xemacs) nil
- '(:help "Copying, moving, expiring articles..."))
- ["Respool article..." gnus-summary-respool-article t]
- ["Move article..." gnus-summary-move-article
- (gnus-check-backend-function
- 'request-move-article gnus-newsgroup-name)]
- ["Copy article..." gnus-summary-copy-article t]
- ["Crosspost article..." gnus-summary-crosspost-article
- (gnus-check-backend-function
- 'request-replace-article gnus-newsgroup-name)]
- ["Import file..." gnus-summary-import-article
- (gnus-check-backend-function
- 'request-accept-article gnus-newsgroup-name)]
- ["Create article..." gnus-summary-create-article
- (gnus-check-backend-function
- 'request-accept-article gnus-newsgroup-name)]
- ["Check if posted" gnus-summary-article-posted-p t]
- ["Edit article" gnus-summary-edit-article
- (not (gnus-group-read-only-p))]
- ["Delete article" gnus-summary-delete-article
- (gnus-check-backend-function
- 'request-expire-articles gnus-newsgroup-name)]
- ["Query respool" gnus-summary-respool-query t]
- ["Trace respool" gnus-summary-respool-trace t]
- ["Delete expirable articles" gnus-summary-expire-articles-now
- (gnus-check-backend-function
- 'request-expire-articles gnus-newsgroup-name)])
- ("Extract"
- ["Uudecode" gnus-uu-decode-uu
- ,@(if (featurep 'xemacs) '(t)
- '(:help "Decode uuencoded article(s)"))]
- ["Uudecode and save" gnus-uu-decode-uu-and-save t]
- ["Unshar" gnus-uu-decode-unshar t]
- ["Unshar and save" gnus-uu-decode-unshar-and-save t]
- ["Save" gnus-uu-decode-save t]
- ["Binhex" gnus-uu-decode-binhex t]
- ["PostScript" gnus-uu-decode-postscript t]
- ["All MIME parts" gnus-summary-save-parts t])
- ("Cache"
- ["Enter article" gnus-cache-enter-article t]
- ["Remove article" gnus-cache-remove-article t])
- ["Translate" gnus-article-babel t]
- ["Select article buffer" gnus-summary-select-article-buffer t]
- ["Make article buffer sticky" gnus-sticky-article t]
- ["Enter digest buffer" gnus-summary-enter-digest-group t]
- ["Isearch article..." gnus-summary-isearch-article t]
- ["Beginning of the article" gnus-summary-beginning-of-article t]
- ["End of the article" gnus-summary-end-of-article t]
- ["Fetch parent of article" gnus-summary-refer-parent-article t]
- ["Fetch referenced articles" gnus-summary-refer-references t]
- ["Fetch current thread" gnus-summary-refer-thread t]
- ["Fetch article with id..." gnus-summary-refer-article t]
- ["Setup Mailing List Params" gnus-mailing-list-insinuate t]
- ["Redisplay" gnus-summary-show-article t]
- ["Raw article" gnus-summary-show-raw-article :keys "C-u g"])))
- (easy-menu-define
- gnus-summary-article-menu gnus-summary-mode-map ""
- (cons "Article" innards))
- (if (not (keymapp gnus-summary-article-menu))
- (easy-menu-define
- gnus-article-commands-menu gnus-article-mode-map ""
- (cons "Commands" innards))
- ;; in Emacs, don't share menu.
- (setq gnus-article-commands-menu
- (copy-keymap gnus-summary-article-menu))
- (define-key gnus-article-mode-map [menu-bar commands]
- (cons "Commands" gnus-article-commands-menu))))
- (easy-menu-define
- gnus-summary-thread-menu gnus-summary-mode-map ""
- '("Threads"
- ["Find all messages in thread" gnus-summary-refer-thread t]
- ["Toggle threading" gnus-summary-toggle-threads t]
- ["Hide threads" gnus-summary-hide-all-threads t]
- ["Show threads" gnus-summary-show-all-threads t]
- ["Hide thread" gnus-summary-hide-thread t]
- ["Show thread" gnus-summary-show-thread t]
- ["Go to next thread" gnus-summary-next-thread t]
- ["Go to previous thread" gnus-summary-prev-thread t]
- ["Go down thread" gnus-summary-down-thread t]
- ["Go up thread" gnus-summary-up-thread t]
- ["Top of thread" gnus-summary-top-thread t]
- ["Mark thread as read" gnus-summary-kill-thread t]
- ["Mark thread as expired" gnus-summary-expire-thread t]
- ["Lower thread score" gnus-summary-lower-thread t]
- ["Raise thread score" gnus-summary-raise-thread t]
- ["Rethread current" gnus-summary-rethread-current t]))
- (easy-menu-define
- gnus-summary-post-menu gnus-summary-mode-map ""
- `("Post"
- ["Send a message (mail or news)" gnus-summary-post-news
- ,@(if (featurep 'xemacs) '(t)
- '(:help "Compose a new message (mail or news)"))]
- ["Followup" gnus-summary-followup
- ,@(if (featurep 'xemacs) '(t)
- '(:help "Post followup to this article"))]
- ["Followup and yank" gnus-summary-followup-with-original
- ,@(if (featurep 'xemacs) '(t)
- '(:help "Post followup to this article, quoting its contents"))]
- ["Supersede article" gnus-summary-supersede-article t]
- ["Cancel article" gnus-summary-cancel-article
- ,@(if (featurep 'xemacs) '(t)
- '(:help "Cancel an article you posted"))]
- ["Reply" gnus-summary-reply t]
- ["Reply and yank" gnus-summary-reply-with-original t]
- ["Wide reply" gnus-summary-wide-reply t]
- ["Wide reply and yank" gnus-summary-wide-reply-with-original
- ,@(if (featurep 'xemacs) '(t)
- '(:help "Mail a reply, quoting this article"))]
- ["Very wide reply" gnus-summary-very-wide-reply t]
- ["Very wide reply and yank" gnus-summary-very-wide-reply-with-original
- ,@(if (featurep 'xemacs) '(t)
- '(:help "Mail a very wide reply, quoting this article"))]
- ["Mail forward" gnus-summary-mail-forward t]
- ["Post forward" gnus-summary-post-forward t]
- ["Digest and mail" gnus-uu-digest-mail-forward t]
- ["Digest and post" gnus-uu-digest-post-forward t]
- ["Resend message" gnus-summary-resend-message t]
- ["Resend message edit" gnus-summary-resend-message-edit t]
- ["Send bounced mail" gnus-summary-resend-bounced-mail t]
- ["Send a mail" gnus-summary-mail-other-window t]
- ["Create a local message" gnus-summary-news-other-window t]
- ["Uuencode and post" gnus-uu-post-news
- ,@(if (featurep 'xemacs) '(t)
- '(:help "Post a uuencoded article"))]
- ["Followup via news" gnus-summary-followup-to-mail t]
- ["Followup via news and yank"
- gnus-summary-followup-to-mail-with-original t]
- ["Strip signature on reply"
- (lambda ()
- (interactive)
- (if (not (memq message-cite-function
- '(message-cite-original-without-signature
- message-cite-original)))
- ;; Stupid workaround for XEmacs not honoring :visible.
- (message "Can't toggle this value of `message-cite-function'")
- (setq message-cite-function
- (if (eq message-cite-function
- 'message-cite-original-without-signature)
- 'message-cite-original
- 'message-cite-original-without-signature))))
- ;; XEmacs barfs on :visible.
- ,@(if (featurep 'xemacs) nil
- '(:visible (memq message-cite-function
- '(message-cite-original-without-signature
- message-cite-original))))
- :style toggle
- :selected (eq message-cite-function
- 'message-cite-original-without-signature)
- ,@(if (featurep 'xemacs) nil
- '(:help "Strip signature from cited article when replying."))]
- ;;("Draft"
- ;;["Send" gnus-summary-send-draft t]
- ;;["Send bounced" gnus-resend-bounced-mail t])
- ))
- (cond
- ((not (keymapp gnus-summary-post-menu))
- (setq gnus-article-post-menu gnus-summary-post-menu))
- ((not gnus-article-post-menu)
- ;; Don't share post menu.
- (setq gnus-article-post-menu
- (copy-keymap gnus-summary-post-menu))))
- (define-key gnus-article-mode-map [menu-bar post]
- (cons "Post" gnus-article-post-menu))
- (easy-menu-define
- gnus-summary-misc-menu gnus-summary-mode-map ""
- `("Gnus"
- ("Mark Read"
- ["Mark as read" gnus-summary-mark-as-read-forward t]
- ["Mark same subject and select"
- gnus-summary-kill-same-subject-and-select t]
- ["Mark same subject" gnus-summary-kill-same-subject t]
- ["Catchup" gnus-summary-catchup
- ,@(if (featurep 'xemacs) '(t)
- '(:help "Mark unread articles in this group as read"))]
- ["Catchup all" gnus-summary-catchup-all t]
- ["Catchup to here" gnus-summary-catchup-to-here t]
- ["Catchup from here" gnus-summary-catchup-from-here t]
- ["Catchup region" gnus-summary-mark-region-as-read
- (gnus-mark-active-p)]
- ["Mark excluded" gnus-summary-limit-mark-excluded-as-read t])
- ("Mark Various"
- ["Tick" gnus-summary-tick-article-forward t]
- ["Mark as dormant" gnus-summary-mark-as-dormant t]
- ["Remove marks" gnus-summary-clear-mark-forward t]
- ["Set expirable mark" gnus-summary-mark-as-expirable t]
- ["Set bookmark" gnus-summary-set-bookmark t]
- ["Remove bookmark" gnus-summary-remove-bookmark t])
- ("Limit to"
- ["Marks..." gnus-summary-limit-to-marks t]
- ["Subject..." gnus-summary-limit-to-subject t]
- ["Author..." gnus-summary-limit-to-author t]
- ["Recipient..." gnus-summary-limit-to-recipient t]
- ["Address..." gnus-summary-limit-to-address t]
- ["Age..." gnus-summary-limit-to-age t]
- ["Extra..." gnus-summary-limit-to-extra t]
- ["Score..." gnus-summary-limit-to-score t]
- ["Display Predicate" gnus-summary-limit-to-display-predicate t]
- ["Unread" gnus-summary-limit-to-unread t]
- ["Unseen" gnus-summary-limit-to-unseen t]
- ["Singletons" gnus-summary-limit-to-singletons t]
- ["Replied" gnus-summary-limit-to-replied t]
- ["Non-dormant" gnus-summary-limit-exclude-dormant t]
- ["Next or process marked articles" gnus-summary-limit-to-articles t]
- ["Pop limit" gnus-summary-pop-limit t]
- ["Show dormant" gnus-summary-limit-include-dormant t]
- ["Hide childless dormant"
- gnus-summary-limit-exclude-childless-dormant t]
- ;;["Hide thread" gnus-summary-limit-exclude-thread t]
- ["Hide marked" gnus-summary-limit-exclude-marks t]
- ["Show expunged" gnus-summary-limit-include-expunged t])
- ("Process Mark"
- ["Set mark" gnus-summary-mark-as-processable t]
- ["Remove mark" gnus-summary-unmark-as-processable t]
- ["Remove all marks" gnus-summary-unmark-all-processable t]
- ["Invert marks" gnus-uu-invert-processable t]
- ["Mark above" gnus-uu-mark-over t]
- ["Mark series" gnus-uu-mark-series t]
- ["Mark region" gnus-uu-mark-region (gnus-mark-active-p)]
- ["Unmark region" gnus-uu-unmark-region (gnus-mark-active-p)]
- ["Mark by regexp..." gnus-uu-mark-by-regexp t]
- ["Unmark by regexp..." gnus-uu-unmark-by-regexp t]
- ["Mark all" gnus-uu-mark-all t]
- ["Mark buffer" gnus-uu-mark-buffer t]
- ["Mark sparse" gnus-uu-mark-sparse t]
- ["Mark thread" gnus-uu-mark-thread t]
- ["Unmark thread" gnus-uu-unmark-thread t]
- ("Process Mark Sets"
- ["Kill" gnus-summary-kill-process-mark t]
- ["Yank" gnus-summary-yank-process-mark
- gnus-newsgroup-process-stack]
- ["Save" gnus-summary-save-process-mark t]
- ["Run command on marked..." gnus-summary-universal-argument t]))
- ("Registry Marks")
- ("Scroll article"
- ["Page forward" gnus-summary-next-page
- ,@(if (featurep 'xemacs) '(t)
- '(:help "Show next page of article"))]
- ["Page backward" gnus-summary-prev-page
- ,@(if (featurep 'xemacs) '(t)
- '(:help "Show previous page of article"))]
- ["Line forward" gnus-summary-scroll-up t])
- ("Move"
- ["Next unread article" gnus-summary-next-unread-article t]
- ["Previous unread article" gnus-summary-prev-unread-article t]
- ["Next article" gnus-summary-next-article t]
- ["Previous article" gnus-summary-prev-article t]
- ["Next unread subject" gnus-summary-next-unread-subject t]
- ["Previous unread subject" gnus-summary-prev-unread-subject t]
- ["Next article same subject" gnus-summary-next-same-subject t]
- ["Previous article same subject" gnus-summary-prev-same-subject t]
- ["First unread article" gnus-summary-first-unread-article t]
- ["Best unread article" gnus-summary-best-unread-article t]
- ["Go to subject number..." gnus-summary-goto-subject t]
- ["Go to article number..." gnus-summary-goto-article t]
- ["Go to the last article" gnus-summary-goto-last-article t]
- ["Pop article off history" gnus-summary-pop-article t])
- ("Sort"
- ["Sort by number" gnus-summary-sort-by-number t]
- ["Sort by most recent number" gnus-summary-sort-by-most-recent-number t]
- ["Sort by author" gnus-summary-sort-by-author t]
- ["Sort by recipient" gnus-summary-sort-by-recipient t]
- ["Sort by subject" gnus-summary-sort-by-subject t]
- ["Sort by date" gnus-summary-sort-by-date t]
- ["Sort by most recent date" gnus-summary-sort-by-most-recent-date t]
- ["Sort by score" gnus-summary-sort-by-score t]
- ["Sort by lines" gnus-summary-sort-by-lines t]
- ["Sort by characters" gnus-summary-sort-by-chars t]
- ["Randomize" gnus-summary-sort-by-random t]
- ["Original sort" gnus-summary-sort-by-original t])
- ("Help"
- ["Describe group" gnus-summary-describe-group t]
- ["Read manual" gnus-info-find-node t])
- ("Modes"
- ["Pick and read" gnus-pick-mode t]
- ["Binary" gnus-binary-mode t])
- ("Regeneration"
- ["Regenerate" gnus-summary-prepare t]
- ["Insert cached articles" gnus-summary-insert-cached-articles t]
- ["Insert dormant articles" gnus-summary-insert-dormant-articles t]
- ["Insert ticked articles" gnus-summary-insert-ticked-articles t]
- ["Toggle threading" gnus-summary-toggle-threads t])
- ["See old articles" gnus-summary-insert-old-articles t]
- ["See new articles" gnus-summary-insert-new-articles t]
- ["Filter articles..." gnus-summary-execute-command t]
- ["Run command on articles..." gnus-summary-universal-argument t]
- ["Search articles forward..." gnus-summary-search-article-forward t]
- ["Search articles backward..." gnus-summary-search-article-backward t]
- ["Toggle line truncation" gnus-summary-toggle-truncation t]
- ["Expand window" gnus-summary-expand-window t]
- ["Expire expirable articles" gnus-summary-expire-articles
- (gnus-check-backend-function
- 'request-expire-articles gnus-newsgroup-name)]
- ["Edit local kill file" gnus-summary-edit-local-kill t]
- ["Edit main kill file" gnus-summary-edit-global-kill t]
- ["Edit group parameters" gnus-summary-edit-parameters t]
- ["Customize group parameters" gnus-summary-customize-parameters t]
- ["Send a bug report" gnus-bug t]
- ("Exit"
- ["Catchup and exit" gnus-summary-catchup-and-exit
- ,@(if (featurep 'xemacs) '(t)
- '(:help "Mark unread articles in this group as read, then exit"))]
- ["Catchup all and exit" gnus-summary-catchup-all-and-exit t]
- ["Catchup and goto next" gnus-summary-catchup-and-goto-next-group t]
- ["Catchup and goto prev" gnus-summary-catchup-and-goto-prev-group t]
- ["Exit group" gnus-summary-exit
- ,@(if (featurep 'xemacs) '(t)
- '(:help "Exit current group, return to group selection mode"))]
- ["Exit group without updating" gnus-summary-exit-no-update t]
- ["Exit and goto next group" gnus-summary-next-group t]
- ["Exit and goto prev group" gnus-summary-prev-group t]
- ["Reselect group" gnus-summary-reselect-current-group t]
- ["Rescan group" gnus-summary-rescan-group t]
- ["Update dribble" gnus-summary-save-newsrc t])))
- (gnus-run-hooks 'gnus-summary-menu-hook)))
- (defvar gnus-summary-tool-bar-map nil)
- ;; Note: The :set function in the `gnus-summary-tool-bar*' variables will only
- ;; affect _new_ message buffers. We might add a function that walks thru all
- ;; summary-mode buffers and force the update.
- (defun gnus-summary-tool-bar-update (&optional symbol value)
- "Update summary mode toolbar.
- Setter function for custom variables."
- (setq-default gnus-summary-tool-bar-map nil)
- (when symbol
- ;; When used as ":set" function:
- (set-default symbol value))
- (when (gnus-buffer-live-p gnus-summary-buffer)
- (with-current-buffer gnus-summary-buffer
- (gnus-summary-make-tool-bar))))
- (defcustom gnus-summary-tool-bar (if (eq gmm-tool-bar-style 'gnome)
- 'gnus-summary-tool-bar-gnome
- 'gnus-summary-tool-bar-retro)
- "Specifies the Gnus summary tool bar.
- It can be either a list or a symbol referring to a list. See
- `gmm-tool-bar-from-list' for the format of the list. The
- default key map is `gnus-summary-mode-map'.
- Pre-defined symbols include `gnus-summary-tool-bar-gnome' and
- `gnus-summary-tool-bar-retro'."
- :type '(choice (const :tag "GNOME style" gnus-summary-tool-bar-gnome)
- (const :tag "Retro look" gnus-summary-tool-bar-retro)
- (repeat :tag "User defined list" gmm-tool-bar-item)
- (symbol))
- :version "23.1" ;; No Gnus
- :initialize 'custom-initialize-default
- :set 'gnus-summary-tool-bar-update
- :group 'gnus-summary)
- (defcustom gnus-summary-tool-bar-gnome
- '((gnus-summary-post-news "mail/compose" nil)
- (gnus-summary-insert-new-articles "mail/inbox" nil
- :visible (or (not gnus-agent)
- gnus-plugged))
- (gnus-summary-reply-with-original "mail/reply")
- (gnus-summary-reply "mail/reply" nil :visible nil)
- (gnus-summary-followup-with-original "mail/reply-all")
- (gnus-summary-followup "mail/reply-all" nil :visible nil)
- (gnus-summary-mail-forward "mail/forward")
- (gnus-summary-save-article "mail/save")
- (gnus-summary-search-article-forward "search" nil :visible nil)
- (gnus-summary-print-article "print")
- (gnus-summary-tick-article-forward "flag-followup" nil :visible nil)
- ;; Some new commands that may need more suitable icons:
- (gnus-summary-save-newsrc "save" nil :visible nil)
- ;; (gnus-summary-show-article "stock_message-display" nil :visible nil)
- (gnus-summary-prev-article "left-arrow")
- (gnus-summary-next-article "right-arrow")
- (gnus-summary-next-page "next-page")
- ;; (gnus-summary-enter-digest-group "right_arrow" nil :visible nil)
- ;;
- ;; Maybe some sort-by-... could be added:
- ;; (gnus-summary-sort-by-author "sort-a-z" nil :visible nil)
- ;; (gnus-summary-sort-by-date "sort-1-9" nil :visible nil)
- (gnus-summary-mark-as-expirable
- "delete" nil
- :visible (gnus-check-backend-function 'request-expire-articles
- gnus-newsgroup-name))
- (gnus-summary-mark-as-spam
- "mail/spam" t
- :visible (and (fboundp 'spam-group-ham-contents-p)
- (spam-group-ham-contents-p gnus-newsgroup-name))
- :help "Mark as spam")
- (gnus-summary-mark-as-read-forward
- "mail/not-spam" nil
- :visible (and (fboundp 'spam-group-spam-contents-p)
- (spam-group-spam-contents-p gnus-newsgroup-name)))
- ;;
- (gnus-summary-exit "exit")
- (gmm-customize-mode "preferences" t :help "Edit mode preferences")
- (gnus-info-find-node "help"))
- "List of functions for the summary tool bar (GNOME style).
- See `gmm-tool-bar-from-list' for the format of the list."
- :type '(repeat gmm-tool-bar-item)
- :version "23.1" ;; No Gnus
- :initialize 'custom-initialize-default
- :set 'gnus-summary-tool-bar-update
- :group 'gnus-summary)
- (defcustom gnus-summary-tool-bar-retro
- '((gnus-summary-prev-unread-article "gnus/prev-ur")
- (gnus-summary-next-unread-article "gnus/next-ur")
- (gnus-summary-post-news "gnus/post")
- (gnus-summary-followup-with-original "gnus/fuwo")
- (gnus-summary-followup "gnus/followup")
- (gnus-summary-reply-with-original "gnus/reply-wo")
- (gnus-summary-reply "gnus/reply")
- (gnus-summary-caesar-message "gnus/rot13")
- (gnus-uu-decode-uu "gnus/uu-decode")
- (gnus-summary-save-article-file "gnus/save-aif")
- (gnus-summary-save-article "gnus/save-art")
- (gnus-uu-post-news "gnus/uu-post")
- (gnus-summary-catchup "gnus/catchup")
- (gnus-summary-catchup-and-exit "gnus/cu-exit")
- (gnus-summary-exit "gnus/exit-summ")
- ;; Some new command that may need more suitable icons:
- (gnus-summary-print-article "gnus/print" nil :visible nil)
- (gnus-summary-mark-as-expirable "gnus/close" nil :visible nil)
- (gnus-summary-save-newsrc "gnus/save" nil :visible nil)
- ;; (gnus-summary-enter-digest-group "gnus/right_arrow" nil :visible nil)
- (gnus-summary-search-article-forward "gnus/search" nil :visible nil)
- ;; (gnus-summary-insert-new-articles "gnus/paste" nil :visible nil)
- ;; (gnus-summary-toggle-threads "gnus/open" nil :visible nil)
- ;;
- (gnus-info-find-node "gnus/help" nil :visible nil))
- "List of functions for the summary tool bar (retro look).
- See `gmm-tool-bar-from-list' for the format of the list."
- :type '(repeat gmm-tool-bar-item)
- :version "23.1" ;; No Gnus
- :initialize 'custom-initialize-default
- :set 'gnus-summary-tool-bar-update
- :group 'gnus-summary)
- (defcustom gnus-summary-tool-bar-zap-list t
- "List of icon items from the global tool bar.
- These items are not displayed in the Gnus summary mode tool bar.
- See `gmm-tool-bar-from-list' for the format of the list."
- :type 'gmm-tool-bar-zap-list
- :version "23.1" ;; No Gnus
- :initialize 'custom-initialize-default
- :set 'gnus-summary-tool-bar-update
- :group 'gnus-summary)
- (defvar image-load-path)
- (defvar tool-bar-map)
- (defun gnus-summary-make-tool-bar (&optional force)
- "Make a summary mode tool bar from `gnus-summary-tool-bar'.
- When FORCE, rebuild the tool bar."
- (when (and (not (featurep 'xemacs))
- (boundp 'tool-bar-mode)
- tool-bar-mode
- (or (not gnus-summary-tool-bar-map) force))
- (let* ((load-path
- (gmm-image-load-path-for-library "gnus"
- "mail/save.xpm"
- nil t))
- (image-load-path (cons (car load-path)
- (when (boundp 'image-load-path)
- image-load-path)))
- (map (gmm-tool-bar-from-list gnus-summary-tool-bar
- gnus-summary-tool-bar-zap-list
- 'gnus-summary-mode-map)))
- (when map
- ;; Need to set `gnus-summary-tool-bar-map' because `gnus-article-mode'
- ;; uses its value.
- (setq gnus-summary-tool-bar-map map))))
- (set (make-local-variable 'tool-bar-map) gnus-summary-tool-bar-map))
- (defun gnus-make-score-map (type)
- "Make a summary score map of type TYPE."
- (if t
- nil
- (let ((headers '(("author" "from" string)
- ("subject" "subject" string)
- ("article body" "body" string)
- ("article head" "head" string)
- ("xref" "xref" string)
- ("extra header" "extra" string)
- ("lines" "lines" number)
- ("followups to author" "followup" string)))
- (types '((number ("less than" <)
- ("greater than" >)
- ("equal" =))
- (string ("substring" s)
- ("exact string" e)
- ("fuzzy string" f)
- ("regexp" r))))
- (perms '(("temporary" (current-time-string))
- ("permanent" nil)
- ("immediate" now)))
- header)
- (list
- (apply
- 'nconc
- (list
- (if (eq type 'lower)
- "Lower score"
- "Increase score"))
- (let (outh)
- (while headers
- (setq header (car headers))
- (setq outh
- (cons
- (apply
- 'nconc
- (list (car header))
- (let ((ts (cdr (assoc (nth 2 header) types)))
- outt)
- (while ts
- (setq outt
- (cons
- (apply
- 'nconc
- (list (caar ts))
- (let ((ps perms)
- outp)
- (while ps
- (setq outp
- (cons
- (vector
- (caar ps)
- (list
- 'gnus-summary-score-entry
- (nth 1 header)
- (if (or (string= (nth 1 header)
- "head")
- (string= (nth 1 header)
- "body"))
- ""
- (list 'gnus-summary-header
- (nth 1 header)))
- (list 'quote (nth 1 (car ts)))
- (list 'gnus-score-delta-default
- nil)
- (nth 1 (car ps))
- t)
- t)
- outp))
- (setq ps (cdr ps)))
- (list (nreverse outp))))
- outt))
- (setq ts (cdr ts)))
- (list (nreverse outt))))
- outh))
- (setq headers (cdr headers)))
- (list (nreverse outh))))))))
- (declare-function turn-on-gnus-mailing-list-mode "gnus-ml" ())
- (defvar bookmark-make-record-function)
- (defvar bidi-paragraph-direction)
- (defun gnus-summary-mode (&optional group)
- "Major mode for reading articles.
- All normal editing commands are switched off.
- \\<gnus-summary-mode-map>
- Each line in this buffer represents one article. To read an
- article, you can, for instance, type `\\[gnus-summary-next-page]'. To move forwards
- and backwards while displaying articles, type `\\[gnus-summary-next-unread-article]' and `\\[gnus-summary-prev-unread-article]',
- respectively.
- You can also post articles and send mail from this buffer. To
- follow up an article, type `\\[gnus-summary-followup]'. To mail a reply to the author
- of an article, type `\\[gnus-summary-reply]'.
- There are approx. one gazillion commands you can execute in this
- buffer; read the info pages for more information (`\\[gnus-info-find-node]').
- The following commands are available:
- \\{gnus-summary-mode-map}"
- ;; FIXME: Use define-derived-mode.
- (interactive)
- (kill-all-local-variables)
- (let ((gnus-summary-local-variables gnus-newsgroup-variables))
- (gnus-summary-make-local-variables))
- (gnus-summary-make-local-variables)
- (setq gnus-newsgroup-name group)
- (when (gnus-visual-p 'summary-menu 'menu)
- (gnus-summary-make-menu-bar)
- (gnus-summary-make-tool-bar))
- (gnus-make-thread-indent-array)
- (gnus-simplify-mode-line)
- (setq major-mode 'gnus-summary-mode)
- (setq mode-name "Summary")
- (use-local-map gnus-summary-mode-map)
- (buffer-disable-undo)
- (setq buffer-read-only t ;Disable modification
- show-trailing-whitespace nil)
- (setq truncate-lines t)
- ;; Force paragraph direction to be left-to-right. Don't make it
- ;; bound globally in old Emacsen and XEmacsen.
- (set (make-local-variable 'bidi-paragraph-direction) 'left-to-right)
- (add-to-invisibility-spec '(gnus-sum . t))
- (gnus-summary-set-display-table)
- (gnus-set-default-directory)
- (make-local-variable 'gnus-summary-line-format)
- (make-local-variable 'gnus-summary-line-format-spec)
- (make-local-variable 'gnus-summary-dummy-line-format)
- (make-local-variable 'gnus-summary-dummy-line-format-spec)
- (make-local-variable 'gnus-summary-mark-positions)
- (gnus-make-local-hook 'pre-command-hook)
- (add-hook 'pre-command-hook 'gnus-set-global-variables nil t)
- (gnus-run-mode-hooks 'gnus-summary-mode-hook)
- (turn-on-gnus-mailing-list-mode)
- (mm-enable-multibyte)
- (set (make-local-variable 'bookmark-make-record-function)
- 'gnus-summary-bookmark-make-record)
- (gnus-update-format-specifications nil 'summary 'summary-mode 'summary-dummy)
- (gnus-update-summary-mark-positions))
- (defun gnus-summary-make-local-variables ()
- "Make all the local summary buffer variables."
- (let (global)
- (dolist (local gnus-summary-local-variables)
- (if (consp local)
- (progn
- (if (eq (cdr local) 'global)
- ;; Copy the global value of the variable.
- (setq global (symbol-value (car local)))
- ;; Use the value from the list.
- (setq global (eval (cdr local))))
- (set (make-local-variable (car local)) global))
- ;; Simple nil-valued local variable.
- (set (make-local-variable local) nil)))))
- ;; Summary data functions.
- (defmacro gnus-data-number (data)
- `(car ,data))
- (defmacro gnus-data-set-number (data number)
- `(setcar ,data ,number))
- (defmacro gnus-data-mark (data)
- `(nth 1 ,data))
- (defmacro gnus-data-set-mark (data mark)
- `(setcar (nthcdr 1 ,data) ,mark))
- (defmacro gnus-data-pos (data)
- `(nth 2 ,data))
- (defmacro gnus-data-set-pos (data pos)
- `(setcar (nthcdr 2 ,data) ,pos))
- (defmacro gnus-data-header (data)
- `(nth 3 ,data))
- (defmacro gnus-data-set-header (data header)
- `(setf (nth 3 ,data) ,header))
- (defmacro gnus-data-level (data)
- `(nth 4 ,data))
- (defmacro gnus-data-unread-p (data)
- `(= (nth 1 ,data) gnus-unread-mark))
- (defmacro gnus-data-read-p (data)
- `(/= (nth 1 ,data) gnus-unread-mark))
- (defmacro gnus-data-pseudo-p (data)
- `(consp (nth 3 ,data)))
- (defmacro gnus-data-find (number)
- `(assq ,number gnus-newsgroup-data))
- (defmacro gnus-data-find-list (number &optional data)
- `(let ((bdata ,(or data 'gnus-newsgroup-data)))
- (memq (assq ,number bdata)
- bdata)))
- (defmacro gnus-data-make (number mark pos header level)
- `(list ,number ,mark ,pos ,header ,level))
- (defun gnus-data-enter (after-article number mark pos header level offset)
- (let ((data (gnus-data-find-list after-article)))
- (unless data
- (error "No such article: %d" after-article))
- (setcdr data (cons (gnus-data-make number mark pos header level)
- (cdr data)))
- (setq gnus-newsgroup-data-reverse nil)
- (gnus-data-update-list (cddr data) offset)))
- (defun gnus-data-enter-list (after-article list &optional offset)
- (when list
- (let ((data (and after-article (gnus-data-find-list after-article)))
- (ilist list))
- (if (not (or data
- after-article))
- (let ((odata gnus-newsgroup-data))
- (setq gnus-newsgroup-data (nconc list gnus-newsgroup-data))
- (when offset
- (gnus-data-update-list odata offset)))
- ;; Find the last element in the list to be spliced into the main
- ;; list.
- (setq list (last list))
- (if (not data)
- (progn
- (setcdr list gnus-newsgroup-data)
- (setq gnus-newsgroup-data ilist)
- (when offset
- (gnus-data-update-list (cdr list) offset)))
- (setcdr list (cdr data))
- (setcdr data ilist)
- (when offset
- (gnus-data-update-list (cdr list) offset))))
- (setq gnus-newsgroup-data-reverse nil))))
- (defun gnus-data-remove (article &optional offset)
- (let ((data gnus-newsgroup-data))
- (if (= (gnus-data-number (car data)) article)
- (progn
- (setq gnus-newsgroup-data (cdr gnus-newsgroup-data)
- gnus-newsgroup-data-reverse nil)
- (when offset
- (gnus-data-update-list gnus-newsgroup-data offset)))
- (while (cdr data)
- (when (= (gnus-data-number (cadr data)) article)
- (setcdr data (cddr data))
- (when offset
- (gnus-data-update-list (cdr data) offset))
- (setq data nil
- gnus-newsgroup-data-reverse nil))
- (setq data (cdr data))))))
- (defmacro gnus-data-list (backward)
- `(if ,backward
- (or gnus-newsgroup-data-reverse
- (setq gnus-newsgroup-data-reverse
- (reverse gnus-newsgroup-data)))
- gnus-newsgroup-data))
- (defun gnus-data-update-list (data offset)
- "Add OFFSET to the POS of all data entries in DATA."
- (setq gnus-newsgroup-data-reverse nil)
- (while data
- (setcar (nthcdr 2 (car data)) (+ offset (nth 2 (car data))))
- (setq data (cdr data))))
- (defun gnus-summary-article-pseudo-p (article)
- "Say whether this article is a pseudo article or not."
- (not (vectorp (gnus-data-header (gnus-data-find article)))))
- (defmacro gnus-summary-article-sparse-p (article)
- "Say whether this article is a sparse article or not."
- `(memq ,article gnus-newsgroup-sparse))
- (defmacro gnus-summary-article-ancient-p (article)
- "Say whether this article is a sparse article or not."
- `(memq ,article gnus-newsgroup-ancient))
- (defun gnus-article-children (number)
- "Return a list of all children to NUMBER."
- (let* ((data (gnus-data-find-list number))
- (level (gnus-data-level (car data)))
- children)
- (setq data (cdr data))
- (while (and data
- (= (gnus-data-level (car data)) (1+ level)))
- (push (gnus-data-number (car data)) children)
- (setq data (cdr data)))
- children))
- (defmacro gnus-summary-skip-intangible ()
- "If the current article is intangible, then jump to a different article."
- '(let ((to (get-text-property (point) 'gnus-intangible)))
- (and to (gnus-summary-goto-subject to))))
- (defmacro gnus-summary-article-intangible-p ()
- "Say whether this article is intangible or not."
- '(get-text-property (point) 'gnus-intangible))
- ;; Some summary mode macros.
- (defmacro gnus-summary-article-number ()
- "The article number of the article on the current line.
- If there isn't an article number here, then we return the current
- article number."
- '(progn
- (gnus-summary-skip-intangible)
- (or (get-text-property (point) 'gnus-number)
- (gnus-summary-last-subject))))
- (defmacro gnus-summary-article-header (&optional number)
- "Return the header of article NUMBER."
- `(gnus-data-header (gnus-data-find
- ,(or number '(gnus-summary-article-number)))))
- (defmacro gnus-summary-thread-level (&optional number)
- "Return the level of thread that starts with article NUMBER."
- `(if (and (eq gnus-summary-make-false-root 'dummy)
- (get-text-property (point) 'gnus-intangible))
- 0
- (gnus-data-level (gnus-data-find
- ,(or number '(gnus-summary-article-number))))))
- (defmacro gnus-summary-article-mark (&optional number)
- "Return the mark of article NUMBER."
- `(gnus-data-mark (gnus-data-find
- ,(or number '(gnus-summary-article-number)))))
- (defmacro gnus-summary-article-pos (&optional number)
- "Return the position of the line of article NUMBER."
- `(gnus-data-pos (gnus-data-find
- ,(or number '(gnus-summary-article-number)))))
- (defalias 'gnus-summary-subject-string 'gnus-summary-article-subject)
- (defmacro gnus-summary-article-subject (&optional number)
- "Return current subject string or nil if nothing."
- `(let ((headers
- ,(if number
- `(gnus-data-header (assq ,number gnus-newsgroup-data))
- '(gnus-data-header (assq (gnus-summary-article-number)
- gnus-newsgroup-data)))))
- (and headers
- (vectorp headers)
- (mail-header-subject headers))))
- (defmacro gnus-summary-article-score (&optional number)
- "Return current article score."
- `(or (cdr (assq ,(or number '(gnus-summary-article-number))
- gnus-newsgroup-scored))
- gnus-summary-default-score 0))
- (defun gnus-summary-article-children (&optional number)
- "Return a list of article numbers that are children of article NUMBER."
- (let* ((data (gnus-data-find-list (or number (gnus-summary-article-number))))
- (level (gnus-data-level (car data)))
- l children)
- (while (and (setq data (cdr data))
- (> (setq l (gnus-data-level (car data))) level))
- (and (= (1+ level) l)
- (push (gnus-data-number (car data))
- children)))
- (nreverse children)))
- (defun gnus-summary-article-parent (&optional number)
- "Return the article number of the parent of article NUMBER."
- (let* ((data (gnus-data-find-list (or number (gnus-summary-article-number))
- (gnus-data-list t)))
- (level (gnus-data-level (car data))))
- (if (zerop level)
- () ; This is a root.
- ;; We search until we find an article with a level less than
- ;; this one. That function has to be the parent.
- (while (and (setq data (cdr data))
- (not (< (gnus-data-level (car data)) level))))
- (and data (gnus-data-number (car data))))))
- (defun gnus-unread-mark-p (mark)
- "Say whether MARK is the unread mark."
- (= mark gnus-unread-mark))
- (defun gnus-read-mark-p (mark)
- "Say whether MARK is one of the marks that mark as read.
- This is all marks except unread, ticked, dormant, and expirable."
- (not (or (= mark gnus-unread-mark)
- (= mark gnus-ticked-mark)
- (= mark gnus-spam-mark)
- (= mark gnus-dormant-mark)
- (= mark gnus-expirable-mark))))
- (defmacro gnus-article-mark (number)
- "Return the MARK of article NUMBER.
- This macro should only be used when computing the mark the \"first\"
- time; i.e., when generating the summary lines. After that,
- `gnus-summary-article-mark' should be used to examine the
- marks of articles."
- `(cond
- ((memq ,number gnus-newsgroup-unsendable) gnus-unsendable-mark)
- ((memq ,number gnus-newsgroup-downloadable) gnus-downloadable-mark)
- ((memq ,number gnus-newsgroup-unreads) gnus-unread-mark)
- ((memq ,number gnus-newsgroup-marked) gnus-ticked-mark)
- ((memq ,number gnus-newsgroup-spam-marked) gnus-spam-mark)
- ((memq ,number gnus-newsgroup-dormant) gnus-dormant-mark)
- ((memq ,number gnus-newsgroup-expirable) gnus-expirable-mark)
- (t (or (cdr (assq ,number gnus-newsgroup-reads))
- gnus-ancient-mark))))
- ;; Saving hidden threads.
- (defmacro gnus-save-hidden-threads (&rest forms)
- "Save hidden threads, eval FORMS, and restore the hidden threads."
- (let ((config (make-symbol "config")))
- `(let ((,config (gnus-hidden-threads-configuration)))
- (unwind-protect
- (save-excursion
- ,@forms)
- (gnus-restore-hidden-threads-configuration ,config)))))
- (put 'gnus-save-hidden-threads 'lisp-indent-function 0)
- (put 'gnus-save-hidden-threads 'edebug-form-spec '(body))
- (defun gnus-data-compute-positions ()
- "Compute the positions of all articles."
- (setq gnus-newsgroup-data-reverse nil)
- (let ((data gnus-newsgroup-data))
- (save-excursion
- (gnus-save-hidden-threads
- (gnus-summary-show-all-threads)
- (goto-char (point-min))
- (while data
- (while (get-text-property (point) 'gnus-intangible)
- (forward-line 1))
- (gnus-data-set-pos (car data) (+ (point) 3))
- (setq data (cdr data))
- (forward-line 1))))))
- (defun gnus-hidden-threads-configuration ()
- "Return the current hidden threads configuration."
- (save-excursion
- (let (config)
- (goto-char (point-min))
- (while (not (eobp))
- (when (eq (get-char-property (point-at-eol) 'invisible) 'gnus-sum)
- (push (save-excursion (forward-line 0) (point)) config))
- (forward-line 1))
- config)))
- (defun gnus-restore-hidden-threads-configuration (config)
- "Restore hidden threads configuration from CONFIG."
- (save-excursion
- (let (point (inhibit-read-only t))
- (while (setq point (pop config))
- (goto-char point)
- (gnus-summary-hide-thread)))))
- ;; Various summary mode internalish functions.
- (defun gnus-mouse-pick-article (e)
- (interactive "e")
- (mouse-set-point e)
- (gnus-summary-next-page nil t))
- (defun gnus-summary-set-display-table ()
- "Change the display table.
- Odd characters have a tendency to mess
- up nicely formatted displays - we make all possible glyphs
- display only a single character."
- ;; We start from the standard display table, if any.
- (let ((table (or (copy-sequence standard-display-table)
- (make-display-table)))
- (i 32))
- ;; Nix out all the control chars...
- (while (>= (setq i (1- i)) 0)
- (gnus-put-display-table i [??] table))
- ;; ... but not newline and cr, of course. (cr is necessary for the
- ;; selective display).
- (gnus-put-display-table ?\n nil table)
- (gnus-put-display-table ?\r nil table)
- ;; We keep TAB as well.
- (gnus-put-display-table ?\t nil table)
- ;; We nix out any glyphs 127 through 255, or 127 through 159 in
- ;; Emacs 23 (unicode), that are not set already.
- (let ((i (if (ignore-errors (= (make-char 'latin-iso8859-1 160) 160))
- 160
- 256)))
- (while (>= (setq i (1- i)) 127)
- ;; Only modify if the entry is nil.
- (unless (gnus-get-display-table i table)
- (gnus-put-display-table i [??] table))))
- (setq buffer-display-table table)))
- (defun gnus-summary-set-article-display-arrow (pos)
- "Update the overlay arrow to point to line at position POS."
- (when gnus-summary-display-arrow
- (make-local-variable 'overlay-arrow-position)
- (make-local-variable 'overlay-arrow-string)
- (save-excursion
- (goto-char pos)
- (beginning-of-line)
- (unless overlay-arrow-position
- (setq overlay-arrow-position (make-marker)))
- (setq overlay-arrow-string "=>"
- overlay-arrow-position (set-marker overlay-arrow-position
- (point)
- (current-buffer))))))
- (defun gnus-summary-setup-buffer (group)
- "Initialize summary buffer.
- If the setup was successful, non-nil is returned."
- (let ((buffer (gnus-summary-buffer-name group))
- (dead-name (concat "*Dead Summary "
- (gnus-group-decoded-name group) "*")))
- ;; If a dead summary buffer exists, we kill it.
- (when (gnus-buffer-live-p dead-name)
- (gnus-kill-buffer dead-name))
- (if (get-buffer buffer)
- (progn
- (set-buffer buffer)
- (setq gnus-summary-buffer (current-buffer))
- (not gnus-newsgroup-prepared))
- (set-buffer (gnus-get-buffer-create buffer))
- (setq gnus-summary-buffer (current-buffer))
- (gnus-summary-mode group)
- (when (gnus-group-quit-config group)
- (set (make-local-variable 'gnus-single-article-buffer) nil))
- (make-local-variable 'gnus-article-buffer)
- (make-local-variable 'gnus-article-current)
- (make-local-variable 'gnus-original-article-buffer)
- (setq gnus-newsgroup-name group)
- ;; Set any local variables in the group parameters.
- (gnus-summary-set-local-parameters gnus-newsgroup-name)
- t)))
- (defun gnus-set-global-variables ()
- "Set the global equivalents of the buffer-local variables.
- They are set to the latest values they had. These reflect the summary
- buffer that was in action when the last article was fetched."
- (when (derived-mode-p 'gnus-summary-mode)
- (setq gnus-summary-buffer (current-buffer))
- (let ((name gnus-newsgroup-name)
- (marked gnus-newsgroup-marked)
- (spam gnus-newsgroup-spam-marked)
- (unread gnus-newsgroup-unreads)
- (headers gnus-current-headers)
- (data gnus-newsgroup-data)
- (summary gnus-summary-buffer)
- (article-buffer gnus-article-buffer)
- (original gnus-original-article-buffer)
- (gac gnus-article-current)
- (reffed gnus-reffed-article-number)
- (score-file gnus-current-score-file)
- (default-charset gnus-newsgroup-charset)
- vlist)
- (let ((locals gnus-newsgroup-variables))
- (while locals
- (if (consp (car locals))
- (push (eval (caar locals)) vlist)
- (push (eval (car locals)) vlist))
- (setq locals (cdr locals)))
- (setq vlist (nreverse vlist)))
- (with-temp-buffer
- (setq gnus-newsgroup-name name
- gnus-newsgroup-marked marked
- gnus-newsgroup-spam-marked spam
- gnus-newsgroup-unreads unread
- gnus-current-headers headers
- gnus-newsgroup-data data
- gnus-article-current gac
- gnus-summary-buffer summary
- gnus-article-buffer article-buffer
- gnus-original-article-buffer original
- gnus-reffed-article-number reffed
- gnus-current-score-file score-file
- gnus-newsgroup-charset default-charset)
- (let ((locals gnus-newsgroup-variables))
- (while locals
- (if (consp (car locals))
- (set (caar locals) (pop vlist))
- (set (car locals) (pop vlist)))
- (setq locals (cdr locals))))))))
- (defun gnus-summary-article-unread-p (article)
- "Say whether ARTICLE is unread or not."
- (memq article gnus-newsgroup-unreads))
- (defun gnus-summary-first-article-p (&optional article)
- "Return whether ARTICLE is the first article in the buffer."
- (if (not (setq article (or article (gnus-summary-article-number))))
- nil
- (eq article (caar gnus-newsgroup-data))))
- (defun gnus-summary-last-article-p (&optional article)
- "Return whether ARTICLE is the last article in the buffer."
- (if (not (setq article (or article (gnus-summary-article-number))))
- ;; All non-existent numbers are the last article. :-)
- t
- (not (cdr (gnus-data-find-list article)))))
- (defun gnus-make-thread-indent-array (&optional n)
- (when (or n
- (progn (setq n 200) nil)
- (null gnus-thread-indent-array)
- (/= gnus-thread-indent-level gnus-thread-indent-array-level))
- (setq gnus-thread-indent-array (make-vector (1+ n) "")
- gnus-thread-indent-array-level gnus-thread-indent-level)
- (while (>= n 0)
- (aset gnus-thread-indent-array n
- (make-string (* n gnus-thread-indent-level) ? ))
- (setq n (1- n)))))
- (defun gnus-update-summary-mark-positions ()
- "Compute where the summary marks are to go."
- (save-excursion
- (when (gnus-buffer-exists-p gnus-summary-buffer)
- (set-buffer gnus-summary-buffer))
- (let ((spec gnus-summary-line-format-spec)
- pos)
- (save-excursion
- (gnus-set-work-buffer)
- (let ((gnus-tmp-unread ?Z)
- (gnus-replied-mark ?Z)
- (gnus-score-below-mark ?Z)
- (gnus-score-over-mark ?Z)
- (gnus-undownloaded-mark ?Z)
- (gnus-summary-line-format-spec spec)
- (gnus-newsgroup-downloadable '(0))
- (header [0 "" "" "05 Apr 2001 23:33:09 +0400" "" "" 0 0 "" nil])
- case-fold-search ignores)
- ;; Here, all marks are bound to Z.
- (gnus-summary-insert-line header
- 0 nil t gnus-tmp-unread t nil "" nil 1)
- (goto-char (point-min))
- ;; Memorize the positions of the same characters as dummy marks.
- (while (re-search-forward "[A-D]" nil t)
- (push (point) ignores))
- (erase-buffer)
- ;; We use A-D as dummy marks in order to know column positions
- ;; where marks should be inserted.
- (setq gnus-tmp-unread ?A
- gnus-replied-mark ?B
- gnus-score-below-mark ?C
- gnus-score-over-mark ?C
- gnus-undownloaded-mark ?D)
- (gnus-summary-insert-line header
- 0 nil t gnus-tmp-unread t nil "" nil 1)
- ;; Ignore characters which aren't dummy marks.
- (dolist (p ignores)
- (delete-region (goto-char (1- p)) p)
- (insert ?Z))
- (goto-char (point-min))
- (setq pos (list (cons 'unread
- (and (search-forward "A" nil t)
- (- (point) (point-min) 1)))))
- (goto-char (point-min))
- (push (cons 'replied (and (search-forward "B" nil t)
- (- (point) (point-min) 1)))
- pos)
- (goto-char (point-min))
- (push (cons 'score (and (search-forward "C" nil t)
- (- (point) (point-min) 1)))
- pos)
- (goto-char (point-min))
- (push (cons 'download (and (search-forward "D" nil t)
- (- (point) (point-min) 1)))
- pos)))
- (setq gnus-summary-mark-positions pos))))
- (defun gnus-summary-insert-dummy-line (gnus-tmp-subject gnus-tmp-number)
- "Insert a dummy root in the summary buffer."
- (beginning-of-line)
- (gnus-add-text-properties
- (point) (progn (eval gnus-summary-dummy-line-format-spec) (point))
- (list 'gnus-number gnus-tmp-number 'gnus-intangible gnus-tmp-number)))
- (defun gnus-summary-extract-address-component (from)
- (or (car (funcall gnus-extract-address-components from))
- from))
- (defun gnus-summary-from-or-to-or-newsgroups (header gnus-tmp-from)
- (let ((mail-parse-charset gnus-newsgroup-charset)
- (ignored-from-addresses (gnus-ignored-from-addresses))
- ;; Is it really necessary to do this next part for each summary line?
- ;; Luckily, doesn't seem to slow things down much.
- (mail-parse-ignored-charsets
- (with-current-buffer gnus-summary-buffer
- gnus-newsgroup-ignored-charsets)))
- (or
- (and ignored-from-addresses
- (string-match ignored-from-addresses gnus-tmp-from)
- (let ((extra-headers (mail-header-extra header))
- to
- newsgroups)
- (cond
- ((setq to (cdr (assq 'To extra-headers)))
- (concat gnus-summary-to-prefix
- (inline
- (gnus-summary-extract-address-component
- (funcall gnus-decode-encoded-address-function to)))))
- ((setq newsgroups
- (or
- (cdr (assq 'Newsgroups extra-headers))
- (and
- (memq 'Newsgroups gnus-extra-headers)
- (eq (car (gnus-find-method-for-group
- gnus-newsgroup-name)) 'nntp)
- (gnus-group-real-name gnus-newsgroup-name))))
- (concat gnus-summary-newsgroup-prefix newsgroups)))))
- (gnus-string-mark-left-to-right
- (inline
- (gnus-summary-extract-address-component gnus-tmp-from))))))
- (defun gnus-summary-insert-line (gnus-tmp-header
- gnus-tmp-level gnus-tmp-current
- undownloaded gnus-tmp-unread gnus-tmp-replied
- gnus-tmp-expirable gnus-tmp-subject-or-nil
- &optional gnus-tmp-dummy gnus-tmp-score
- gnus-tmp-process)
- (if (>= gnus-tmp-level (length gnus-thread-indent-array))
- (gnus-make-thread-indent-array (max (* 2 (length gnus-thread-indent-array))
- gnus-tmp-level)))
- (let* ((gnus-tmp-indentation (aref gnus-thread-indent-array gnus-tmp-level))
- (gnus-tmp-lines (mail-header-lines gnus-tmp-header))
- (gnus-tmp-score (or gnus-tmp-score gnus-summary-default-score 0))
- (gnus-tmp-score-char
- (if (or (null gnus-summary-default-score)
- (<= (abs (- gnus-tmp-score gnus-summary-default-score))
- gnus-summary-zcore-fuzz))
- ? ;Whitespace
- (if (< gnus-tmp-score gnus-summary-default-score)
- gnus-score-below-mark gnus-score-over-mark)))
- (gnus-tmp-number (mail-header-number gnus-tmp-header))
- (gnus-tmp-replied
- (cond (gnus-tmp-process gnus-process-mark)
- ((memq gnus-tmp-current gnus-newsgroup-cached)
- gnus-cached-mark)
- (gnus-tmp-replied gnus-replied-mark)
- ((memq gnus-tmp-current gnus-newsgroup-forwarded)
- gnus-forwarded-mark)
- ((memq gnus-tmp-current gnus-newsgroup-saved)
- gnus-saved-mark)
- ((memq gnus-tmp-number gnus-newsgroup-unseen)
- gnus-unseen-mark)
- (t gnus-no-mark)))
- (gnus-tmp-downloaded
- (cond (undownloaded
- gnus-undownloaded-mark)
- (gnus-newsgroup-agentized
- gnus-downloaded-mark)
- (t
- gnus-no-mark)))
- (gnus-tmp-from (mail-header-from gnus-tmp-header))
- (gnus-tmp-name
- (cond
- ((string-match "<[^>]+> *$" gnus-tmp-from)
- (let ((beg (match-beginning 0)))
- (or (and (string-match "^\".+\"" gnus-tmp-from)
- (substring gnus-tmp-from 1 (1- (match-end 0))))
- (substring gnus-tmp-from 0 beg))))
- ((string-match "(.+)" gnus-tmp-from)
- (substring gnus-tmp-from
- (1+ (match-beginning 0)) (1- (match-end 0))))
- (t gnus-tmp-from)))
- (gnus-tmp-subject (mail-header-subject gnus-tmp-header))
- (gnus-tmp-opening-bracket (if gnus-tmp-dummy ?\< ?\[))
- (gnus-tmp-closing-bracket (if gnus-tmp-dummy ?\> ?\]))
- (inhibit-read-only t))
- (when (string= gnus-tmp-name "")
- (setq gnus-tmp-name gnus-tmp-from))
- (unless (numberp gnus-tmp-lines)
- (setq gnus-tmp-lines -1))
- (if (= gnus-tmp-lines -1)
- (setq gnus-tmp-lines "?")
- (setq gnus-tmp-lines (number-to-string gnus-tmp-lines)))
- (condition-case ()
- (gnus-put-text-property
- (point)
- (progn (eval gnus-summary-line-format-spec) (point))
- 'gnus-number gnus-tmp-number)
- (error (gnus-message 5 "Error updating the summary line")))
- (when (gnus-visual-p 'summary-highlight 'highlight)
- (forward-line -1)
- (gnus-summary-highlight-line)
- (gnus-run-hooks 'gnus-summary-update-hook)
- (forward-line 1))))
- (defun gnus-summary-update-line (&optional dont-update)
- "Update summary line after change."
- (when (and gnus-summary-default-score
- (not gnus-summary-inhibit-highlight))
- (let* ((gnus-summary-inhibit-highlight t) ; Prevent recursion.
- (article (gnus-summary-article-number))
- (score (gnus-summary-article-score article)))
- (unless dont-update
- (if (and gnus-summary-mark-below
- (< (gnus-summary-article-score)
- gnus-summary-mark-below))
- ;; This article has a low score, so we mark it as read.
- (when (memq article gnus-newsgroup-unreads)
- (gnus-summary-mark-article-as-read gnus-low-score-mark))
- (when (eq (gnus-summary-article-mark) gnus-low-score-mark)
- ;; This article was previously marked as read on account
- ;; of a low score, but now it has risen, so we mark it as
- ;; unread.
- (gnus-summary-mark-article-as-unread gnus-unread-mark)))
- (gnus-summary-update-mark
- (if (or (null gnus-summary-default-score)
- (<= (abs (- score gnus-summary-default-score))
- gnus-summary-zcore-fuzz))
- ? ;Whitespace
- (if (< score gnus-summary-default-score)
- gnus-score-below-mark gnus-score-over-mark))
- 'score))
- ;; Do visual highlighting.
- (when (gnus-visual-p 'summary-highlight 'highlight)
- (gnus-summary-highlight-line)
- (gnus-run-hooks 'gnus-summary-update-hook)))))
- (defvar gnus-tmp-new-adopts nil)
- (defun gnus-summary-number-of-articles-in-thread (thread &optional level char)
- "Return the number of articles in THREAD.
- This may be 0 in some cases -- if none of the articles in
- the thread are to be displayed."
- (let* ((number
- ;; Fix by Luc Van Eycken <Luc.VanEycken@esat.kuleuven.ac.be>.
- (cond
- ((not (listp thread))
- 1)
- ((and (consp thread) (cdr thread))
- (apply
- '+ 1 (mapcar
- 'gnus-summary-number-of-articles-in-thread (cdr thread))))
- ((null thread)
- 1)
- ((memq (mail-header-number (car thread)) gnus-newsgroup-limit)
- 1)
- (t 0))))
- (when (and level (zerop level) gnus-tmp-new-adopts)
- (incf number
- (apply '+ (mapcar
- 'gnus-summary-number-of-articles-in-thread
- gnus-tmp-new-adopts))))
- (if char
- (if (> number 1) gnus-not-empty-thread-mark
- gnus-empty-thread-mark)
- number)))
- (defsubst gnus-summary-line-message-size (head)
- "Return pretty-printed version of message size.
- This function is intended to be used in
- `gnus-summary-line-format-alist'."
- (let ((c (or (mail-header-chars head) -1)))
- (cond ((< c 0) "n/a") ; chars not available
- ((< c (* 1000 10)) (format "%1.1fk" (/ c 1024.0)))
- ((< c (* 1000 100)) (format "%dk" (/ c 1024.0)))
- ((< c (* 1000 10000)) (format "%1.1fM" (/ c (* 1024.0 1024))))
- (t (format "%dM" (/ c (* 1024.0 1024)))))))
- (defcustom gnus-user-date-format-alist
- '(((gnus-seconds-today) . "Today, %H:%M")
- ((+ 86400 (gnus-seconds-today)) . "Yesterday, %H:%M")
- (604800 . "%A %H:%M") ; That's one week
- ((gnus-seconds-month) . "%A %d")
- ((gnus-seconds-year) . "%B %d")
- (t . "%b %d %Y")) ; This one is used when no other
- ; does match
- "Specifies date format depending on age of article.
- This is an alist of items (AGE . FORMAT). AGE can be a number (of
- seconds) or a Lisp expression evaluating to a number. When the age of
- the article is less than this number, then use `format-time-string'
- with the corresponding FORMAT for displaying the date of the article.
- If AGE is not a number or a Lisp expression evaluating to a
- non-number, then the corresponding FORMAT is used as a default value.
- Note that the list is processed from the beginning, so it should be
- sorted by ascending AGE. Also note that items following the first
- non-number AGE will be ignored.
- You can use the functions `gnus-seconds-today', `gnus-seconds-month'
- and `gnus-seconds-year' in the AGE spec. They return the number of
- seconds passed since the start of today, of this month, of this year,
- respectively."
- :version "24.1"
- :group 'gnus-summary-format
- :type '(alist :key-type sexp :value-type string))
- (defun gnus-user-date (messy-date)
- "Format the messy-date according to `gnus-user-date-format-alist'.
- Returns \" ? \" if there's bad input or if another error occurs.
- Input should look like this: \"Sun, 14 Oct 2001 13:34:39 +0200\"."
- (condition-case ()
- (let* ((messy-date (gnus-float-time (gnus-date-get-time messy-date)))
- (now (gnus-float-time))
- ;;If we don't find something suitable we'll use this one
- (my-format "%b %d '%y"))
- (let* ((difference (- now messy-date))
- (templist gnus-user-date-format-alist)
- (top (eval (caar templist))))
- (while (if (numberp top) (< top difference) (not top))
- (progn
- (setq templist (cdr templist))
- (setq top (eval (caar templist)))))
- (if (stringp (cdr (car templist)))
- (setq my-format (cdr (car templist)))))
- (format-time-string (eval my-format) (seconds-to-time messy-date)))
- (error " ? ")))
- (defun gnus-summary-set-local-parameters (group)
- "Go through the local params of GROUP and set all variable specs in that list."
- (let ((vars '(quit-config active))) ; Ignore things that aren't
- ; really variables.
- (dolist (elem (gnus-group-find-parameter group))
- (and (consp elem) ; Has to be a cons.
- (consp (cdr elem)) ; The cdr has to be a list.
- (symbolp (car elem)) ; Has to be a symbol in there.
- (not (memq (car elem) vars))
- (ignore-errors
- (push (car elem) vars)
- ;; Variables like `gnus-show-threads' that are globally
- ;; bound, if used as group parameters, need to get to be
- ;; buffer-local, whereas just parameters like `gcc-self',
- ;; `timestamp', etc. should not be bound as variables.
- (if (boundp (car elem))
- (set (make-local-variable (car elem)) (eval (nth 1 elem)))
- (eval (nth 1 elem))))))))
- (defun gnus-summary-read-group (group &optional show-all no-article
- kill-buffer no-display backward
- select-articles)
- "Start reading news in newsgroup GROUP.
- If SHOW-ALL is non-nil, already read articles are also listed.
- If NO-ARTICLE is non-nil, no article is selected initially.
- If NO-DISPLAY, don't generate the summary buffer contents.
- If KILL-BUFFER, it should be a buffer that's killed once the new
- summary buffer has been generated.
- If BACKWARD, move point to the previous group in the group buffer
- If SELECT-ARTICLES, only select those articles from GROUP."
- (let (result)
- (while (and group
- (null (setq result
- (let ((gnus-auto-select-next nil))
- (or (gnus-summary-read-group-1
- group show-all no-article
- kill-buffer no-display
- select-articles)
- (setq show-all nil
- select-articles nil)))))
- (eq gnus-auto-select-next 'quietly))
- (set-buffer gnus-group-buffer)
- ;; The entry function called above goes to the next
- ;; group automatically, so we go two groups back
- ;; if we are searching for the previous group.
- (when backward
- (gnus-group-prev-unread-group 2))
- (if (not (equal group (gnus-group-group-name)))
- (setq group (gnus-group-group-name))
- (setq group nil)))
- result))
- (defun gnus-summary-read-group-1 (group show-all no-article
- kill-buffer no-display
- &optional select-articles)
- ;; Killed foreign groups can't be entered.
- ;; (when (and (not (gnus-group-native-p group))
- ;; (not (gnus-gethash group gnus-newsrc-hashtb)))
- ;; (error "Dead non-native groups can't be entered"))
- (gnus-message 7 "Retrieving newsgroup: %s..."
- (gnus-group-decoded-name group))
- (let* ((new-group (gnus-summary-setup-buffer group))
- (quit-config (gnus-group-quit-config group))
- (did-select (and new-group (gnus-select-newsgroup
- group show-all select-articles))))
- (cond
- ;; This summary buffer exists already, so we just select it.
- ((not new-group)
- (gnus-set-global-variables)
- (when kill-buffer
- (gnus-kill-or-deaden-summary kill-buffer))
- (gnus-configure-windows 'summary 'force)
- (gnus-set-mode-line 'summary)
- (gnus-summary-position-point)
- (message "")
- t)
- ;; We couldn't select this group.
- ((null did-select)
- (when (and (derived-mode-p 'gnus-summary-mode)
- (not (equal (current-buffer) kill-buffer)))
- (kill-buffer (current-buffer))
- (if (not quit-config)
- (progn
- ;; Update the info -- marks might need to be removed,
- ;; for instance.
- (gnus-summary-update-info)
- (set-buffer gnus-group-buffer)
- (gnus-group-jump-to-group group)
- (gnus-group-next-unread-group 1))
- (gnus-handle-ephemeral-exit quit-config)))
- (if (null (gnus-list-of-unread-articles group))
- (gnus-message 3 "Group %s contains no messages" group)
- (gnus-message 3 "Can't select group"))
- nil)
- ;; The user did a `C-g' while prompting for number of articles,
- ;; so we exit this group.
- ((eq did-select 'quit)
- (and (derived-mode-p 'gnus-summary-mode)
- (not (equal (current-buffer) kill-buffer))
- (kill-buffer (current-buffer)))
- (when kill-buffer
- (gnus-kill-or-deaden-summary kill-buffer))
- (if (not quit-config)
- (progn
- (set-buffer gnus-group-buffer)
- (gnus-group-jump-to-group group)
- (gnus-configure-windows 'group 'force))
- (gnus-handle-ephemeral-exit quit-config))
- ;; Finally signal the quit.
- (signal 'quit nil))
- ;; The group was successfully selected.
- (t
- (gnus-set-global-variables)
- (when (boundp 'spam-install-hooks)
- (spam-initialize))
- ;; Save the active value in effect when the group was entered.
- (setq gnus-newsgroup-active
- (gnus-copy-sequence
- (gnus-active gnus-newsgroup-name)))
- (setq gnus-newsgroup-highest (cdr gnus-newsgroup-active))
- ;; You can change the summary buffer in some way with this hook.
- (gnus-run-hooks 'gnus-select-group-hook)
- (when (memq 'summary (gnus-update-format-specifications
- nil 'summary 'summary-mode 'summary-dummy))
- ;; The format specification for the summary line was updated,
- ;; so we need to update the mark positions as well.
- (gnus-update-summary-mark-positions))
- ;; Do score processing.
- (when gnus-use-scoring
- (gnus-possibly-score-headers))
- ;; Check whether to fill in the gaps in the threads.
- (when gnus-build-sparse-threads
- (gnus-build-sparse-threads))
- ;; Find the initial limit.
- (if show-all
- (let ((gnus-newsgroup-dormant nil))
- (gnus-summary-initial-limit show-all))
- (gnus-summary-initial-limit show-all))
- ;; Generate the summary buffer.
- (unless no-display
- (gnus-summary-prepare))
- (when gnus-use-trees
- (gnus-tree-open)
- (setq gnus-summary-highlight-line-function
- 'gnus-tree-highlight-article))
- ;; If the summary buffer is empty, but there are some low-scored
- ;; articles or some excluded dormants, we include these in the
- ;; buffer.
- (when (and (zerop (buffer-size))
- (not no-display))
- (cond (gnus-newsgroup-dormant
- (gnus-summary-limit-include-dormant))
- ((and gnus-newsgroup-scored show-all)
- (gnus-summary-limit-include-expunged t))))
- ;; Function `gnus-apply-kill-file' must be called in this hook.
- (gnus-run-hooks 'gnus-apply-kill-hook)
- (if (and (zerop (buffer-size))
- (not no-display))
- (progn
- ;; This newsgroup is empty.
- (gnus-summary-catchup-and-exit nil t)
- (gnus-message 6 "No unread news")
- (when kill-buffer
- (gnus-kill-or-deaden-summary kill-buffer))
- ;; Return nil from this function.
- nil)
- ;; Hide conversation thread subtrees. We cannot do this in
- ;; gnus-summary-prepare-hook since kill processing may not
- ;; work with hidden articles.
- (gnus-summary-maybe-hide-threads)
- (gnus-configure-windows 'summary)
- (when kill-buffer
- (gnus-kill-or-deaden-summary kill-buffer))
- (gnus-summary-auto-select-subject)
- ;; Show first unread article if requested.
- (if (and (not no-article)
- (not no-display)
- gnus-newsgroup-unreads
- gnus-auto-select-first)
- (progn
- (let ((art (gnus-summary-article-number)))
- (when (and art
- gnus-plugged
- (not (memq art gnus-newsgroup-undownloaded))
- (not (memq art gnus-newsgroup-downloadable)))
- (gnus-summary-goto-article art))))
- ;; Don't select any articles.
- (gnus-summary-position-point)
- (gnus-configure-windows 'summary 'force)
- (gnus-set-mode-line 'summary))
- (when (and gnus-auto-center-group
- (get-buffer-window gnus-group-buffer t))
- ;; Gotta use windows, because recenter does weird stuff if
- ;; the current buffer ain't the displayed window.
- (let ((owin (selected-window)))
- (select-window (get-buffer-window gnus-group-buffer t))
- (when (gnus-group-goto-group group)
- (recenter))
- (select-window owin)))
- ;; Mark this buffer as "prepared".
- (setq gnus-newsgroup-prepared t)
- (gnus-run-hooks 'gnus-summary-prepared-hook)
- (unless (gnus-ephemeral-group-p group)
- (gnus-group-update-group group nil t))
- t)))))
- (defun gnus-summary-auto-select-subject ()
- "Select the subject line on initial group entry."
- (goto-char (point-min))
- (cond
- ((eq gnus-auto-select-subject 'best)
- (gnus-summary-best-unread-subject))
- ((eq gnus-auto-select-subject 'unread)
- (gnus-summary-first-unread-subject))
- ((eq gnus-auto-select-subject 'unseen)
- (gnus-summary-first-unseen-subject))
- ((eq gnus-auto-select-subject 'unseen-or-unread)
- (gnus-summary-first-unseen-or-unread-subject))
- ((eq gnus-auto-select-subject 'first)
- ;; Do nothing.
- )
- ((functionp gnus-auto-select-subject)
- (funcall gnus-auto-select-subject))))
- (defun gnus-summary-prepare ()
- "Generate the summary buffer."
- (interactive)
- (let ((inhibit-read-only t))
- (erase-buffer)
- (setq gnus-newsgroup-data nil
- gnus-newsgroup-data-reverse nil)
- (gnus-run-hooks 'gnus-summary-generate-hook)
- ;; Generate the buffer, either with threads or without.
- (when gnus-newsgroup-headers
- (gnus-summary-prepare-threads
- (if gnus-show-threads
- (gnus-sort-gathered-threads
- (funcall gnus-summary-thread-gathering-function
- (gnus-sort-threads
- (gnus-cut-threads (gnus-make-threads)))))
- ;; Unthreaded display.
- (gnus-sort-articles gnus-newsgroup-headers))))
- (setq gnus-newsgroup-data (nreverse gnus-newsgroup-data))
- ;; Call hooks for modifying summary buffer.
- (goto-char (point-min))
- (gnus-run-hooks 'gnus-summary-prepare-hook)))
- (defsubst gnus-general-simplify-subject (subject)
- "Simplify subject by the same rules as `gnus-gather-threads-by-subject'."
- (setq subject
- (cond
- ;; Truncate the subject.
- (gnus-simplify-subject-functions
- (gnus-map-function gnus-simplify-subject-functions subject))
- ((numberp gnus-summary-gather-subject-limit)
- (setq subject (gnus-simplify-subject-re subject))
- (if (> (length subject) gnus-summary-gather-subject-limit)
- (substring subject 0 gnus-summary-gather-subject-limit)
- subject))
- ;; Fuzzily simplify it.
- ((eq 'fuzzy gnus-summary-gather-subject-limit)
- (gnus-simplify-subject-fuzzy subject))
- ;; Just remove the leading "Re:".
- (t
- (gnus-simplify-subject-re subject))))
- (if (and gnus-summary-gather-exclude-subject
- (string-match gnus-summary-gather-exclude-subject subject))
- nil ; This article shouldn't be gathered
- subject))
- (defun gnus-summary-simplify-subject-query ()
- "Query where the respool algorithm would put this article."
- (interactive)
- (gnus-summary-select-article)
- (message "%s" (gnus-general-simplify-subject (gnus-summary-article-subject))))
- (defun gnus-gather-threads-by-subject (threads)
- "Gather threads by looking at Subject headers."
- (if (not gnus-summary-make-false-root)
- threads
- (let ((hashtb (gnus-make-hashtable 1024))
- (prev threads)
- (result threads)
- subject hthread whole-subject)
- (while threads
- (setq subject (gnus-general-simplify-subject
- (setq whole-subject (mail-header-subject
- (caar threads)))))
- (when subject
- (if (setq hthread (gnus-gethash subject hashtb))
- (progn
- ;; We enter a dummy root into the thread, if we
- ;; haven't done that already.
- (unless (stringp (caar hthread))
- (setcar hthread (list whole-subject (car hthread))))
- ;; We add this new gathered thread to this gathered
- ;; thread.
- (setcdr (car hthread)
- (nconc (cdar hthread) (list (car threads))))
- ;; Remove it from the list of threads.
- (setcdr prev (cdr threads))
- (setq threads prev))
- ;; Enter this thread into the hash table.
- (gnus-sethash subject
- (if gnus-summary-make-false-root-always
- (progn
- ;; If you want a dummy root above all
- ;; threads...
- (setcar threads (list whole-subject
- (car threads)))
- threads)
- threads)
- hashtb)))
- (setq prev threads)
- (setq threads (cdr threads)))
- result)))
- (defun gnus-gather-threads-by-references (threads)
- "Gather threads by looking at References headers."
- (let ((idhashtb (gnus-make-hashtable 1024))
- (thhashtb (gnus-make-hashtable 1024))
- (prev threads)
- (result threads)
- ids references id gthread gid entered ref)
- (while threads
- (when (setq references (mail-header-references (caar threads)))
- (setq id (mail-header-id (caar threads))
- ids (inline (gnus-split-references references))
- entered nil)
- (while (setq ref (pop ids))
- (setq ids (delete ref ids))
- (if (not (setq gid (gnus-gethash ref idhashtb)))
- (progn
- (gnus-sethash ref id idhashtb)
- (gnus-sethash id threads thhashtb))
- (setq gthread (gnus-gethash gid thhashtb))
- (unless entered
- ;; We enter a dummy root into the thread, if we
- ;; haven't done that already.
- (unless (stringp (caar gthread))
- (setcar gthread (list (mail-header-subject (caar gthread))
- (car gthread))))
- ;; We add this new gathered thread to this gathered
- ;; thread.
- (setcdr (car gthread)
- (nconc (cdar gthread) (list (car threads)))))
- ;; Add it into the thread hash table.
- (gnus-sethash id gthread thhashtb)
- (setq entered t)
- ;; Remove it from the list of threads.
- (setcdr prev (cdr threads))
- (setq threads prev))))
- (setq prev threads)
- (setq threads (cdr threads)))
- result))
- (defun gnus-sort-gathered-threads (threads)
- "Sort subthreads inside each gathered thread by `gnus-sort-gathered-threads-function'."
- (let ((result threads))
- (while threads
- (when (stringp (caar threads))
- (setcdr (car threads)
- (sort (cdar threads) gnus-sort-gathered-threads-function)))
- (setq threads (cdr threads)))
- result))
- (defun gnus-thread-loop-p (root thread)
- "Say whether ROOT is in THREAD."
- (let ((stack (list thread))
- (infloop 0)
- th)
- (while (setq thread (pop stack))
- (setq th (cdr thread))
- (while (and th
- (not (eq (caar th) root)))
- (pop th))
- (if th
- ;; We have found a loop.
- (let (ref-dep)
- (setcdr thread (delq (car th) (cdr thread)))
- (if (boundp (setq ref-dep (intern "none"
- gnus-newsgroup-dependencies)))
- (setcdr (symbol-value ref-dep)
- (nconc (cdr (symbol-value ref-dep))
- (list (car th))))
- (set ref-dep (list nil (car th))))
- (setq infloop 1
- stack nil))
- ;; Push all the subthreads onto the stack.
- (push (cdr thread) stack)))
- infloop))
- (defun gnus-make-threads ()
- "Go through the dependency hashtb and find the roots. Return all threads."
- (let (threads)
- (while (catch 'infloop
- (mapatoms
- (lambda (refs)
- ;; Deal with self-referencing References loops.
- (when (and (car (symbol-value refs))
- (not (zerop
- (apply
- '+
- (mapcar
- (lambda (thread)
- (gnus-thread-loop-p
- (car (symbol-value refs)) thread))
- (cdr (symbol-value refs)))))))
- (setq threads nil)
- (throw 'infloop t))
- (unless (car (symbol-value refs))
- ;; These threads do not refer back to any other
- ;; articles, so they're roots.
- (setq threads (append (cdr (symbol-value refs)) threads))))
- gnus-newsgroup-dependencies)))
- threads))
- ;; Build the thread tree.
- (defsubst gnus-dependencies-add-header (header dependencies force-new)
- "Enter HEADER into the DEPENDENCIES table if it is not already there.
- If FORCE-NEW is not nil, enter HEADER into the DEPENDENCIES table even
- if it was already present.
- If `gnus-summary-ignore-duplicates' is nil then duplicate Message-IDs
- will not be entered in the DEPENDENCIES table. Otherwise duplicate
- Message-IDs will be renamed to a unique Message-ID before being
- entered.
- Returns HEADER if it was entered in the DEPENDENCIES. Returns nil otherwise."
- (let* ((id (mail-header-id header))
- (id-dep (and id (intern id dependencies)))
- parent-id ref ref-dep ref-header replaced)
- ;; Enter this `header' in the `dependencies' table.
- (cond
- ((not id-dep)
- (setq header nil))
- ;; The first two cases do the normal part: enter a new `header'
- ;; in the `dependencies' table.
- ((not (boundp id-dep))
- (set id-dep (list header)))
- ((null (car (symbol-value id-dep)))
- (setcar (symbol-value id-dep) header))
- ;; From here the `header' was already present in the
- ;; `dependencies' table.
- (force-new
- ;; Overrides an existing entry;
- ;; just set the header part of the entry.
- (setcar (symbol-value id-dep) header)
- (setq replaced t))
- ;; Renames the existing `header' to a unique Message-ID.
- ((not gnus-summary-ignore-duplicates)
- ;; An article with this Message-ID has already been seen.
- ;; We rename the Message-ID.
- (set (setq id-dep (intern (setq id (nnmail-message-id)) dependencies))
- (list header))
- (mail-header-set-id header id))
- ;; The last case ignores an existing entry, except it adds any
- ;; additional Xrefs (in case the two articles came from different
- ;; servers.
- ;; Also sets `header' to nil meaning that the `dependencies'
- ;; table was *not* modified.
- (t
- (mail-header-set-xref
- (car (symbol-value id-dep))
- (concat (or (mail-header-xref (car (symbol-value id-dep)))
- "")
- (or (mail-header-xref header) "")))
- (setq header nil)))
- (when (and header (not replaced))
- ;; First check that we are not creating a References loop.
- (setq parent-id (gnus-parent-id (mail-header-references header)))
- (setq ref parent-id)
- (while (and ref
- (setq ref-dep (intern-soft ref dependencies))
- (boundp ref-dep)
- (setq ref-header (car (symbol-value ref-dep))))
- (if (string= id ref)
- ;; Yuk! This is a reference loop. Make the article be a
- ;; root article.
- (progn
- (mail-header-set-references (car (symbol-value id-dep)) "none")
- (setq ref nil)
- (setq parent-id nil))
- (setq ref (gnus-parent-id (mail-header-references ref-header)))))
- (setq ref-dep (intern (or parent-id "none") dependencies))
- (if (boundp ref-dep)
- (setcdr (symbol-value ref-dep)
- (nconc (cdr (symbol-value ref-dep))
- (list (symbol-value id-dep))))
- (set ref-dep (list nil (symbol-value id-dep)))))
- header))
- (defun gnus-extract-message-id-from-in-reply-to (string)
- (if (string-match "<[^>]+>" string)
- (substring string (match-beginning 0) (match-end 0))
- nil))
- (defun gnus-build-sparse-threads ()
- (let ((headers gnus-newsgroup-headers)
- (mail-parse-charset gnus-newsgroup-charset)
- (gnus-summary-ignore-duplicates t)
- header references generation relations
- subject child end new-child date)
- ;; First we create an alist of generations/relations, where
- ;; generations is how much we trust the relation, and the relation
- ;; is parent/child.
- (gnus-message 7 "Making sparse threads...")
- (save-excursion
- (nnheader-set-temp-buffer " *gnus sparse threads*")
- (while (setq header (pop headers))
- (when (and (setq references (mail-header-references header))
- (not (string= references "")))
- (insert references)
- (setq child (mail-header-id header)
- subject (mail-header-subject header)
- date (mail-header-date header)
- generation 0)
- (while (search-backward ">" nil t)
- (setq end (1+ (point)))
- (when (search-backward "<" nil t)
- (setq new-child (buffer-substring (point) end))
- (push (list (incf generation)
- child (setq child new-child)
- subject date)
- relations)))
- (when child
- (push (list (1+ generation) child nil subject) relations))
- (erase-buffer)))
- (kill-buffer (current-buffer)))
- ;; Sort over trustworthiness.
- (dolist (relation (sort relations 'car-less-than-car))
- (when (gnus-dependencies-add-header
- (make-full-mail-header
- gnus-reffed-article-number
- (nth 3 relation) "" (or (nth 4 relation) "")
- (nth 1 relation)
- (or (nth 2 relation) "") 0 0 "")
- gnus-newsgroup-dependencies nil)
- (push gnus-reffed-article-number gnus-newsgroup-limit)
- (push gnus-reffed-article-number gnus-newsgroup-sparse)
- (push (cons gnus-reffed-article-number gnus-sparse-mark)
- gnus-newsgroup-reads)
- (decf gnus-reffed-article-number)))
- (gnus-message 7 "Making sparse threads...done")))
- (defun gnus-build-old-threads ()
- ;; Look at all the articles that refer back to old articles, and
- ;; fetch the headers for the articles that aren't there. This will
- ;; build complete threads - if the roots haven't been expired by the
- ;; server, that is.
- (let ((mail-parse-charset gnus-newsgroup-charset)
- id heads)
- (mapatoms
- (lambda (refs)
- (when (not (car (symbol-value refs)))
- (setq heads (cdr (symbol-value refs)))
- (while heads
- (if (memq (mail-header-number (caar heads))
- gnus-newsgroup-dormant)
- (setq heads (cdr heads))
- (setq id (symbol-name refs))
- (while (and (setq id (gnus-build-get-header id))
- (not (car (gnus-id-to-thread id)))))
- (setq heads nil)))))
- gnus-newsgroup-dependencies)))
- (defsubst gnus-remove-odd-characters (string)
- "Translate STRING into something that doesn't contain weird characters."
- (mm-subst-char-in-string
- ?\r ?\-
- (mm-subst-char-in-string ?\n ?\- string t) t))
- ;; This function has to be called with point after the article number
- ;; on the beginning of the line.
- (defsubst gnus-nov-parse-line (number dependencies &optional force-new)
- (let ((eol (point-at-eol))
- (buffer (current-buffer))
- header references in-reply-to)
- ;; overview: [num subject from date id refs chars lines misc]
- (unwind-protect
- (let (x)
- (narrow-to-region (point) eol)
- (unless (eobp)
- (forward-char))
- (setq header
- (make-full-mail-header
- number ; number
- (condition-case () ; subject
- (gnus-remove-odd-characters
- (funcall gnus-decode-encoded-word-function
- (setq x (nnheader-nov-field))))
- (error x))
- (condition-case () ; from
- (gnus-remove-odd-characters
- (funcall gnus-decode-encoded-address-function
- (setq x (nnheader-nov-field))))
- (error x))
- (nnheader-nov-field) ; date
- (nnheader-nov-read-message-id number) ; id
- (setq references (nnheader-nov-field)) ; refs
- (nnheader-nov-read-integer) ; chars
- (nnheader-nov-read-integer) ; lines
- (unless (eobp)
- (if (looking-at "Xref: ")
- (goto-char (match-end 0)))
- (nnheader-nov-field)) ; Xref
- (nnheader-nov-parse-extra)))) ; extra
- (widen))
- (when (and (string= references "")
- (setq in-reply-to (mail-header-extra header))
- (setq in-reply-to (cdr (assq 'In-Reply-To in-reply-to))))
- (mail-header-set-references
- header (gnus-extract-message-id-from-in-reply-to in-reply-to)))
- (when gnus-alter-header-function
- (funcall gnus-alter-header-function header))
- (gnus-dependencies-add-header header dependencies force-new)))
- (defun gnus-build-get-header (id)
- "Look through the buffer of NOV lines and find the header to ID.
- Enter this line into the dependencies hash table, and return
- the id of the parent article (if any)."
- (let ((deps gnus-newsgroup-dependencies)
- found header)
- (prog1
- (with-current-buffer nntp-server-buffer
- (let ((case-fold-search nil))
- (goto-char (point-min))
- (while (and (not found)
- (search-forward id nil t))
- (beginning-of-line)
- (setq found (looking-at
- (format "^[^\t]*\t[^\t]*\t[^\t]*\t[^\t]*\t%s"
- (regexp-quote id))))
- (or found (beginning-of-line 2)))
- (when found
- (beginning-of-line)
- (and
- (setq header (gnus-nov-parse-line
- (read (current-buffer)) deps))
- (gnus-parent-id (mail-header-references header))))))
- (when header
- (let ((number (mail-header-number header)))
- (push number gnus-newsgroup-limit)
- (push header gnus-newsgroup-headers)
- (if (memq number gnus-newsgroup-unselected)
- (progn
- (setq gnus-newsgroup-unreads
- (gnus-add-to-sorted-list gnus-newsgroup-unreads
- number))
- (setq gnus-newsgroup-unselected
- (delq number gnus-newsgroup-unselected)))
- (push number gnus-newsgroup-ancient)))))))
- (defun gnus-build-all-threads ()
- "Read all the headers."
- (let ((gnus-summary-ignore-duplicates t)
- (mail-parse-charset gnus-newsgroup-charset)
- (dependencies gnus-newsgroup-dependencies)
- header article)
- (with-current-buffer nntp-server-buffer
- (let ((case-fold-search nil))
- (goto-char (point-min))
- (while (not (eobp))
- (ignore-errors
- (setq article (read (current-buffer))
- header (gnus-nov-parse-line article dependencies t)))
- (when header
- (with-current-buffer gnus-summary-buffer
- (push header gnus-newsgroup-headers)
- (if (memq (setq article (mail-header-number header))
- gnus-newsgroup-unselected)
- (progn
- (setq gnus-newsgroup-unreads
- (gnus-add-to-sorted-list
- gnus-newsgroup-unreads article))
- (setq gnus-newsgroup-unselected
- (delq article gnus-newsgroup-unselected)))
- (push article gnus-newsgroup-ancient)))
- (forward-line 1)))))))
- (defun gnus-summary-update-article-line (article header)
- "Update the line for ARTICLE using HEADER."
- (let* ((id (mail-header-id header))
- (thread (gnus-id-to-thread id)))
- (unless thread
- (error "Article in no thread"))
- ;; Update the thread.
- (setcar thread header)
- (gnus-summary-goto-subject article)
- (let* ((datal (gnus-data-find-list article))
- (data (car datal))
- (inhibit-read-only t)
- (level (gnus-summary-thread-level)))
- (gnus-delete-line)
- (let ((inserted (- (point)
- (progn
- (gnus-summary-insert-line
- header level nil
- (memq article gnus-newsgroup-undownloaded)
- (gnus-article-mark article)
- (memq article gnus-newsgroup-replied)
- (memq article gnus-newsgroup-expirable)
- ;; Only insert the Subject string when it's different
- ;; from the previous Subject string.
- (if (and
- gnus-show-threads
- (gnus-subject-equal
- (condition-case ()
- (mail-header-subject
- (gnus-data-header
- (cadr
- (gnus-data-find-list
- article
- (gnus-data-list t)))))
- ;; Error on the side of excessive subjects.
- (error ""))
- (mail-header-subject header)))
- ""
- (mail-header-subject header))
- nil (cdr (assq article gnus-newsgroup-scored))
- (memq article gnus-newsgroup-processable))
- (point)))))
- (when (cdr datal)
- (gnus-data-update-list
- (cdr datal)
- (- (gnus-data-pos data) (gnus-data-pos (cadr datal)) inserted)))))))
- (defun gnus-summary-update-article (article &optional iheader)
- "Update ARTICLE in the summary buffer."
- (set-buffer gnus-summary-buffer)
- (let* ((header (gnus-summary-article-header article))
- (id (mail-header-id header))
- (data (gnus-data-find article))
- (thread (gnus-id-to-thread id))
- (references (mail-header-references header))
- (parent
- (gnus-id-to-thread
- (or (gnus-parent-id
- (when (and references
- (not (equal "" references)))
- references))
- "none")))
- (inhibit-read-only t)
- (old (car thread)))
- (when thread
- (unless iheader
- (setcar thread nil)
- (when parent
- (delq thread parent)))
- (if (gnus-summary-insert-subject id header)
- ;; Set the (possibly) new article number in the data structure.
- (gnus-data-set-number data (gnus-id-to-article id))
- (setcar thread old)
- nil))))
- (defun gnus-rebuild-thread (id &optional line)
- "Rebuild the thread containing ID.
- If LINE, insert the rebuilt thread starting on line LINE."
- (let ((inhibit-read-only t)
- old-pos current thread data)
- (if (not gnus-show-threads)
- (setq thread (list (car (gnus-id-to-thread id))))
- ;; Get the thread this article is part of.
- (setq thread (gnus-remove-thread id)))
- (setq old-pos (point-at-bol))
- (setq current (save-excursion
- (and (re-search-backward "[\r\n]" nil t)
- (gnus-summary-article-number))))
- ;; If this is a gathered thread, we have to go some re-gathering.
- (when (stringp (car thread))
- (let ((subject (car thread))
- roots thr)
- (setq thread (cdr thread))
- (while thread
- (unless (memq (setq thr (gnus-id-to-thread
- (gnus-root-id
- (mail-header-id (caar thread)))))
- roots)
- (push thr roots))
- (setq thread (cdr thread)))
- ;; We now have all (unique) roots.
- (if (= (length roots) 1)
- ;; All the loose roots are now one solid root.
- (setq thread (car roots))
- (setq thread (cons subject (gnus-sort-threads roots))))))
- (let (threads)
- ;; We then insert this thread into the summary buffer.
- (when line
- (goto-char (point-min))
- (forward-line (1- line)))
- (let (gnus-newsgroup-data gnus-newsgroup-threads)
- (if gnus-show-threads
- (gnus-summary-prepare-threads (gnus-cut-threads (list thread)))
- (gnus-summary-prepare-unthreaded thread))
- (setq data (nreverse gnus-newsgroup-data))
- (setq threads gnus-newsgroup-threads))
- ;; We splice the new data into the data structure.
- ;;!!! This is kinda bogus. We assume that in LINE is non-nil,
- ;;!!! then we want to insert at the beginning of the buffer.
- ;;!!! That happens to be true with Gnus now, but that may
- ;;!!! change in the future. Perhaps.
- (gnus-data-enter-list
- (if line nil current) data (- (point) old-pos))
- (setq gnus-newsgroup-threads
- (nconc threads gnus-newsgroup-threads))
- (gnus-data-compute-positions))))
- (defun gnus-number-to-header (number)
- "Return the header for article NUMBER."
- (let ((headers gnus-newsgroup-headers))
- (while (and headers
- (not (= number (mail-header-number (car headers)))))
- (pop headers))
- (when headers
- (car headers))))
- (defun gnus-parent-headers (in-headers &optional generation)
- "Return the headers of the GENERATIONth parent of HEADERS."
- (unless generation
- (setq generation 1))
- (let ((parent t)
- (headers in-headers)
- references)
- (while (and parent
- (not (zerop generation))
- (setq references (mail-header-references headers)))
- (setq headers (if (and references
- (setq parent (gnus-parent-id references)))
- (car (gnus-id-to-thread parent))
- nil))
- (decf generation))
- (and (not (eq headers in-headers))
- headers)))
- (defun gnus-id-to-thread (id)
- "Return the (sub-)thread where ID appears."
- (gnus-gethash id gnus-newsgroup-dependencies))
- (defun gnus-id-to-article (id)
- "Return the article number of ID."
- (let ((thread (gnus-id-to-thread id)))
- (when (and thread
- (car thread))
- (mail-header-number (car thread)))))
- (defun gnus-id-to-header (id)
- "Return the article headers of ID."
- (car (gnus-id-to-thread id)))
- (defun gnus-article-displayed-root-p (article)
- "Say whether ARTICLE is a root(ish) article."
- (let ((level (gnus-summary-thread-level article))
- (refs (mail-header-references (gnus-summary-article-header article)))
- particle)
- (cond
- ((null level) nil)
- ((zerop level) t)
- ((null refs) t)
- ((null (gnus-parent-id refs)) t)
- ((and (= 1 level)
- (null (setq particle (gnus-id-to-article
- (gnus-parent-id refs))))
- (null (gnus-summary-thread-level particle)))))))
- (defun gnus-root-id (id)
- "Return the id of the root of the thread where ID appears."
- (let (last-id prev)
- (while (and id (setq prev (car (gnus-id-to-thread id))))
- (setq last-id id
- id (gnus-parent-id (mail-header-references prev))))
- last-id))
- (defun gnus-articles-in-thread (thread)
- "Return the list of articles in THREAD."
- (cons (mail-header-number (car thread))
- (apply 'nconc (mapcar 'gnus-articles-in-thread (cdr thread)))))
- (defun gnus-remove-thread (id &optional dont-remove)
- "Remove the thread that has ID in it."
- (let (headers thread last-id)
- ;; First go up in this thread until we find the root.
- (setq last-id (gnus-root-id id)
- headers (message-flatten-list (gnus-id-to-thread last-id)))
- ;; We have now found the real root of this thread. It might have
- ;; been gathered into some loose thread, so we have to search
- ;; through the threads to find the thread we wanted.
- (let ((threads gnus-newsgroup-threads)
- sub)
- (while threads
- (setq sub (car threads))
- (if (stringp (car sub))
- ;; This is a gathered thread, so we look at the roots
- ;; below it to find whether this article is in this
- ;; gathered root.
- (progn
- (setq sub (cdr sub))
- (while sub
- (when (member (caar sub) headers)
- (setq thread (car threads)
- threads nil
- sub nil))
- (setq sub (cdr sub))))
- ;; It's an ordinary thread, so we check it.
- (when (eq (car sub) (car headers))
- (setq thread sub
- threads nil)))
- (setq threads (cdr threads)))
- ;; If this article is in no thread, then it's a root.
- (if thread
- (unless dont-remove
- (setq gnus-newsgroup-threads (delq thread gnus-newsgroup-threads)))
- (setq thread (gnus-id-to-thread last-id)))
- (when thread
- (prog1
- thread ; We return this thread.
- (unless dont-remove
- (if (stringp (car thread))
- (progn
- ;; If we use dummy roots, then we have to remove the
- ;; dummy root as well.
- (when (eq gnus-summary-make-false-root 'dummy)
- ;; We go to the dummy root by going to
- ;; the first sub-"thread", and then one line up.
- (gnus-summary-goto-article
- (mail-header-number (caadr thread)))
- (forward-line -1)
- (gnus-delete-line)
- (gnus-data-compute-positions))
- (setq thread (cdr thread))
- (while thread
- (gnus-remove-thread-1 (car thread))
- (setq thread (cdr thread))))
- (gnus-remove-thread-1 thread))))))))
- (defun gnus-remove-thread-1 (thread)
- "Remove the thread THREAD recursively."
- (let ((number (mail-header-number (pop thread)))
- d)
- (setq thread (reverse thread))
- (while thread
- (gnus-remove-thread-1 (pop thread)))
- (when (setq d (gnus-data-find number))
- (goto-char (gnus-data-pos d))
- (gnus-summary-show-thread)
- (gnus-data-remove
- number
- (- (point-at-bol)
- (prog1
- (1+ (point-at-eol))
- (gnus-delete-line)))))))
- (defun gnus-sort-threads-recursive (threads func)
- ;; Responsible for sorting the root articles of threads.
- (let ((subthread-sort-func (if (eq gnus-subthread-sort-functions
- 'gnus-thread-sort-functions)
- func
- (gnus-make-sort-function
- gnus-subthread-sort-functions))))
- (sort (mapcar (lambda (thread)
- (cons (car thread)
- (and (cdr thread)
- (gnus-sort-subthreads-recursive
- (cdr thread) subthread-sort-func))))
- threads) func)))
- (defun gnus-sort-subthreads-recursive (threads func)
- ;; Responsible for sorting subthreads.
- (sort (mapcar (lambda (thread)
- (cons (car thread)
- (and (cdr thread)
- (gnus-sort-subthreads-recursive (cdr thread) func))))
- threads) func))
- (defun gnus-sort-threads-loop (threads func)
- (let* ((superthread (cons nil threads))
- (stack (list (cons superthread threads)))
- remaining-threads thread)
- (while stack
- (setq remaining-threads (cdr (car stack)))
- (if remaining-threads
- (progn (setq thread (car remaining-threads))
- (setcdr (car stack) (cdr remaining-threads))
- (if (cdr thread)
- (push (cons thread (cdr thread)) stack)))
- (setq thread (caar stack))
- (setcdr thread (sort (cdr thread) func))
- (pop stack)))
- (cdr superthread)))
- (defun gnus-sort-threads (threads)
- "Sort THREADS."
- (if (not gnus-thread-sort-functions)
- threads
- (gnus-message 8 "Sorting threads...")
- (prog1
- (condition-case nil
- (let ((max-lisp-eval-depth (max max-lisp-eval-depth 5000))
- (sort-func (gnus-make-sort-function gnus-thread-sort-functions)))
- (gnus-sort-threads-recursive threads sort-func))
- ;; Even after binding max-lisp-eval-depth, the recursive
- ;; sorter might fail for very long threads. In that case,
- ;; try using a (less well-tested) non-recursive sorter.
- (error (gnus-message 9 "Sorting threads with loop...")
- (gnus-sort-threads-loop
- threads (gnus-make-sort-function
- gnus-thread-sort-functions))))
- (gnus-message 8 "Sorting threads...done"))))
- (defun gnus-sort-articles (articles)
- "Sort ARTICLES."
- (when gnus-article-sort-functions
- (gnus-message 7 "Sorting articles...")
- (prog1
- (setq gnus-newsgroup-headers
- (sort articles (gnus-make-sort-function
- gnus-article-sort-functions)))
- (gnus-message 7 "Sorting articles...done"))))
- ;; Written by Hallvard B Furuseth <h.b.furuseth@usit.uio.no>.
- (defmacro gnus-thread-header (thread)
- "Return header of first article in THREAD.
- Note that THREAD must never, ever be anything else than a variable -
- using some other form will lead to serious barfage."
- (or (symbolp thread) (signal 'wrong-type-argument '(symbolp thread)))
- ;; (8% speedup to gnus-summary-prepare, just for fun :-)
- (list 'byte-code "\10\211:\203\17\0\211@;\203\16\0A@@\207"
- (vector thread) 2))
- (defsubst gnus-article-sort-by-number (h1 h2)
- "Sort articles by article number."
- (< (mail-header-number h1)
- (mail-header-number h2)))
- (defun gnus-thread-sort-by-number (h1 h2)
- "Sort threads by root article number."
- (gnus-article-sort-by-number
- (gnus-thread-header h1) (gnus-thread-header h2)))
- (defsubst gnus-article-sort-by-random (h1 h2)
- "Sort articles randomly."
- (zerop (random 2)))
- (defun gnus-thread-sort-by-random (h1 h2)
- "Sort threads randomly."
- (gnus-article-sort-by-random
- (gnus-thread-header h1) (gnus-thread-header h2)))
- (defsubst gnus-article-sort-by-lines (h1 h2)
- "Sort articles by article Lines header."
- (< (mail-header-lines h1)
- (mail-header-lines h2)))
- (defun gnus-thread-sort-by-lines (h1 h2)
- "Sort threads by root article Lines header."
- (gnus-article-sort-by-lines
- (gnus-thread-header h1) (gnus-thread-header h2)))
- (defsubst gnus-article-sort-by-chars (h1 h2)
- "Sort articles by octet length."
- (< (mail-header-chars h1)
- (mail-header-chars h2)))
- (defun gnus-thread-sort-by-chars (h1 h2)
- "Sort threads by root article octet length."
- (gnus-article-sort-by-chars
- (gnus-thread-header h1) (gnus-thread-header h2)))
- (defsubst gnus-article-sort-by-author (h1 h2)
- "Sort articles by root author."
- (gnus-string<
- (let ((extract (funcall
- gnus-extract-address-components
- (mail-header-from h1))))
- (or (car extract) (cadr extract) ""))
- (let ((extract (funcall
- gnus-extract-address-components
- (mail-header-from h2))))
- (or (car extract) (cadr extract) ""))))
- (defun gnus-thread-sort-by-author (h1 h2)
- "Sort threads by root author."
- (gnus-article-sort-by-author
- (gnus-thread-header h1) (gnus-thread-header h2)))
- (defsubst gnus-article-sort-by-recipient (h1 h2)
- "Sort articles by recipient."
- (gnus-string<
- (let ((extract (funcall
- gnus-extract-address-components
- (or (cdr (assq 'To (mail-header-extra h1))) ""))))
- (or (car extract) (cadr extract)))
- (let ((extract (funcall
- gnus-extract-address-components
- (or (cdr (assq 'To (mail-header-extra h2))) ""))))
- (or (car extract) (cadr extract)))))
- (defun gnus-thread-sort-by-recipient (h1 h2)
- "Sort threads by root recipient."
- (gnus-article-sort-by-recipient
- (gnus-thread-header h1) (gnus-thread-header h2)))
- (defsubst gnus-article-sort-by-subject (h1 h2)
- "Sort articles by root subject."
- (gnus-string<
- (downcase (gnus-simplify-subject-re (mail-header-subject h1)))
- (downcase (gnus-simplify-subject-re (mail-header-subject h2)))))
- (defun gnus-thread-sort-by-subject (h1 h2)
- "Sort threads by root subject."
- (gnus-article-sort-by-subject
- (gnus-thread-header h1) (gnus-thread-header h2)))
- (defsubst gnus-article-sort-by-date (h1 h2)
- "Sort articles by root article date."
- (time-less-p
- (gnus-date-get-time (mail-header-date h1))
- (gnus-date-get-time (mail-header-date h2))))
- (defun gnus-thread-sort-by-date (h1 h2)
- "Sort threads by root article date."
- (gnus-article-sort-by-date
- (gnus-thread-header h1) (gnus-thread-header h2)))
- (defsubst gnus-article-sort-by-score (h1 h2)
- "Sort articles by root article score.
- Unscored articles will be counted as having a score of zero."
- (> (or (cdr (assq (mail-header-number h1)
- gnus-newsgroup-scored))
- gnus-summary-default-score 0)
- (or (cdr (assq (mail-header-number h2)
- gnus-newsgroup-scored))
- gnus-summary-default-score 0)))
- (defun gnus-thread-sort-by-score (h1 h2)
- "Sort threads by root article score."
- (gnus-article-sort-by-score
- (gnus-thread-header h1) (gnus-thread-header h2)))
- (defun gnus-thread-sort-by-total-score (h1 h2)
- "Sort threads by the sum of all scores in the thread.
- Unscored articles will be counted as having a score of zero."
- (> (gnus-thread-total-score h1) (gnus-thread-total-score h2)))
- (defun gnus-thread-total-score (thread)
- ;; This function find the total score of THREAD.
- (cond
- ((null thread)
- 0)
- ((consp thread)
- (if (stringp (car thread))
- (apply gnus-thread-score-function 0
- (mapcar 'gnus-thread-total-score-1 (cdr thread)))
- (gnus-thread-total-score-1 thread)))
- (t
- (gnus-thread-total-score-1 (list thread)))))
- (defun gnus-article-sort-by-most-recent-number (h1 h2)
- "Sort articles by number."
- (gnus-article-sort-by-number h1 h2))
- (defun gnus-thread-sort-by-most-recent-number (h1 h2)
- "Sort threads such that the thread with the most recently arrived article comes first."
- (> (gnus-thread-highest-number h1) (gnus-thread-highest-number h2)))
- (defun gnus-thread-highest-number (thread)
- "Return the highest article number in THREAD."
- (apply 'max (mapcar (lambda (header)
- (mail-header-number header))
- (message-flatten-list thread))))
- (defun gnus-article-sort-by-most-recent-date (h1 h2)
- "Sort articles by number."
- (gnus-article-sort-by-date h1 h2))
- (defun gnus-thread-sort-by-most-recent-date (h1 h2)
- "Sort threads such that the thread with the most recently dated article comes first."
- (> (gnus-thread-latest-date h1) (gnus-thread-latest-date h2)))
- ; Since this is called not only to sort the top-level threads, but
- ; also in recursive sorts to order the articles within a thread, each
- ; article will be processed many times. Thus it speeds things up
- ; quite a bit to use gnus-date-get-time, which caches the time value.
- (defun gnus-thread-latest-date (thread)
- "Return the highest article date in THREAD."
- (apply 'max
- (mapcar (lambda (header) (gnus-float-time
- (gnus-date-get-time
- (mail-header-date header))))
- (message-flatten-list thread))))
- (defun gnus-thread-total-score-1 (root)
- ;; This function find the total score of the thread below ROOT.
- (setq root (car root))
- (apply gnus-thread-score-function
- (or (append
- (mapcar 'gnus-thread-total-score
- (cdr (gnus-id-to-thread (mail-header-id root))))
- (when (> (mail-header-number root) 0)
- (list (or (cdr (assq (mail-header-number root)
- gnus-newsgroup-scored))
- gnus-summary-default-score 0))))
- (list gnus-summary-default-score)
- '(0))))
- ;; Added by Per Abrahamsen <amanda@iesd.auc.dk>.
- (defvar gnus-tmp-prev-subject nil)
- (defvar gnus-tmp-false-parent nil)
- (defvar gnus-tmp-root-expunged nil)
- (defvar gnus-tmp-dummy-line nil)
- (defun gnus-extra-header (type &optional header)
- "Return the extra header of TYPE."
- (or (cdr (assq type (mail-header-extra (or header gnus-tmp-header))))
- ""))
- (defvar gnus-tmp-thread-tree-header-string "")
- (defcustom gnus-sum-thread-tree-root "> "
- "With %B spec, used for the root of a thread.
- If nil, use subject instead."
- :version "22.1"
- :type '(radio (const :format "%v " nil) string)
- :group 'gnus-thread)
- (defcustom gnus-sum-thread-tree-false-root "> "
- "With %B spec, used for a false root of a thread.
- If nil, use subject instead."
- :version "22.1"
- :type '(radio (const :format "%v " nil) string)
- :group 'gnus-thread)
- (defcustom gnus-sum-thread-tree-single-indent ""
- "With %B spec, used for a thread with just one message.
- If nil, use subject instead."
- :version "22.1"
- :type '(radio (const :format "%v " nil) string)
- :group 'gnus-thread)
- (defcustom gnus-sum-thread-tree-vertical "| "
- "With %B spec, used for drawing a vertical line."
- :version "22.1"
- :type 'string
- :group 'gnus-thread)
- (defcustom gnus-sum-thread-tree-indent " "
- "With %B spec, used for indenting."
- :version "22.1"
- :type 'string
- :group 'gnus-thread)
- (defcustom gnus-sum-thread-tree-leaf-with-other "+-> "
- "With %B spec, used for a leaf with brothers."
- :version "22.1"
- :type 'string
- :group 'gnus-thread)
- (defcustom gnus-sum-thread-tree-single-leaf "\\-> "
- "With %B spec, used for a leaf without brothers."
- :version "22.1"
- :type 'string
- :group 'gnus-thread)
- (defcustom gnus-summary-display-while-building nil
- "If non-nil, show and update the summary buffer as it's being built.
- If the value is t, update the buffer after every line is inserted. If
- the value is an integer (N), update the display every N lines."
- :version "22.1"
- :group 'gnus-thread
- :type '(choice (const :tag "off" nil)
- number
- (const :tag "frequently" t)))
- (defun gnus-summary-prepare-threads (threads)
- "Prepare summary buffer from THREADS and indentation LEVEL.
- THREADS is either a list of `(PARENT [(CHILD1 [(GRANDCHILD ...]...) ...])'
- or a straight list of headers."
- (gnus-message 7 "Generating summary...")
- (setq gnus-newsgroup-threads threads)
- (beginning-of-line)
- (let ((gnus-tmp-level 0)
- (default-score (or gnus-summary-default-score 0))
- (gnus-visual-p (gnus-visual-p 'summary-highlight 'highlight))
- (building-line-count gnus-summary-display-while-building)
- (building-count (integerp gnus-summary-display-while-building))
- thread number subject stack state gnus-tmp-gathered beg-match
- new-roots gnus-tmp-new-adopts thread-end simp-subject
- gnus-tmp-header gnus-tmp-unread gnus-tmp-downloaded
- gnus-tmp-replied gnus-tmp-subject-or-nil
- gnus-tmp-dummy gnus-tmp-indentation gnus-tmp-lines gnus-tmp-score
- gnus-tmp-score-char gnus-tmp-from gnus-tmp-name
- gnus-tmp-number gnus-tmp-opening-bracket gnus-tmp-closing-bracket
- tree-stack)
- (setq gnus-tmp-prev-subject nil
- gnus-tmp-thread-tree-header-string "")
- (if (vectorp (car threads))
- ;; If this is a straight (sic) list of headers, then a
- ;; threaded summary display isn't required, so we just create
- ;; an unthreaded one.
- (gnus-summary-prepare-unthreaded threads)
- ;; Do the threaded display.
- (if gnus-summary-display-while-building
- (switch-to-buffer (buffer-name)))
- (while (or threads stack gnus-tmp-new-adopts new-roots)
- (if (and (= gnus-tmp-level 0)
- (or (not stack)
- (= (caar stack) 0))
- (not gnus-tmp-false-parent)
- (or gnus-tmp-new-adopts new-roots))
- (if gnus-tmp-new-adopts
- (setq gnus-tmp-level (if gnus-tmp-root-expunged 0 1)
- thread (list (car gnus-tmp-new-adopts))
- gnus-tmp-header (caar thread)
- gnus-tmp-new-adopts (cdr gnus-tmp-new-adopts))
- (when new-roots
- (setq thread (list (car new-roots))
- gnus-tmp-header (caar thread)
- new-roots (cdr new-roots))))
- (if threads
- ;; If there are some threads, we do them before the
- ;; threads on the stack.
- (setq thread threads
- gnus-tmp-header (caar thread))
- ;; There were no current threads, so we pop something off
- ;; the stack.
- (setq state (car stack)
- gnus-tmp-level (car state)
- tree-stack (cadr state)
- thread (caddr state)
- stack (cdr stack)
- gnus-tmp-header (caar thread))))
- (setq gnus-tmp-false-parent nil)
- (setq gnus-tmp-root-expunged nil)
- (setq thread-end nil)
- (if (stringp gnus-tmp-header)
- ;; The header is a dummy root.
- (cond
- ((eq gnus-summary-make-false-root 'adopt)
- ;; We let the first article adopt the rest.
- (setq gnus-tmp-new-adopts (nconc gnus-tmp-new-adopts
- (cddar thread)))
- (setq gnus-tmp-gathered
- (nconc (mapcar
- (lambda (h) (mail-header-number (car h)))
- (cddar thread))
- gnus-tmp-gathered))
- (setq thread (cons (list (caar thread)
- (cadar thread))
- (cdr thread)))
- (setq gnus-tmp-level -1
- gnus-tmp-false-parent t))
- ((eq gnus-summary-make-false-root 'empty)
- ;; We print adopted articles with empty subject fields.
- (setq gnus-tmp-gathered
- (nconc (mapcar
- (lambda (h) (mail-header-number (car h)))
- (cddar thread))
- gnus-tmp-gathered))
- (setq gnus-tmp-level -1))
- ((eq gnus-summary-make-false-root 'dummy)
- ;; We remember that we probably want to output a dummy
- ;; root.
- (setq gnus-tmp-dummy-line gnus-tmp-header)
- (setq gnus-tmp-prev-subject gnus-tmp-header))
- (t
- ;; We do not make a root for the gathered
- ;; sub-threads at all.
- (setq gnus-tmp-level -1)))
- (setq number (mail-header-number gnus-tmp-header)
- subject (mail-header-subject gnus-tmp-header)
- simp-subject (gnus-simplify-subject-fully subject))
- (cond
- ;; If the thread has changed subject, we might want to make
- ;; this subthread into a root.
- ((and (null gnus-thread-ignore-subject)
- (not (zerop gnus-tmp-level))
- gnus-tmp-prev-subject
- (not (string= gnus-tmp-prev-subject simp-subject)))
- (setq new-roots (nconc new-roots (list (car thread)))
- thread-end t
- gnus-tmp-header nil))
- ;; If the article lies outside the current limit,
- ;; then we do not display it.
- ((not (memq number gnus-newsgroup-limit))
- (setq gnus-tmp-gathered
- (nconc (mapcar
- (lambda (h) (mail-header-number (car h)))
- (cdar thread))
- gnus-tmp-gathered))
- (setq gnus-tmp-new-adopts (if (cdar thread)
- (append gnus-tmp-new-adopts
- (cdar thread))
- gnus-tmp-new-adopts)
- thread-end t
- gnus-tmp-header nil)
- (when (zerop gnus-tmp-level)
- (setq gnus-tmp-root-expunged t)))
- ;; Perhaps this article is to be marked as read?
- ((and gnus-summary-mark-below
- (< (or (cdr (assq number gnus-newsgroup-scored))
- default-score)
- gnus-summary-mark-below)
- ;; Don't touch sparse articles.
- (not (gnus-summary-article-sparse-p number))
- (not (gnus-summary-article-ancient-p number)))
- (setq gnus-newsgroup-unreads
- (delq number gnus-newsgroup-unreads))
- (if gnus-newsgroup-auto-expire
- (setq gnus-newsgroup-expirable
- (gnus-add-to-sorted-list
- gnus-newsgroup-expirable number))
- (push (cons number gnus-low-score-mark)
- gnus-newsgroup-reads))))
- (when gnus-tmp-header
- ;; We may have an old dummy line to output before this
- ;; article.
- (when (and gnus-tmp-dummy-line
- (gnus-subject-equal
- gnus-tmp-dummy-line
- (mail-header-subject gnus-tmp-header)))
- (gnus-summary-insert-dummy-line
- gnus-tmp-dummy-line (mail-header-number gnus-tmp-header))
- (setq gnus-tmp-dummy-line nil))
- ;; Compute the mark.
- (setq gnus-tmp-unread (gnus-article-mark number))
- (push (gnus-data-make number gnus-tmp-unread (1+ (point))
- gnus-tmp-header gnus-tmp-level)
- gnus-newsgroup-data)
- ;; Actually insert the line.
- (setq
- gnus-tmp-subject-or-nil
- (cond
- ((and gnus-thread-ignore-subject
- gnus-tmp-prev-subject
- (not (string= gnus-tmp-prev-subject simp-subject)))
- subject)
- ((zerop gnus-tmp-level)
- (if (and (eq gnus-summary-make-false-root 'empty)
- (memq number gnus-tmp-gathered)
- gnus-tmp-prev-subject
- (string= gnus-tmp-prev-subject simp-subject))
- gnus-summary-same-subject
- subject))
- (t gnus-summary-same-subject)))
- (if (and (eq gnus-summary-make-false-root 'adopt)
- (= gnus-tmp-level 1)
- (memq number gnus-tmp-gathered))
- (setq gnus-tmp-opening-bracket ?\<
- gnus-tmp-closing-bracket ?\>)
- (setq gnus-tmp-opening-bracket ?\[
- gnus-tmp-closing-bracket ?\]))
- (if (>= gnus-tmp-level (length gnus-thread-indent-array))
- (gnus-make-thread-indent-array
- (max (* 2 (length gnus-thread-indent-array))
- gnus-tmp-level)))
- (setq
- gnus-tmp-indentation
- (aref gnus-thread-indent-array gnus-tmp-level)
- gnus-tmp-lines (mail-header-lines gnus-tmp-header)
- gnus-tmp-score (or (cdr (assq number gnus-newsgroup-scored))
- gnus-summary-default-score 0)
- gnus-tmp-score-char
- (if (or (null gnus-summary-default-score)
- (<= (abs (- gnus-tmp-score gnus-summary-default-score))
- gnus-summary-zcore-fuzz))
- ? ;Whitespace
- (if (< gnus-tmp-score gnus-summary-default-score)
- gnus-score-below-mark gnus-score-over-mark))
- gnus-tmp-replied
- (cond ((memq number gnus-newsgroup-processable)
- gnus-process-mark)
- ((memq number gnus-newsgroup-cached)
- gnus-cached-mark)
- ((memq number gnus-newsgroup-replied)
- gnus-replied-mark)
- ((memq number gnus-newsgroup-forwarded)
- gnus-forwarded-mark)
- ((memq number gnus-newsgroup-saved)
- gnus-saved-mark)
- ((memq number gnus-newsgroup-unseen)
- gnus-unseen-mark)
- (t gnus-no-mark))
- gnus-tmp-downloaded
- (cond ((memq number gnus-newsgroup-undownloaded)
- gnus-undownloaded-mark)
- (gnus-newsgroup-agentized
- gnus-downloaded-mark)
- (t
- gnus-no-mark))
- gnus-tmp-from (mail-header-from gnus-tmp-header)
- gnus-tmp-name
- (cond
- ((string-match "<[^>]+> *$" gnus-tmp-from)
- (setq beg-match (match-beginning 0))
- (or (and (string-match "^\".+\"" gnus-tmp-from)
- (substring gnus-tmp-from 1 (1- (match-end 0))))
- (substring gnus-tmp-from 0 beg-match)))
- ((string-match "(.+)" gnus-tmp-from)
- (substring gnus-tmp-from
- (1+ (match-beginning 0)) (1- (match-end 0))))
- (t gnus-tmp-from))
- ;; Do the %B string
- gnus-tmp-thread-tree-header-string
- (cond
- ((not gnus-show-threads) "")
- ((zerop gnus-tmp-level)
- (cond ((cdar thread)
- (or gnus-sum-thread-tree-root subject))
- (gnus-tmp-new-adopts
- (or gnus-sum-thread-tree-false-root subject))
- (t
- (or gnus-sum-thread-tree-single-indent subject))))
- (t
- (concat (apply 'concat
- (mapcar (lambda (item)
- (if (= item 1)
- gnus-sum-thread-tree-vertical
- gnus-sum-thread-tree-indent))
- (cdr (reverse tree-stack))))
- (if (nth 1 thread)
- gnus-sum-thread-tree-leaf-with-other
- gnus-sum-thread-tree-single-leaf)))))
- (when (string= gnus-tmp-name "")
- (setq gnus-tmp-name gnus-tmp-from))
- (unless (numberp gnus-tmp-lines)
- (setq gnus-tmp-lines -1))
- (if (= gnus-tmp-lines -1)
- (setq gnus-tmp-lines "?")
- (setq gnus-tmp-lines (number-to-string gnus-tmp-lines)))
- (gnus-put-text-property
- (point)
- (progn (eval gnus-summary-line-format-spec) (point))
- 'gnus-number number)
- (when gnus-visual-p
- (forward-line -1)
- (gnus-summary-highlight-line)
- (when gnus-summary-update-hook
- (gnus-run-hooks 'gnus-summary-update-hook))
- (forward-line 1))
- (setq gnus-tmp-prev-subject simp-subject)))
- (when (nth 1 thread)
- (push (list (max 0 gnus-tmp-level)
- (copy-sequence tree-stack)
- (nthcdr 1 thread))
- stack))
- (push (if (nth 1 thread) 1 0) tree-stack)
- (incf gnus-tmp-level)
- (setq threads (if thread-end nil (cdar thread)))
- (if gnus-summary-display-while-building
- (if building-count
- (progn
- ;; use a set frequency
- (setq building-line-count (1- building-line-count))
- (when (= building-line-count 0)
- (sit-for 0)
- (setq building-line-count
- gnus-summary-display-while-building)))
- ;; always
- (sit-for 0)))
- (unless threads
- (setq gnus-tmp-level 0)))))
- (gnus-message 7 "Generating summary...done"))
- (defun gnus-summary-prepare-unthreaded (headers)
- "Generate an unthreaded summary buffer based on HEADERS."
- (let (header number mark)
- (beginning-of-line)
- (while headers
- ;; We may have to root out some bad articles...
- (when (memq (setq number (mail-header-number
- (setq header (pop headers))))
- gnus-newsgroup-limit)
- ;; Mark article as read when it has a low score.
- (when (and gnus-summary-mark-below
- (< (or (cdr (assq number gnus-newsgroup-scored))
- gnus-summary-default-score 0)
- gnus-summary-mark-below)
- (not (gnus-summary-article-ancient-p number)))
- (setq gnus-newsgroup-unreads
- (delq number gnus-newsgroup-unreads))
- (if gnus-newsgroup-auto-expire
- (push number gnus-newsgroup-expirable)
- (push (cons number gnus-low-score-mark)
- gnus-newsgroup-reads)))
- (setq mark (gnus-article-mark number))
- (push (gnus-data-make number mark (1+ (point)) header 0)
- gnus-newsgroup-data)
- (gnus-summary-insert-line
- header 0 number
- (memq number gnus-newsgroup-undownloaded)
- mark (memq number gnus-newsgroup-replied)
- (memq number gnus-newsgroup-expirable)
- (mail-header-subject header) nil
- (cdr (assq number gnus-newsgroup-scored))
- (memq number gnus-newsgroup-processable))))))
- (declare-function gnus-parameter-list-identifier "gnus-art" (name) t)
- (defun gnus-group-get-list-identifiers (group)
- "Get list identifier regexp for GROUP."
- (or (gnus-parameter-list-identifier group)
- (if (consp gnus-list-identifiers)
- (mapconcat 'identity gnus-list-identifiers " *\\|")
- gnus-list-identifiers)))
- (defun gnus-summary-remove-list-identifiers ()
- "Remove list identifiers in `gnus-list-identifiers' from articles in the current group."
- (let ((regexp (gnus-group-get-list-identifiers gnus-newsgroup-name))
- changed subject)
- (when regexp
- (setq regexp (concat "^\\(?:R[Ee]: +\\)*\\(" regexp " *\\)"))
- (dolist (header gnus-newsgroup-headers)
- (setq subject (mail-header-subject header)
- changed nil)
- (while (string-match regexp subject)
- (setq subject
- (concat (substring subject 0 (match-beginning 1))
- (substring subject (match-end 0)))
- changed t))
- (when changed
- (when (string-match "^\\(\\(?:R[Ee]: +\\)+\\)R[Ee]: +" subject)
- (setq subject
- (concat (substring subject 0 (match-beginning 1))
- (substring subject (match-end 1)))))
- (mail-header-set-subject header subject))))))
- (defun gnus-fetch-headers (articles &optional limit force-new dependencies)
- "Fetch headers of ARTICLES."
- (let ((name (gnus-group-decoded-name gnus-newsgroup-name)))
- (gnus-message 7 "Fetching headers for %s..." name)
- (prog1
- (if (eq 'nov
- (setq gnus-headers-retrieved-by
- (gnus-retrieve-headers
- articles gnus-newsgroup-name
- (or limit
- ;; We might want to fetch old headers, but
- ;; not if there is only 1 article.
- (and (or (and
- (not (eq gnus-fetch-old-headers 'some))
- (not (numberp gnus-fetch-old-headers)))
- (> (length articles) 1))
- gnus-fetch-old-headers)))))
- (gnus-get-newsgroup-headers-xover
- articles force-new dependencies gnus-newsgroup-name t)
- (gnus-get-newsgroup-headers dependencies force-new))
- (gnus-message 7 "Fetching headers for %s...done" name))))
- (defun gnus-select-newsgroup (group &optional read-all select-articles)
- "Select newsgroup GROUP.
- If READ-ALL is non-nil, all articles in the group are selected.
- If SELECT-ARTICLES, only select those articles from GROUP."
- (let* ((entry (gnus-group-entry group))
- ;;!!! Dirty hack; should be removed.
- (gnus-summary-ignore-duplicates
- (if (eq (car (gnus-find-method-for-group group)) 'nnvirtual)
- t
- gnus-summary-ignore-duplicates))
- (info (nth 2 entry))
- charset articles fetched-articles cached)
- (unless (gnus-check-server
- (set (make-local-variable 'gnus-current-select-method)
- (gnus-find-method-for-group group)))
- (error "Couldn't open server"))
- (setq charset (gnus-group-name-charset gnus-current-select-method group))
- (or (and entry (not (eq (car entry) t))) ; Either it's active...
- (gnus-activate-group group) ; Or we can activate it...
- (progn ; Or we bug out.
- (when (derived-mode-p 'gnus-summary-mode)
- (gnus-kill-buffer (current-buffer)))
- (error
- "Couldn't activate group %s: %s"
- (mm-decode-coding-string group charset)
- (mm-decode-coding-string (gnus-status-message group) charset))))
- (unless (gnus-request-group group t nil (gnus-get-info group))
- (when (derived-mode-p 'gnus-summary-mode)
- (gnus-kill-buffer (current-buffer)))
- (error "Couldn't request group %s: %s"
- (mm-decode-coding-string group charset)
- (mm-decode-coding-string (gnus-status-message group) charset)))
- (when (and gnus-agent
- (gnus-active group))
- (gnus-agent-possibly-alter-active group (gnus-active group) info)
- (setq gnus-summary-use-undownloaded-faces
- (gnus-agent-find-parameter
- group
- 'agent-enable-undownloaded-faces)))
- (setq gnus-newsgroup-name group
- gnus-newsgroup-unselected nil
- gnus-newsgroup-unreads (gnus-list-of-unread-articles group))
- (let ((display (gnus-group-find-parameter group 'display)))
- (setq gnus-newsgroup-display
- (cond
- ((not (zerop (or (car-safe read-all) 0)))
- ;; The user entered the group with C-u SPC/RET, let's show
- ;; all articles.
- 'gnus-not-ignore)
- ((eq display 'all)
- 'gnus-not-ignore)
- ((arrayp display)
- (gnus-summary-display-make-predicate (mapcar 'identity display)))
- ((numberp display)
- ;; The following is probably the "correct" solution, but
- ;; it makes Gnus fetch all headers and then limit the
- ;; articles (which is slow), so instead we hack the
- ;; select-articles parameter instead. -- Simon Josefsson
- ;; <jas@kth.se>
- ;;
- ;; (gnus-byte-compile
- ;; `(lambda () (> number ,(- (cdr (gnus-active group))
- ;; display)))))
- (setq select-articles
- (gnus-uncompress-range
- (cons (let ((tmp (- (cdr (gnus-active group)) display)))
- (if (> tmp 0)
- tmp
- 1))
- (cdr (gnus-active group)))))
- nil)
- (t
- nil))))
- (gnus-summary-setup-default-charset)
- ;; Kludge to avoid having cached articles nixed out in virtual groups.
- (when (gnus-virtual-group-p group)
- (setq cached gnus-newsgroup-cached))
- (setq gnus-newsgroup-unreads
- (gnus-sorted-ndifference
- (gnus-sorted-ndifference gnus-newsgroup-unreads
- gnus-newsgroup-marked)
- gnus-newsgroup-dormant))
- (setq gnus-newsgroup-processable nil)
- (gnus-update-read-articles group gnus-newsgroup-unreads t)
- ;; Adjust and set lists of article marks.
- (when info
- (gnus-adjust-marked-articles info))
- (if (setq articles select-articles)
- (setq gnus-newsgroup-unselected
- (gnus-sorted-difference gnus-newsgroup-unreads articles))
- (setq articles (gnus-articles-to-read group read-all)))
- (cond
- ((null articles)
- ;;(gnus-message 3 "Couldn't select newsgroup -- no articles to display")
- 'quit)
- ((eq articles 0) nil)
- (t
- ;; Init the dependencies hash table.
- (setq gnus-newsgroup-dependencies
- (gnus-make-hashtable (length articles)))
- (if (gnus-buffer-live-p gnus-group-buffer)
- (gnus-set-global-variables)
- (set-default 'gnus-newsgroup-name gnus-newsgroup-name))
- ;; Retrieve the headers and read them in.
- (setq gnus-newsgroup-headers (gnus-fetch-headers articles))
- ;; Kludge to avoid having cached articles nixed out in virtual groups.
- (when cached
- (setq gnus-newsgroup-cached cached))
- ;; Suppress duplicates?
- (when gnus-suppress-duplicates
- (gnus-dup-suppress-articles))
- ;; Set the initial limit.
- (setq gnus-newsgroup-limit (copy-sequence articles))
- ;; Remove canceled articles from the list of unread articles.
- (setq fetched-articles
- (mapcar (lambda (headers) (mail-header-number headers))
- gnus-newsgroup-headers))
- (setq gnus-newsgroup-articles fetched-articles)
- (setq gnus-newsgroup-unreads
- (gnus-sorted-nintersection
- gnus-newsgroup-unreads fetched-articles))
- (gnus-compute-unseen-list)
- ;; Removed marked articles that do not exist.
- (gnus-update-missing-marks
- (gnus-sorted-difference articles fetched-articles))
- ;; We might want to build some more threads first.
- (when (and gnus-fetch-old-headers
- (eq gnus-headers-retrieved-by 'nov))
- (if (eq gnus-fetch-old-headers 'invisible)
- (gnus-build-all-threads)
- (gnus-build-old-threads)))
- ;; Let the Gnus agent mark articles as read.
- (when gnus-agent
- (gnus-agent-get-undownloaded-list))
- ;; Remove list identifiers from subject
- (gnus-summary-remove-list-identifiers)
- ;; Check whether auto-expire is to be done in this group.
- (setq gnus-newsgroup-auto-expire
- (and (gnus-group-auto-expirable-p group)
- (not (gnus-group-read-only-p group))))
- ;; Set up the article buffer now, if necessary.
- (unless (and gnus-single-article-buffer
- (equal gnus-article-buffer "*Article*"))
- (gnus-article-setup-buffer))
- ;; First and last article in this newsgroup.
- (when gnus-newsgroup-headers
- (setq gnus-newsgroup-begin
- (mail-header-number (car gnus-newsgroup-headers))
- gnus-newsgroup-end
- (mail-header-number
- (gnus-last-element gnus-newsgroup-headers))))
- ;; GROUP is successfully selected.
- (or gnus-newsgroup-headers t)))))
- (defun gnus-compute-unseen-list ()
- ;; The `seen' marks are treated specially.
- (if (not gnus-newsgroup-seen)
- (setq gnus-newsgroup-unseen gnus-newsgroup-articles)
- (setq gnus-newsgroup-unseen
- (gnus-inverse-list-range-intersection
- gnus-newsgroup-articles gnus-newsgroup-seen))))
- (declare-function gnus-get-predicate "gnus-agent" (predicate))
- (defun gnus-summary-display-make-predicate (display)
- (require 'gnus-agent)
- (when (= (length display) 1)
- (setq display (car display)))
- (unless gnus-summary-display-cache
- (dolist (elem (append '((unread . unread)
- (read . read)
- (unseen . unseen))
- gnus-article-mark-lists))
- (push (cons (cdr elem)
- (gnus-byte-compile ;Why bother?
- `(lambda () (gnus-article-marked-p ',(cdr elem)))))
- gnus-summary-display-cache)))
- (let ((gnus-category-predicate-alist gnus-summary-display-cache)
- (gnus-category-predicate-cache gnus-summary-display-cache))
- (gnus-get-predicate display)))
- ;; Uses the dynamically bound `gnus-number' variable.
- (defvar gnus-number)
- (defun gnus-article-marked-p (type &optional article)
- (let ((article (or article gnus-number)))
- (cond
- ((eq type 'tick)
- (memq article gnus-newsgroup-marked))
- ((eq type 'spam)
- (memq article gnus-newsgroup-spam-marked))
- ((eq type 'unsend)
- (memq article gnus-newsgroup-unsendable))
- ((eq type 'undownload)
- (memq article gnus-newsgroup-undownloaded))
- ((eq type 'download)
- (memq article gnus-newsgroup-downloadable))
- ((eq type 'unread)
- (memq article gnus-newsgroup-unreads))
- ((eq type 'read)
- (memq article gnus-newsgroup-reads))
- ((eq type 'dormant)
- (memq article gnus-newsgroup-dormant) )
- ((eq type 'expire)
- (memq article gnus-newsgroup-expirable))
- ((eq type 'reply)
- (memq article gnus-newsgroup-replied))
- ((eq type 'killed)
- (memq article gnus-newsgroup-killed))
- ((eq type 'bookmark)
- (assq article gnus-newsgroup-bookmarks))
- ((eq type 'score)
- (assq article gnus-newsgroup-scored))
- ((eq type 'save)
- (memq article gnus-newsgroup-saved))
- ((eq type 'cache)
- (memq article gnus-newsgroup-cached))
- ((eq type 'forward)
- (memq article gnus-newsgroup-forwarded))
- ((eq type 'seen)
- (not (memq article gnus-newsgroup-unseen)))
- (t t))))
- (defun gnus-articles-to-read (group &optional read-all)
- "Find out what articles the user wants to read."
- (let* ((only-read-p t)
- (articles
- (gnus-list-range-difference
- ;; Select all articles if `read-all' is non-nil, or if there
- ;; are no unread articles.
- (if (or read-all
- (and (zerop (length gnus-newsgroup-marked))
- (zerop (length gnus-newsgroup-unreads)))
- ;; Fetch all if the predicate is non-nil.
- gnus-newsgroup-display)
- ;; We want to select the headers for all the articles in
- ;; the group, so we select either all the active
- ;; articles in the group, or (if that's nil), the
- ;; articles in the cache.
- (or
- (if gnus-newsgroup-maximum-articles
- (let ((active (gnus-active group)))
- (gnus-uncompress-range
- (cons (max (car active)
- (- (cdr active)
- gnus-newsgroup-maximum-articles
- -1))
- (cdr active))))
- (gnus-uncompress-range (gnus-active group)))
- (gnus-cache-articles-in-group group))
- ;; Select only the "normal" subset of articles.
- (setq only-read-p nil)
- (gnus-sorted-nunion
- (gnus-sorted-union gnus-newsgroup-dormant gnus-newsgroup-marked)
- gnus-newsgroup-unreads))
- (cdr (assq 'unexist (gnus-info-marks (gnus-get-info group))))))
- (scored-list (gnus-killed-articles gnus-newsgroup-killed articles))
- (scored (length scored-list))
- (number (length articles))
- (marked (+ (length gnus-newsgroup-marked)
- (length gnus-newsgroup-dormant)))
- (select
- (cond
- ((numberp read-all)
- read-all)
- ((numberp gnus-newsgroup-display)
- gnus-newsgroup-display)
- (t
- (condition-case ()
- (cond
- ((and (or (<= scored marked) (= scored number))
- (numberp gnus-large-newsgroup)
- (> number gnus-large-newsgroup))
- (let* ((cursor-in-echo-area nil)
- (initial (gnus-parameter-large-newsgroup-initial
- gnus-newsgroup-name))
- (default (if only-read-p
- (or initial gnus-large-newsgroup)
- number))
- (input
- (read-string
- (if only-read-p
- (format
- "How many articles from %s (available %d, default %d): "
- (gnus-group-decoded-name
- (gnus-group-real-name gnus-newsgroup-name))
- number default)
- (format
- "How many articles from %s (%d default): "
- (gnus-group-decoded-name
- (gnus-group-real-name gnus-newsgroup-name))
- default))
- nil
- nil
- (number-to-string default))))
- (if (string-match "^[ \t]*$" input) number input)))
- ((and (> scored marked) (< scored number)
- (> (- scored number) 20))
- (let ((input
- (read-string
- (format "%s %s (%d scored, %d total): "
- "How many articles from"
- (gnus-group-decoded-name
- (gnus-group-real-name gnus-newsgroup-name))
- scored number))))
- (if (string-match "^[ \t]*$" input)
- number input)))
- (t number))
- (quit
- (message "Quit getting the articles to read")
- nil))))))
- (setq select (if (stringp select) (string-to-number select) select))
- (if (or (null select) (zerop select))
- select
- (if (and (not (zerop scored)) (<= (abs select) scored))
- (progn
- (setq articles (sort scored-list '<))
- (setq number (length articles)))
- (setq articles (copy-sequence articles)))
- (when (< (abs select) number)
- (if (< select 0)
- ;; Select the N oldest articles.
- (setcdr (nthcdr (1- (abs select)) articles) nil)
- ;; Select the N most recent articles.
- (setq articles (nthcdr (- number select) articles))))
- (setq gnus-newsgroup-unselected
- (gnus-sorted-difference gnus-newsgroup-unreads articles))
- (when gnus-alter-articles-to-read-function
- (setq articles
- (sort
- (funcall gnus-alter-articles-to-read-function
- gnus-newsgroup-name articles)
- '<)))
- articles)))
- (defun gnus-killed-articles (killed articles)
- (let (out)
- (while articles
- (when (inline (gnus-member-of-range (car articles) killed))
- (push (car articles) out))
- (setq articles (cdr articles)))
- out))
- (defun gnus-article-mark-to-type (mark)
- "Return the type of MARK."
- (or (cadr (assq mark gnus-article-special-mark-lists))
- 'list))
- (defun gnus-article-unpropagatable-p (mark)
- "Return whether MARK should be propagated to back end."
- (memq mark gnus-article-unpropagated-mark-lists))
- (defun gnus-adjust-marked-articles (info)
- "Set all article lists and remove all marks that are no longer valid."
- (let* ((marked-lists (gnus-info-marks info))
- (active (gnus-active (gnus-info-group info)))
- (min (car active))
- (max (cdr active))
- (types gnus-article-mark-lists)
- marks var articles article mark mark-type
- bgn end)
- ;; Hack to avoid adjusting marks for imap.
- (when (eq (car (gnus-find-method-for-group (gnus-info-group info)))
- 'nnimap)
- (setq min 1))
- (dolist (marks marked-lists)
- (setq mark (car marks)
- mark-type (gnus-article-mark-to-type mark)
- var (intern (format "gnus-newsgroup-%s" (car (rassq mark types)))))
- ;; We set the variable according to the type of the marks list,
- ;; and then adjust the marks to a subset of the active articles.
- (cond
- ;; Adjust "simple" lists - compressed yet unsorted
- ((eq mark-type 'list)
- ;; Simultaneously uncompress and clip to active range
- ;; See gnus-uncompress-range for a description of possible marks
- (let (l lh)
- (if (not (cadr marks))
- (set var nil)
- (setq articles (if (numberp (cddr marks))
- (list (cdr marks))
- (cdr marks))
- lh (cons nil nil)
- l lh)
- (while (setq article (pop articles))
- (cond ((consp article)
- (setq bgn (max (car article) min)
- end (min (cdr article) max))
- (while (<= bgn end)
- (setq l (setcdr l (cons bgn nil))
- bgn (1+ bgn))))
- ((and (<= min article)
- (>= max article))
- (setq l (setcdr l (cons article nil))))))
- (set var (cdr lh)))))
- ;; Adjust assocs.
- ((eq mark-type 'tuple)
- (set var (setq articles (cdr marks)))
- (when (not (listp (cdr (symbol-value var))))
- (set var (list (symbol-value var))))
- (when (not (listp (cdr articles)))
- (setq articles (list articles)))
- (while articles
- (when (or (not (consp (setq article (pop articles))))
- (< (car article) min)
- (> (car article) max))
- (set var (delq article (symbol-value var))))))
- ;; Adjust ranges (sloppily).
- ((eq mark-type 'range)
- (cond
- ((eq mark 'seen)
- ;; Fix the record for `seen' if it looks like (seen NUM1 . NUM2).
- ;; It should be (seen (NUM1 . NUM2)).
- (when (numberp (cddr marks))
- (setcdr marks (list (cdr marks))))
- (setq articles (cdr marks))
- (while (and articles
- (or (and (consp (car articles))
- (> min (cdar articles)))
- (and (numberp (car articles))
- (> min (car articles)))))
- (pop articles))
- (set var articles))
- ((eq mark 'unexist)
- (set var (cdr marks)))))))))
- (defun gnus-update-missing-marks (missing)
- "Go through the list of MISSING articles and remove them from the mark lists."
- (when missing
- (let (var m)
- ;; Go through all types.
- (dolist (elem gnus-article-mark-lists)
- (when (eq (gnus-article-mark-to-type (cdr elem)) 'list)
- (setq var (intern (format "gnus-newsgroup-%s" (car elem))))
- (when (symbol-value var)
- ;; This list has articles. So we delete all missing
- ;; articles from it.
- (setq m missing)
- (while m
- (set var (delq (pop m) (symbol-value var))))))))))
- (defun gnus-update-marks ()
- "Enter the various lists of marked articles into the newsgroup info list."
- (let ((types gnus-article-mark-lists)
- (info (gnus-get-info gnus-newsgroup-name))
- type list newmarked symbol delta-marks)
- (when info
- ;; Add all marks lists to the list of marks lists.
- (while (setq type (pop types))
- (setq list (symbol-value
- (setq symbol
- (intern (format "gnus-newsgroup-%s" (car type))))))
- (when list
- ;; Get rid of the entries of the articles that have the
- ;; default score.
- (when (and (eq (cdr type) 'score)
- gnus-save-score
- list)
- (let* ((arts list)
- (prev (cons nil list))
- (all prev))
- (while arts
- (if (or (not (consp (car arts)))
- (= (cdar arts) gnus-summary-default-score))
- (setcdr prev (cdr arts))
- (setq prev arts))
- (setq arts (cdr arts)))
- (setq list (cdr all)))))
- (when (eq (cdr type) 'seen)
- (setq list (gnus-range-add list gnus-newsgroup-unseen)))
- (when (eq (gnus-article-mark-to-type (cdr type)) 'list)
- (setq list (gnus-compress-sequence (set symbol (sort list '<)) t)))
- (when (and (gnus-check-backend-function
- 'request-set-mark gnus-newsgroup-name)
- (not (gnus-article-unpropagatable-p (cdr type))))
- (let* ((old (cdr (assq (cdr type) (gnus-info-marks info))))
- ;; Don't do anything about marks for articles we
- ;; didn't actually get any headers for.
- (del
- (gnus-list-range-intersection
- gnus-newsgroup-articles
- (gnus-remove-from-range (gnus-copy-sequence old) list)))
- (add
- (gnus-list-range-intersection
- gnus-newsgroup-articles
- (gnus-remove-from-range
- (gnus-copy-sequence list) old))))
- (when add
- (push (list add 'add (list (cdr type))) delta-marks))
- (when del
- ;; Don't delete marks from outside the active range.
- ;; This shouldn't happen, but is a sanity check.
- (setq del (gnus-sorted-range-intersection
- (gnus-active gnus-newsgroup-name) del))
- (push (list del 'del (list (cdr type))) delta-marks))))
- (when (or list
- (eq (cdr type) 'unexist))
- (push (cons (cdr type) list) newmarked)))
- (when delta-marks
- (unless (gnus-check-group gnus-newsgroup-name)
- (error "Can't open server for %s" gnus-newsgroup-name))
- (gnus-request-set-mark gnus-newsgroup-name delta-marks))
- ;; Enter these new marks into the info of the group.
- (if (nthcdr 3 info)
- (setcar (nthcdr 3 info) newmarked)
- ;; Add the marks lists to the end of the info.
- (when newmarked
- (setcdr (nthcdr 2 info) (list newmarked))))
- ;; Cut off the end of the info if there's nothing else there.
- (let ((i 5))
- (while (and (> i 2)
- (not (nth i info)))
- (when (nthcdr (decf i) info)
- (setcdr (nthcdr i info) nil)))))))
- (defun gnus-set-mode-line (where)
- "Set the mode line of the article or summary buffers.
- If WHERE is `summary', the summary mode line format will be used."
- ;; Is this mode line one we keep updated?
- (when (and (memq where gnus-updated-mode-lines)
- (symbol-value
- (intern (format "gnus-%s-mode-line-format-spec" where))))
- (let (mode-string)
- ;; We evaluate this in the summary buffer since these
- ;; variables are buffer-local to that buffer.
- (with-current-buffer gnus-summary-buffer
- ;; We bind all these variables that are used in the `eval' form
- ;; below.
- (let* ((mformat (symbol-value
- (intern
- (format "gnus-%s-mode-line-format-spec" where))))
- (gnus-tmp-group-name (gnus-mode-string-quote
- (gnus-group-decoded-name
- gnus-newsgroup-name)))
- (gnus-tmp-article-number (or gnus-current-article 0))
- (gnus-tmp-unread gnus-newsgroup-unreads)
- (gnus-tmp-unread-and-unticked (length gnus-newsgroup-unreads))
- (gnus-tmp-unselected (length gnus-newsgroup-unselected))
- (gnus-tmp-unread-and-unselected
- (cond ((and (zerop gnus-tmp-unread-and-unticked)
- (zerop gnus-tmp-unselected))
- "")
- ((zerop gnus-tmp-unselected)
- (format "{%d more}" gnus-tmp-unread-and-unticked))
- (t (format "{%d(+%d) more}"
- gnus-tmp-unread-and-unticked
- gnus-tmp-unselected))))
- (gnus-tmp-subject
- (if (and gnus-current-headers
- (vectorp gnus-current-headers))
- (gnus-mode-string-quote
- (mail-header-subject gnus-current-headers))
- ""))
- bufname-length max-len
- gnus-tmp-header) ;; passed as argument to any user-format-funcs
- (setq mode-string (eval mformat))
- (setq bufname-length (if (string-match "%b" mode-string)
- (- (length
- (buffer-name
- (if (eq where 'summary)
- nil
- (get-buffer gnus-article-buffer))))
- 2)
- 0))
- (setq max-len (max 4 (if gnus-mode-non-string-length
- (- (window-width)
- gnus-mode-non-string-length
- bufname-length)
- (length mode-string))))
- ;; We might have to chop a bit of the string off...
- (when (> (length mode-string) max-len)
- (setq mode-string
- (concat (truncate-string-to-width mode-string (- max-len 3))
- "...")))))
- ;; Update the mode line.
- (setq mode-line-buffer-identification
- (gnus-mode-line-buffer-identification (list mode-string)))
- (set-buffer-modified-p t))))
- (defun gnus-create-xref-hashtb (from-newsgroup headers unreads)
- "Go through the HEADERS list and add all Xrefs to a hash table.
- The resulting hash table is returned, or nil if no Xrefs were found."
- (let* ((virtual (gnus-virtual-group-p from-newsgroup))
- (prefix (if virtual "" (gnus-group-real-prefix from-newsgroup)))
- (xref-hashtb (gnus-make-hashtable))
- start group entry number xrefs header)
- (while headers
- (setq header (pop headers))
- (when (and (setq xrefs (mail-header-xref header))
- (not (memq (setq number (mail-header-number header))
- unreads)))
- (setq start 0)
- (while (string-match "\\([^ ]+\\)[:/]\\([0-9]+\\)" xrefs start)
- (setq start (match-end 0))
- (setq group (if prefix
- (concat prefix (substring xrefs (match-beginning 1)
- (match-end 1)))
- (substring xrefs (match-beginning 1) (match-end 1))))
- (setq number
- (string-to-number (substring xrefs (match-beginning 2)
- (match-end 2))))
- (if (setq entry (gnus-gethash group xref-hashtb))
- (setcdr entry (cons number (cdr entry)))
- (gnus-sethash group (cons number nil) xref-hashtb)))))
- (and start xref-hashtb)))
- (defun gnus-mark-xrefs-as-read (from-newsgroup headers unreads)
- "Look through all the headers and mark the Xrefs as read."
- (let ((virtual (gnus-virtual-group-p from-newsgroup))
- name info xref-hashtb idlist method nth4)
- (with-current-buffer gnus-group-buffer
- (when (setq xref-hashtb
- (gnus-create-xref-hashtb from-newsgroup headers unreads))
- (mapatoms
- (lambda (group)
- (unless (string= from-newsgroup (setq name (symbol-name group)))
- (setq idlist (symbol-value group))
- ;; Dead groups are not updated.
- (and (prog1
- (setq info (gnus-get-info name))
- (when (stringp (setq nth4 (gnus-info-method info)))
- (setq nth4 (gnus-server-to-method nth4))))
- ;; Only do the xrefs if the group has the same
- ;; select method as the group we have just read.
- (or (gnus-methods-equal-p
- nth4 (gnus-find-method-for-group from-newsgroup))
- virtual
- (equal nth4 (setq method (gnus-find-method-for-group
- from-newsgroup)))
- (and (equal (car nth4) (car method))
- (equal (nth 1 nth4) (nth 1 method))))
- gnus-use-cross-reference
- (or (not (eq gnus-use-cross-reference t))
- virtual
- ;; Only do cross-references on subscribed
- ;; groups, if that is what is wanted.
- (<= (gnus-info-level info) gnus-level-subscribed))
- (gnus-group-make-articles-read name idlist))))
- xref-hashtb)))))
- (defun gnus-compute-read-articles (group articles)
- (let* ((entry (gnus-group-entry group))
- (info (nth 2 entry))
- (active (gnus-active group))
- ninfo)
- (when entry
- ;; First peel off all invalid article numbers.
- (when active
- (let ((ids articles)
- id first)
- (while (setq id (pop ids))
- (when (and first (> id (cdr active)))
- ;; We'll end up in this situation in one particular
- ;; obscure situation. If you re-scan a group and get
- ;; a new article that is cross-posted to a different
- ;; group that has not been re-scanned, you might get
- ;; crossposted article that has a higher number than
- ;; Gnus believes possible. So we re-activate this
- ;; group as well. This might mean doing the
- ;; crossposting thingy will *increase* the number
- ;; of articles in some groups. Tsk, tsk.
- (setq active (or (gnus-activate-group group) active)))
- (when (or (> id (cdr active))
- (< id (car active)))
- (setq articles (delq id articles))))))
- ;; If the read list is nil, we init it.
- (if (and active
- (null (gnus-info-read info))
- (> (car active) 1))
- (setq ninfo (cons 1 (1- (car active))))
- (setq ninfo (gnus-info-read info)))
- ;; Then we add the read articles to the range.
- (gnus-add-to-range
- ninfo (setq articles (sort articles '<))))))
- (defun gnus-group-make-articles-read (group articles)
- "Update the info of GROUP to say that ARTICLES are read."
- (let* ((num 0)
- (entry (gnus-group-entry group))
- (info (nth 2 entry))
- (active (gnus-active group))
- (set-marks
- (gnus-method-option-p
- (gnus-find-method-for-group group)
- 'server-marks))
- range)
- (if (not entry)
- ;; Group that Gnus doesn't know exists, but still allow the
- ;; backend to set marks.
- (when set-marks
- (gnus-request-set-mark
- group (list (list (gnus-compress-sequence (sort articles #'<))
- 'add '(read)))))
- ;; Normal, subscribed groups.
- (setq range (gnus-compute-read-articles group articles))
- (with-current-buffer gnus-group-buffer
- (gnus-undo-register
- `(progn
- (gnus-info-set-marks ',info ',(gnus-info-marks info) t)
- (gnus-info-set-read ',info ',(gnus-info-read info))
- (gnus-get-unread-articles-in-group ',info (gnus-active ,group))
- (when ,set-marks
- (gnus-request-set-mark
- ,group (list (list ',range 'del '(read)))))
- (gnus-group-update-group ,group t))))
- ;; Add the read articles to the range.
- (gnus-info-set-read info range)
- (when set-marks
- (gnus-request-set-mark group (list (list range 'add '(read)))))
- ;; Then we have to re-compute how many unread
- ;; articles there are in this group.
- (when active
- (cond
- ((not range)
- (setq num (- (1+ (cdr active)) (car active))))
- ((not (listp (cdr range)))
- (setq num (- (cdr active) (- (1+ (cdr range))
- (car range)))))
- (t
- (while range
- (if (numberp (car range))
- (setq num (1+ num))
- (setq num (+ num (- (1+ (cdar range)) (caar range)))))
- (setq range (cdr range)))
- (setq num (- (cdr active) num))))
- ;; Update the number of unread articles.
- (setcar entry num)
- ;; Update the group buffer.
- (unless (gnus-ephemeral-group-p group)
- (gnus-group-update-group group t))))))
- (defun gnus-get-newsgroup-headers (&optional dependencies force-new)
- (let ((cur nntp-server-buffer)
- (dependencies
- (or dependencies
- (with-current-buffer gnus-summary-buffer
- gnus-newsgroup-dependencies)))
- headers id end ref number
- (mail-parse-charset gnus-newsgroup-charset)
- (mail-parse-ignored-charsets
- (save-current-buffer (condition-case nil
- (set-buffer gnus-summary-buffer)
- (error))
- gnus-newsgroup-ignored-charsets)))
- (with-current-buffer nntp-server-buffer
- ;; Translate all TAB characters into SPACE characters.
- (subst-char-in-region (point-min) (point-max) ?\t ? t)
- (subst-char-in-region (point-min) (point-max) ?\r ? t)
- (ietf-drums-unfold-fws)
- (gnus-run-hooks 'gnus-parse-headers-hook)
- (let ((case-fold-search t)
- in-reply-to header p lines chars)
- (goto-char (point-min))
- ;; Search to the beginning of the next header. Error messages
- ;; do not begin with 2 or 3.
- (while (re-search-forward "^[23][0-9]+ " nil t)
- (setq id nil
- ref nil)
- ;; This implementation of this function, with nine
- ;; search-forwards instead of the one re-search-forward and
- ;; a case (which basically was the old function) is actually
- ;; about twice as fast, even though it looks messier. You
- ;; can't have everything, I guess. Speed and elegance
- ;; doesn't always go hand in hand.
- (setq
- header
- (vector
- ;; Number.
- (prog1
- (setq number (read cur))
- (end-of-line)
- (setq p (point))
- (narrow-to-region (point)
- (or (and (search-forward "\n.\n" nil t)
- (- (point) 2))
- (point))))
- ;; Subject.
- (progn
- (goto-char p)
- (if (search-forward "\nsubject:" nil t)
- (funcall gnus-decode-encoded-word-function
- (nnheader-header-value))
- "(none)"))
- ;; From.
- (progn
- (goto-char p)
- (if (search-forward "\nfrom:" nil t)
- (funcall gnus-decode-encoded-address-function
- (nnheader-header-value))
- "(nobody)"))
- ;; Date.
- (progn
- (goto-char p)
- (if (search-forward "\ndate:" nil t)
- (nnheader-header-value) ""))
- ;; Message-ID.
- (progn
- (goto-char p)
- (setq id (if (re-search-forward
- "^message-id: *\\(<[^\n\t> ]+>\\)" nil t)
- ;; We do it this way to make sure the Message-ID
- ;; is (somewhat) syntactically valid.
- (buffer-substring (match-beginning 1)
- (match-end 1))
- ;; If there was no message-id, we just fake one
- ;; to make subsequent routines simpler.
- (nnheader-generate-fake-message-id number))))
- ;; References.
- (progn
- (goto-char p)
- (if (search-forward "\nreferences:" nil t)
- (progn
- (setq end (point))
- (prog1
- (nnheader-header-value)
- (setq ref
- (buffer-substring
- (progn
- (end-of-line)
- (search-backward ">" end t)
- (1+ (point)))
- (progn
- (search-backward "<" end t)
- (point))))))
- ;; Get the references from the in-reply-to header if there
- ;; were no references and the in-reply-to header looks
- ;; promising.
- (if (and (search-forward "\nin-reply-to:" nil t)
- (setq in-reply-to (nnheader-header-value))
- (string-match "<[^>]+>" in-reply-to))
- (let (ref2)
- (setq ref (substring in-reply-to (match-beginning 0)
- (match-end 0)))
- (while (string-match "<[^>]+>" in-reply-to (match-end 0))
- (setq ref2 (substring in-reply-to (match-beginning 0)
- (match-end 0)))
- (when (> (length ref2) (length ref))
- (setq ref ref2)))
- ref)
- (setq ref nil))))
- ;; Chars.
- (progn
- (goto-char p)
- (if (search-forward "\nchars: " nil t)
- (if (numberp (setq chars (ignore-errors (read cur))))
- chars -1)
- -1))
- ;; Lines.
- (progn
- (goto-char p)
- (if (search-forward "\nlines: " nil t)
- (if (numberp (setq lines (ignore-errors (read cur))))
- lines -1)
- -1))
- ;; Xref.
- (progn
- (goto-char p)
- (and (search-forward "\nxref:" nil t)
- (nnheader-header-value)))
- ;; Extra.
- (when gnus-extra-headers
- (let ((extra gnus-extra-headers)
- out)
- (while extra
- (goto-char p)
- (when (search-forward
- (concat "\n" (symbol-name (car extra)) ":") nil t)
- (push (cons (car extra) (nnheader-header-value))
- out))
- (pop extra))
- out))))
- (when (equal id ref)
- (setq ref nil))
- (when gnus-alter-header-function
- (funcall gnus-alter-header-function header)
- (setq id (mail-header-id header)
- ref (gnus-parent-id (mail-header-references header))))
- (when (setq header
- (gnus-dependencies-add-header
- header dependencies force-new))
- (push header headers))
- (goto-char (point-max))
- (widen))
- (nreverse headers)))))
- ;; Goes through the xover lines and returns a list of vectors
- (defun gnus-get-newsgroup-headers-xover (sequence &optional
- force-new dependencies
- group also-fetch-heads)
- "Parse the news overview data in the server buffer.
- Return a list of headers that match SEQUENCE (see
- `nntp-retrieve-headers')."
- ;; Get the Xref when the users reads the articles since most/some
- ;; NNTP servers do not include Xrefs when using XOVER.
- (setq gnus-article-internal-prepare-hook '(gnus-article-get-xrefs))
- (let ((mail-parse-charset gnus-newsgroup-charset)
- (mail-parse-ignored-charsets gnus-newsgroup-ignored-charsets)
- (cur nntp-server-buffer)
- (dependencies (or dependencies gnus-newsgroup-dependencies))
- (allp (cond
- ((eq gnus-read-all-available-headers t)
- t)
- ((and (stringp gnus-read-all-available-headers)
- group)
- (string-match gnus-read-all-available-headers group))
- (t
- nil)))
- number headers header)
- (with-current-buffer nntp-server-buffer
- (subst-char-in-region (point-min) (point-max) ?\r ? t)
- ;; Allow the user to mangle the headers before parsing them.
- (gnus-run-hooks 'gnus-parse-headers-hook)
- (goto-char (point-min))
- (gnus-parse-without-error
- (while (and (or sequence allp)
- (not (eobp)))
- (setq number (read cur))
- (when (not allp)
- (while (and sequence
- (< (car sequence) number))
- (setq sequence (cdr sequence))))
- (when (and (or allp
- (and sequence
- (eq number (car sequence))))
- (progn
- (setq sequence (cdr sequence))
- (setq header (inline
- (gnus-nov-parse-line
- number dependencies force-new)))))
- (push header headers))
- (forward-line 1)))
- ;; A common bug in inn is that if you have posted an article and
- ;; then retrieves the active file, it will answer correctly --
- ;; the new article is included. However, a NOV entry for the
- ;; article may not have been generated yet, so this may fail.
- ;; We work around this problem by retrieving the last few
- ;; headers using HEAD.
- (if (or (not also-fetch-heads)
- (not sequence))
- ;; We (probably) got all the headers.
- (nreverse headers)
- (let ((gnus-nov-is-evil t))
- (nconc
- (nreverse headers)
- (when (eq (gnus-retrieve-headers sequence group) 'headers)
- (gnus-get-newsgroup-headers))))))))
- (defun gnus-article-get-xrefs ()
- "Fill in the Xref value in `gnus-current-headers', if necessary.
- This is meant to be called in `gnus-article-internal-prepare-hook'."
- (let ((headers (with-current-buffer gnus-summary-buffer
- gnus-current-headers)))
- (or (not gnus-use-cross-reference)
- (not headers)
- (and (mail-header-xref headers)
- (not (string= (mail-header-xref headers) "")))
- (let ((case-fold-search t)
- xref)
- (save-restriction
- (nnheader-narrow-to-headers)
- (goto-char (point-min))
- (when (or (and (not (eobp))
- (eq (downcase (char-after)) ?x)
- (looking-at "Xref:"))
- (search-forward "\nXref:" nil t))
- (goto-char (1+ (match-end 0)))
- (setq xref (buffer-substring (point) (point-at-eol)))
- (mail-header-set-xref headers xref)))))))
- (defun gnus-summary-insert-subject (id &optional old-header use-old-header)
- "Find article ID and insert the summary line for that article.
- OLD-HEADER can either be a header or a line number to insert
- the subject line on.
- If USE-OLD-HEADER is non-nil, then OLD-HEADER should be a header,
- and OLD-HEADER will be used when the summary line is inserted,
- too, instead of trying to fetch new headers."
- (let* ((line (and (numberp old-header) old-header))
- (old-header (and (vectorp old-header) old-header))
- (header (cond ((and old-header use-old-header)
- old-header)
- ((and (numberp id)
- (gnus-number-to-header id))
- (gnus-number-to-header id))
- (t
- (gnus-read-header id))))
- (number (and (numberp id) id))
- d)
- (when header
- ;; Rebuild the thread that this article is part of and go to the
- ;; article we have fetched.
- (when (and (not gnus-show-threads)
- old-header)
- (when (and number
- (setq d (gnus-data-find (mail-header-number old-header))))
- (goto-char (gnus-data-pos d))
- (gnus-data-remove
- number
- (- (point-at-bol)
- (prog1
- (1+ (point-at-eol))
- (gnus-delete-line))))))
- ;; Remove list identifiers from subject.
- (let ((gnus-newsgroup-headers (list header)))
- (gnus-summary-remove-list-identifiers))
- (when old-header
- (mail-header-set-number header (mail-header-number old-header)))
- (setq gnus-newsgroup-sparse
- (delq (setq number (mail-header-number header))
- gnus-newsgroup-sparse))
- (setq gnus-newsgroup-ancient (delq number gnus-newsgroup-ancient))
- (push number gnus-newsgroup-limit)
- (gnus-rebuild-thread (mail-header-id header) line)
- (gnus-summary-goto-subject number nil t))
- (when (and (numberp number)
- (> number 0))
- ;; We have to update the boundaries even if we can't fetch the
- ;; article if ID is a number -- so that the next `P' or `N'
- ;; command will fetch the previous (or next) article even
- ;; if the one we tried to fetch this time has been canceled.
- (unless (and gnus-newsgroup-end (< number gnus-newsgroup-end))
- (setq gnus-newsgroup-end number))
- (unless (and gnus-newsgroup-begin (> number gnus-newsgroup-begin))
- (setq gnus-newsgroup-begin number))
- (setq gnus-newsgroup-unselected
- (delq number gnus-newsgroup-unselected)))
- ;; Report back a success?
- (and header (mail-header-number header))))
- ;;; Process/prefix in the summary buffer
- (defun gnus-summary-work-articles (n)
- "Return a list of articles to be worked upon.
- The prefix argument, the list of process marked articles, and the
- current article will be taken into consideration."
- (with-current-buffer gnus-summary-buffer
- (cond
- (n
- ;; A numerical prefix has been given.
- (setq n (prefix-numeric-value n))
- (let ((backward (< n 0))
- (n (abs (prefix-numeric-value n)))
- articles article)
- (save-excursion
- (while
- (and (> n 0)
- (push (setq article (gnus-summary-article-number))
- articles)
- (if backward
- (gnus-summary-find-prev nil article)
- (gnus-summary-find-next nil article)))
- (decf n)))
- (nreverse articles)))
- ((and (gnus-region-active-p) (mark))
- (message "region active")
- ;; Work on the region between point and mark.
- (let ((max (max (point) (mark)))
- articles article)
- (save-excursion
- (goto-char (min (point) (mark)))
- (while
- (and
- (push (setq article (gnus-summary-article-number)) articles)
- (gnus-summary-find-next nil article)
- (< (point) max)))
- (nreverse articles))))
- (gnus-newsgroup-processable
- ;; There are process-marked articles present.
- ;; Save current state.
- (gnus-summary-save-process-mark)
- ;; Return the list.
- (reverse gnus-newsgroup-processable))
- (t
- ;; Just return the current article.
- (list (gnus-summary-article-number))))))
- (defmacro gnus-summary-iterate (arg &rest forms)
- "Iterate over the process/prefixed articles and do FORMS.
- ARG is the interactive prefix given to the command. FORMS will be
- executed with point over the summary line of the articles."
- (let ((articles (make-symbol "gnus-summary-iterate-articles")))
- `(let ((,articles (gnus-summary-work-articles ,arg)))
- (while ,articles
- (gnus-summary-goto-subject (car ,articles))
- ,@forms
- (pop ,articles)))))
- (put 'gnus-summary-iterate 'lisp-indent-function 1)
- (put 'gnus-summary-iterate 'edebug-form-spec '(form body))
- (defun gnus-summary-save-process-mark ()
- "Push the current set of process marked articles on the stack."
- (interactive)
- (push (copy-sequence gnus-newsgroup-processable)
- gnus-newsgroup-process-stack))
- (defun gnus-summary-kill-process-mark ()
- "Push the current set of process marked articles on the stack and unmark."
- (interactive)
- (gnus-summary-save-process-mark)
- (gnus-summary-unmark-all-processable))
- (defun gnus-summary-yank-process-mark ()
- "Pop the last process mark state off the stack and restore it."
- (interactive)
- (unless gnus-newsgroup-process-stack
- (error "Empty mark stack"))
- (gnus-summary-process-mark-set (pop gnus-newsgroup-process-stack)))
- (defun gnus-summary-process-mark-set (set)
- "Make SET into the current process marked articles."
- (gnus-summary-unmark-all-processable)
- (mapc 'gnus-summary-set-process-mark set))
- ;;; Searching and stuff
- (defun gnus-summary-search-group (&optional backward use-level)
- "Search for next unread newsgroup.
- If optional argument BACKWARD is non-nil, search backward instead."
- (with-current-buffer gnus-group-buffer
- (when (gnus-group-search-forward
- backward nil (if use-level (gnus-group-group-level) nil))
- (gnus-group-group-name))))
- (defun gnus-summary-best-group (&optional exclude-group)
- "Find the name of the best unread group.
- If EXCLUDE-GROUP, do not go to this group."
- (with-current-buffer gnus-group-buffer
- (save-excursion
- (gnus-group-best-unread-group exclude-group))))
- (defun gnus-summary-find-next (&optional unread article backward)
- (if backward
- (gnus-summary-find-prev unread article)
- (let* ((dummy (gnus-summary-article-intangible-p))
- (article (or article (gnus-summary-article-number)))
- (data (gnus-data-find-list article))
- result)
- (when (and (not dummy)
- (or (not gnus-summary-check-current)
- (not unread)
- (not (gnus-data-unread-p (car data)))))
- (setq data (cdr data)))
- (when (setq result
- (if unread
- (progn
- (while data
- (unless (memq (gnus-data-number (car data))
- (cond
- ((eq gnus-auto-goto-ignores
- 'always-undownloaded)
- gnus-newsgroup-undownloaded)
- (gnus-plugged
- nil)
- ((eq gnus-auto-goto-ignores
- 'unfetched)
- gnus-newsgroup-unfetched)
- ((eq gnus-auto-goto-ignores
- 'undownloaded)
- gnus-newsgroup-undownloaded)))
- (when (gnus-data-unread-p (car data))
- (setq result (car data)
- data nil)))
- (setq data (cdr data)))
- result)
- (car data)))
- (goto-char (gnus-data-pos result))
- (gnus-data-number result)))))
- (defun gnus-summary-find-prev (&optional unread article)
- (let* ((eobp (eobp))
- (article (or article (gnus-summary-article-number)))
- (data (gnus-data-find-list article (gnus-data-list 'rev)))
- result)
- (when (and (not eobp)
- (or (not gnus-summary-check-current)
- (not unread)
- (not (gnus-data-unread-p (car data)))))
- (setq data (cdr data)))
- (when (setq result
- (if unread
- (progn
- (while data
- (unless (memq (gnus-data-number (car data))
- (cond
- ((eq gnus-auto-goto-ignores
- 'always-undownloaded)
- gnus-newsgroup-undownloaded)
- (gnus-plugged
- nil)
- ((eq gnus-auto-goto-ignores
- 'unfetched)
- gnus-newsgroup-unfetched)
- ((eq gnus-auto-goto-ignores
- 'undownloaded)
- gnus-newsgroup-undownloaded)))
- (when (gnus-data-unread-p (car data))
- (setq result (car data)
- data nil)))
- (setq data (cdr data)))
- result)
- (car data)))
- (goto-char (gnus-data-pos result))
- (gnus-data-number result))))
- (defun gnus-summary-find-subject (subject &optional unread backward article)
- (let* ((simp-subject (gnus-simplify-subject-fully subject))
- (article (or article (gnus-summary-article-number)))
- (articles (gnus-data-list backward))
- (arts (gnus-data-find-list article articles))
- result)
- (when (or (not gnus-summary-check-current)
- (not unread)
- (not (gnus-data-unread-p (car arts))))
- (setq arts (cdr arts)))
- (while arts
- (and (or (not unread)
- (gnus-data-unread-p (car arts)))
- (vectorp (gnus-data-header (car arts)))
- (gnus-subject-equal
- simp-subject (mail-header-subject (gnus-data-header (car arts))) t)
- (setq result (car arts)
- arts nil))
- (setq arts (cdr arts)))
- (and result
- (goto-char (gnus-data-pos result))
- (gnus-data-number result))))
- (defun gnus-summary-search-forward (&optional unread subject backward)
- "Search forward for an article.
- If UNREAD, look for unread articles. If SUBJECT, look for
- articles with that subject. If BACKWARD, search backward instead."
- (cond (subject (gnus-summary-find-subject subject unread backward))
- (backward (gnus-summary-find-prev unread))
- (t (gnus-summary-find-next unread))))
- (defun gnus-recenter (&optional n)
- "Center point in window and redisplay frame.
- Also do horizontal recentering."
- (interactive "P")
- (when (and gnus-auto-center-summary
- (not (eq gnus-auto-center-summary 'vertical)))
- (gnus-horizontal-recenter))
- (if (fboundp 'recenter-top-bottom)
- (recenter-top-bottom n)
- (recenter n)))
- (put 'gnus-recenter 'isearch-scroll t)
- (defun gnus-forward-line-ignore-invisible (n)
- "Move N lines forward (backward if N is negative).
- Like forward-line, but skip over (and don't count) invisible lines."
- (let (done)
- (while (and (> n 0) (not done))
- ;; If the following character is currently invisible,
- ;; skip all characters with that same `invisible' property value.
- (while (gnus-invisible-p (point))
- (goto-char (gnus-next-char-property-change (point))))
- (forward-line 1)
- (if (eobp)
- (setq done t)
- (setq n (1- n))))
- (while (and (< n 0) (not done))
- (forward-line -1)
- (if (bobp) (setq done t)
- (setq n (1+ n))
- (while (and (not (bobp)) (gnus-invisible-p (1- (point))))
- (goto-char (gnus-previous-char-property-change (point))))))))
- (defun gnus-summary-recenter ()
- "Center point in the summary window.
- If `gnus-auto-center-summary' is nil, or the article buffer isn't
- displayed, no centering will be performed."
- ;; Suggested by earle@mahendo.JPL.NASA.GOV (Greg Earle).
- ;; Recenter only when requested. Suggested by popovich@park.cs.columbia.edu.
- (interactive)
- ;; The user has to want it.
- (when gnus-auto-center-summary
- (let* ((top (cond ((< (window-height) 4) 0)
- ((< (window-height) 7) 1)
- (t (if (numberp gnus-auto-center-summary)
- gnus-auto-center-summary
- (/ (1- (window-height)) 2)))))
- (height (1- (window-height)))
- (bottom (save-excursion
- (goto-char (point-max))
- (gnus-forward-line-ignore-invisible (- height))
- (point)))
- (window (get-buffer-window (current-buffer))))
- (when (get-buffer-window gnus-article-buffer)
- ;; Only do recentering when the article buffer is displayed,
- ;; Set the window start to either `bottom', which is the biggest
- ;; possible valid number, or the second line from the top,
- ;; whichever is the least.
- (let ((top-pos (save-excursion
- (gnus-forward-line-ignore-invisible (- top))
- (point))))
- (if (> bottom top-pos)
- ;; Keep the second line from the top visible
- (set-window-start window top-pos)
- ;; Try to keep the bottom line visible; if it's partially
- ;; obscured, either scroll one more line to make it fully
- ;; visible, or revert to using TOP-POS.
- (save-excursion
- (goto-char (point-max))
- (gnus-forward-line-ignore-invisible -1)
- (let ((last-line-start (point)))
- (goto-char bottom)
- (set-window-start window (point) t)
- (when (not (pos-visible-in-window-p last-line-start window))
- (gnus-forward-line-ignore-invisible 1)
- (set-window-start window (min (point) top-pos) t)))))))
- ;; Do horizontal recentering while we're at it.
- (when (and (get-buffer-window (current-buffer) t)
- (not (eq gnus-auto-center-summary 'vertical)))
- (let ((selected (selected-window)))
- (select-window (get-buffer-window (current-buffer) t))
- (gnus-summary-position-point)
- (gnus-horizontal-recenter)
- (select-window selected))))))
- (defun gnus-summary-jump-to-group (newsgroup)
- "Move point to NEWSGROUP in group mode buffer."
- ;; Keep update point of group mode buffer if visible.
- (if (eq (current-buffer) (get-buffer gnus-group-buffer))
- (save-window-excursion
- ;; Take care of tree window mode.
- (when (get-buffer-window gnus-group-buffer)
- (pop-to-buffer gnus-group-buffer))
- (gnus-group-jump-to-group newsgroup))
- (save-excursion
- ;; Take care of tree window mode.
- (if (get-buffer-window gnus-group-buffer 0)
- (pop-to-buffer gnus-group-buffer)
- (set-buffer gnus-group-buffer))
- (gnus-group-jump-to-group newsgroup))))
- ;; This function returns a list of article numbers based on the
- ;; difference between the ranges of read articles in this group and
- ;; the range of active articles.
- (defun gnus-list-of-unread-articles (group)
- (let* ((read (gnus-info-read (gnus-get-info group)))
- (active (or (gnus-active group) (gnus-activate-group group)))
- (last (or (cdr active)
- (error "Group %s couldn't be activated " group)))
- (bottom (if gnus-newsgroup-maximum-articles
- (max (car active)
- (- last gnus-newsgroup-maximum-articles -1))
- (car active)))
- first nlast unread)
- ;; If none are read, then all are unread.
- (if (not read)
- (setq first bottom)
- ;; If the range of read articles is a single range, then the
- ;; first unread article is the article after the last read
- ;; article. Sounds logical, doesn't it?
- (if (and (not (listp (cdr read)))
- (or (< (car read) bottom)
- (progn (setq read (list read))
- nil)))
- (setq first (max bottom (1+ (cdr read))))
- ;; `read' is a list of ranges.
- (when (/= (setq nlast (or (and (numberp (car read)) (car read))
- (caar read)))
- 1)
- (setq first bottom))
- (while read
- (when first
- (while (< first nlast)
- (setq unread (cons first unread)
- first (1+ first))))
- (setq first (1+ (if (atom (car read)) (car read) (cdar read))))
- (setq nlast (if (atom (cadr read)) (cadr read) (caadr read)))
- (setq read (cdr read)))))
- ;; And add the last unread articles.
- (while (<= first last)
- (setq unread (cons first unread)
- first (1+ first)))
- ;; Return the list of unread articles.
- (delq 0 (nreverse unread))))
- (defun gnus-list-of-read-articles (group)
- "Return a list of unread, unticked and non-dormant articles."
- (let* ((info (gnus-get-info group))
- (marked (gnus-info-marks info))
- (active (gnus-active group)))
- (and info active
- (gnus-list-range-difference
- (gnus-list-range-difference
- (gnus-sorted-complement
- (gnus-uncompress-range
- (if gnus-newsgroup-maximum-articles
- (cons (max (car active)
- (- (cdr active)
- gnus-newsgroup-maximum-articles
- -1))
- (cdr active))
- active))
- (gnus-list-of-unread-articles group))
- (cdr (assq 'dormant marked)))
- (cdr (assq 'tick marked))))))
- ;; This function returns a sequence of article numbers based on the
- ;; difference between the ranges of read articles in this group and
- ;; the range of active articles.
- (defun gnus-sequence-of-unread-articles (group)
- (let* ((read (gnus-info-read (gnus-get-info group)))
- (active (or (gnus-active group) (gnus-activate-group group)))
- (last (cdr active))
- (bottom (if gnus-newsgroup-maximum-articles
- (max (car active)
- (- last gnus-newsgroup-maximum-articles -1))
- (car active)))
- first nlast unread)
- ;; If none are read, then all are unread.
- (if (not read)
- (setq first bottom)
- ;; If the range of read articles is a single range, then the
- ;; first unread article is the article after the last read
- ;; article. Sounds logical, doesn't it?
- (if (and (not (listp (cdr read)))
- (or (< (car read) bottom)
- (progn (setq read (list read))
- nil)))
- (setq first (max bottom (1+ (cdr read))))
- ;; `read' is a list of ranges.
- (when (/= (setq nlast (or (and (numberp (car read)) (car read))
- (caar read)))
- 1)
- (setq first bottom))
- (while read
- (when first
- (push (cons first nlast) unread))
- (setq first (1+ (if (atom (car read)) (car read) (cdar read))))
- (setq nlast (if (atom (cadr read)) (cadr read) (caadr read)))
- (setq read (cdr read)))))
- ;; And add the last unread articles.
- (cond ((not (and first last))
- nil)
- ((< first last)
- (push (cons first last) unread))
- ((= first last)
- (push first unread)))
- ;; Return the sequence of unread articles.
- (delq 0 (nreverse unread))))
- ;; Various summary commands
- (defun gnus-summary-select-article-buffer ()
- "Reconfigure windows to show the article buffer.
- If `gnus-widen-article-window' is set, show only the article
- buffer."
- (interactive)
- (if (not (gnus-buffer-live-p gnus-article-buffer))
- (error "There is no article buffer for this summary buffer")
- (unless (get-buffer-window gnus-article-buffer)
- (gnus-summary-show-article))
- (gnus-configure-windows
- (if gnus-widen-article-window
- 'only-article
- 'article)
- t)
- (select-window (get-buffer-window gnus-article-buffer))))
- (defun gnus-summary-universal-argument (arg)
- "Perform any operation on all articles that are process/prefixed."
- (interactive "P")
- (let ((articles (gnus-summary-work-articles arg))
- func article)
- (if (eq
- (setq
- func
- (key-binding
- (read-key-sequence
- (substitute-command-keys
- "\\<gnus-summary-mode-map>\\[gnus-summary-universal-argument]"))))
- 'undefined)
- (gnus-error 1 "Undefined key")
- (save-excursion
- (while articles
- (gnus-summary-goto-subject (setq article (pop articles)))
- (let (gnus-newsgroup-processable)
- (command-execute func))
- (gnus-summary-remove-process-mark article)))))
- (gnus-summary-position-point))
- (defun gnus-summary-toggle-truncation (&optional arg)
- "Toggle truncation of summary lines.
- With ARG, turn line truncation on if ARG is positive."
- (interactive "P")
- (setq truncate-lines
- (if (null arg) (not truncate-lines)
- (> (prefix-numeric-value arg) 0)))
- (redraw-display))
- (defun gnus-summary-find-for-reselect ()
- "Return the number of an article to stay on across a reselect.
- The current article is considered, then following articles, then previous
- articles. An article is sought which is not canceled and isn't a temporary
- insertion from another group. If there's no such then return a dummy 0."
- (let (found)
- (dolist (rev '(nil t))
- (unless found ; don't demand the reverse list if we don't need it
- (let ((data (gnus-data-find-list
- (gnus-summary-article-number) (gnus-data-list rev))))
- (while (and data (not found))
- (if (and (< 0 (gnus-data-number (car data)))
- (not (eq gnus-canceled-mark (gnus-data-mark (car data)))))
- (setq found (gnus-data-number (car data))))
- (setq data (cdr data))))))
- (or found 0)))
- (defun gnus-summary-reselect-current-group (&optional all rescan)
- "Exit and then reselect the current newsgroup.
- The prefix argument ALL means to select all articles."
- (interactive "P")
- (when (gnus-ephemeral-group-p gnus-newsgroup-name)
- (error "Ephemeral groups can't be reselected"))
- (let ((current-subject (gnus-summary-find-for-reselect))
- (group gnus-newsgroup-name))
- (setq gnus-newsgroup-begin nil)
- (gnus-summary-exit nil 'leave-hidden)
- ;; We have to adjust the point of group mode buffer because
- ;; point was moved to the next unread newsgroup by exiting.
- (gnus-summary-jump-to-group group)
- (when rescan
- (save-excursion
- (gnus-group-get-new-news-this-group 1)))
- (gnus-group-read-group all t)
- (gnus-summary-goto-subject current-subject nil t)))
- (defun gnus-summary-rescan-group (&optional all)
- "Exit the newsgroup, ask for new articles, and select the newsgroup."
- (interactive "P")
- (let ((config gnus-current-window-configuration))
- (gnus-summary-reselect-current-group all t)
- (gnus-configure-windows config)
- (when (eq config 'article)
- (gnus-summary-select-article))))
- (defun gnus-summary-update-info (&optional non-destructive)
- (save-excursion
- (let ((group gnus-newsgroup-name))
- (when group
- (when gnus-newsgroup-kill-headers
- (setq gnus-newsgroup-killed
- (gnus-compress-sequence
- (gnus-sorted-union
- (gnus-list-range-intersection
- gnus-newsgroup-unselected gnus-newsgroup-killed)
- gnus-newsgroup-unreads)
- t)))
- (unless (listp (cdr gnus-newsgroup-killed))
- (setq gnus-newsgroup-killed (list gnus-newsgroup-killed)))
- (let ((headers gnus-newsgroup-headers)
- (ephemeral-p (gnus-ephemeral-group-p group))
- info)
- (unless ephemeral-p
- (setq info (copy-sequence (gnus-get-info group))
- info (delq (gnus-info-params info) info)))
- ;; Set the new ranges of read articles.
- (with-current-buffer gnus-group-buffer
- (gnus-undo-force-boundary))
- (gnus-update-read-articles
- group (gnus-sorted-union
- gnus-newsgroup-unreads gnus-newsgroup-unselected))
- ;; Set the current article marks.
- (let ((gnus-newsgroup-scored
- (if (and (not gnus-save-score)
- (not non-destructive))
- nil
- gnus-newsgroup-scored)))
- (save-excursion
- (gnus-update-marks)))
- ;; Do the cross-ref thing.
- (when gnus-use-cross-reference
- (gnus-mark-xrefs-as-read group headers gnus-newsgroup-unreads))
- ;; Do not switch windows but change the buffer to work.
- (set-buffer gnus-group-buffer)
- (unless ephemeral-p
- (gnus-group-update-group
- group nil
- (equal info
- (setq info (copy-sequence (gnus-get-info group))
- info (delq (gnus-info-params info) info))))))))))
- (defun gnus-summary-save-newsrc (&optional force)
- "Save the current number of read/marked articles in the dribble buffer.
- The dribble buffer will then be saved.
- If FORCE (the prefix), also save the .newsrc file(s)."
- (interactive "P")
- (gnus-summary-update-info t)
- (if force
- (gnus-save-newsrc-file)
- (gnus-dribble-save)))
- (declare-function gnus-cache-write-active "gnus-cache" (&optional force))
- (declare-function gnus-article-stop-animations "gnus-art" ())
- (defun gnus-summary-exit (&optional temporary leave-hidden)
- "Exit reading current newsgroup, and then return to group selection mode.
- `gnus-exit-group-hook' is called with no arguments if that value is non-nil."
- (interactive)
- (gnus-set-global-variables)
- (when (gnus-buffer-live-p gnus-article-buffer)
- (with-current-buffer gnus-article-buffer
- (mm-destroy-parts gnus-article-mime-handles)
- ;; Set it to nil for safety reason.
- (setq gnus-article-mime-handle-alist nil)
- (setq gnus-article-mime-handles nil)))
- (gnus-kill-save-kill-buffer)
- (gnus-async-halt-prefetch)
- (let* ((group gnus-newsgroup-name)
- (quit-config (gnus-group-quit-config gnus-newsgroup-name))
- (gnus-group-is-exiting-p t)
- (article-buffer gnus-article-buffer)
- (original-article-buffer gnus-original-article-buffer)
- (mode major-mode)
- (group-point nil)
- (buf (current-buffer))
- ;; `gnus-single-article-buffer' is nil buffer-locally in
- ;; ephemeral group of which summary buffer will be killed,
- ;; but the global value may be non-nil.
- (single-article-buffer gnus-single-article-buffer))
- (unless quit-config
- ;; Do adaptive scoring, and possibly save score files.
- (when gnus-newsgroup-adaptive
- (gnus-score-adaptive))
- (when gnus-use-scoring
- (gnus-score-save)))
- (gnus-run-hooks 'gnus-summary-prepare-exit-hook)
- (when gnus-use-cache
- (gnus-cache-possibly-remove-articles)
- (gnus-cache-save-buffers))
- (gnus-async-prefetch-remove-group group)
- (when gnus-suppress-duplicates
- (gnus-dup-enter-articles))
- (when gnus-use-trees
- (gnus-tree-close))
- (when gnus-use-cache
- (gnus-cache-write-active))
- ;; Remove entries for this group.
- (nnmail-purge-split-history (gnus-group-real-name group))
- ;; Make all changes in this group permanent.
- (unless quit-config
- (gnus-run-hooks 'gnus-exit-group-hook)
- (gnus-summary-update-info))
- (gnus-close-group group)
- ;; Make sure where we were, and go to next newsgroup.
- (when (buffer-live-p (get-buffer gnus-group-buffer))
- (set-buffer gnus-group-buffer))
- (unless quit-config
- (gnus-group-jump-to-group group))
- (gnus-run-hooks 'gnus-summary-exit-hook)
- (unless (or quit-config
- (not gnus-summary-next-group-on-exit)
- ;; If this group has disappeared from the summary
- ;; buffer, don't skip forwards.
- (not (string= group (gnus-group-group-name))))
- (gnus-group-next-unread-group 1))
- (setq group-point (point))
- (gnus-article-stop-animations)
- (if temporary
- nil ;Nothing to do.
- (set-buffer buf)
- (if (not gnus-kill-summary-on-exit)
- (progn
- (gnus-deaden-summary)
- (setq mode nil))
- (when (get-buffer gnus-article-buffer)
- (bury-buffer gnus-article-buffer))
- ;; Return to group mode buffer.
- (when (eq mode 'gnus-summary-mode)
- (gnus-kill-buffer buf)))
- (setq gnus-current-select-method gnus-select-method)
- (when (gnus-buffer-live-p gnus-group-buffer)
- (set-buffer gnus-group-buffer))
- (if quit-config
- (gnus-handle-ephemeral-exit quit-config)
- (goto-char group-point)
- ;; If gnus-group-buffer is already displayed, make sure we also move
- ;; the cursor in the window that displays it.
- (let ((win (get-buffer-window (current-buffer) 0)))
- (if win (set-window-point win (point))))
- (unless leave-hidden
- (gnus-configure-windows 'group 'force)))
- ;; If we have several article buffers, we kill them at exit.
- (unless single-article-buffer
- (when (gnus-buffer-live-p article-buffer)
- (with-current-buffer article-buffer
- ;; Don't kill sticky article buffers
- (unless (eq major-mode 'gnus-sticky-article-mode)
- (gnus-kill-buffer article-buffer)
- (setq gnus-article-current nil))))
- (gnus-kill-buffer original-article-buffer))
- ;; Clear the current group name.
- (unless quit-config
- (setq gnus-newsgroup-name nil)))))
- (declare-function gnus-stop-downloads "gnus-art" ())
- (defalias 'gnus-summary-quit 'gnus-summary-exit-no-update)
- (defun gnus-summary-exit-no-update (&optional no-questions)
- "Quit reading current newsgroup without updating read article info."
- (interactive)
- (let* ((group gnus-newsgroup-name)
- (gnus-group-is-exiting-p t)
- (gnus-group-is-exiting-without-update-p t)
- (quit-config (gnus-group-quit-config group)))
- (when (or no-questions
- (gnus-ephemeral-group-p group)
- gnus-expert-user
- (gnus-y-or-n-p "Discard changes to this group and exit? "))
- (gnus-async-halt-prefetch)
- (run-hooks 'gnus-summary-prepare-exit-hook)
- (when (gnus-buffer-live-p gnus-article-buffer)
- (with-current-buffer gnus-article-buffer
- (gnus-article-stop-animations)
- (gnus-stop-downloads)
- (mm-destroy-parts gnus-article-mime-handles)
- ;; Set it to nil for safety reason.
- (setq gnus-article-mime-handle-alist nil)
- (setq gnus-article-mime-handles nil)))
- ;; If we have several article buffers, we kill them at exit.
- (unless gnus-single-article-buffer
- (gnus-kill-buffer gnus-article-buffer)
- (gnus-kill-buffer gnus-original-article-buffer)
- (setq gnus-article-current nil))
- ;; Return to the group buffer.
- (if (not gnus-kill-summary-on-exit)
- (progn
- (gnus-deaden-summary)
- (gnus-configure-windows 'group 'force))
- (gnus-configure-windows 'group 'force)
- (gnus-close-group group)
- (gnus-kill-buffer gnus-summary-buffer))
- (unless gnus-single-article-buffer
- (setq gnus-article-current nil))
- (when gnus-use-trees
- (gnus-tree-close))
- (gnus-async-prefetch-remove-group group)
- (when (get-buffer gnus-article-buffer)
- (bury-buffer gnus-article-buffer))
- ;; Clear the current group name.
- (setq gnus-newsgroup-name nil)
- (unless (gnus-ephemeral-group-p group)
- (gnus-group-update-group group nil t))
- (when (equal (gnus-group-group-name) group)
- (gnus-group-next-unread-group 1))
- (gnus-article-stop-animations)
- (when quit-config
- (gnus-handle-ephemeral-exit quit-config)))))
- (defun gnus-handle-ephemeral-exit (quit-config)
- "Handle movement when leaving an ephemeral group.
- The state which existed when entering the ephemeral is reset."
- (if (not (buffer-live-p (car quit-config)))
- (when (gnus-buffer-live-p gnus-group-buffer)
- (gnus-configure-windows 'group 'force))
- (set-buffer (car quit-config))
- (unless (eq (cdr quit-config) 'group)
- (setq gnus-current-select-method
- (gnus-find-method-for-group gnus-newsgroup-name)))
- (cond ((derived-mode-p 'gnus-summary-mode)
- (gnus-set-global-variables))
- ((derived-mode-p 'gnus-article-mode)
- (save-current-buffer
- ;; The `gnus-summary-buffer' variable may point
- ;; to the old summary buffer when using a single
- ;; article buffer.
- (unless (gnus-buffer-live-p gnus-summary-buffer)
- (set-buffer gnus-group-buffer))
- (set-buffer gnus-summary-buffer)
- (gnus-set-global-variables))))
- (if (or (eq (cdr quit-config) 'article)
- (eq (cdr quit-config) 'pick))
- (if (and (boundp 'gnus-pick-mode) (symbol-value 'gnus-pick-mode))
- (gnus-configure-windows 'pick 'force)
- (gnus-configure-windows (cdr quit-config) 'force))
- (gnus-configure-windows (cdr quit-config) 'force))
- (when (derived-mode-p 'gnus-summary-mode)
- (if (memq gnus-auto-select-on-ephemeral-exit '(next-noselect
- next-unread-noselect))
- (when (zerop (cond ((eq gnus-auto-select-on-ephemeral-exit
- 'next-noselect)
- (gnus-summary-next-subject 1 nil t))
- ((eq gnus-auto-select-on-ephemeral-exit
- 'next-unread-noselect)
- (gnus-summary-next-subject 1 t t))))
- ;; Hide the article buffer which displays the article different
- ;; from the one that the cursor points to in the summary buffer.
- (gnus-configure-windows 'summary 'force))
- (cond ((eq gnus-auto-select-on-ephemeral-exit 'next)
- (gnus-summary-next-subject 1))
- ((eq gnus-auto-select-on-ephemeral-exit 'next-unread)
- (gnus-summary-next-subject 1 t))))
- (gnus-summary-recenter)
- (gnus-summary-position-point))))
- ;;; Dead summaries.
- (defvar gnus-dead-summary-mode-map
- (let ((map (make-keymap)))
- (suppress-keymap map)
- (substitute-key-definition 'undefined 'gnus-summary-wake-up-the-dead map)
- (dolist (key '("\C-d" "\r" "\177" [delete]))
- (define-key map key 'gnus-summary-wake-up-the-dead))
- (dolist (key '("q" "Q"))
- (define-key map key 'bury-buffer))
- map))
- (define-minor-mode gnus-dead-summary-mode
- "Minor mode for Gnus summary buffers."
- :lighter " Dead" :keymap gnus-dead-summary-mode-map
- (unless (derived-mode-p 'gnus-summary-mode)
- (setq gnus-dead-summary-mode nil)))
- (defun gnus-deaden-summary ()
- "Make the current summary buffer into a dead summary buffer."
- ;; Kill any previous dead summary buffer.
- (when (and gnus-dead-summary
- (buffer-name gnus-dead-summary))
- (with-current-buffer gnus-dead-summary
- (when gnus-dead-summary-mode
- (kill-buffer (current-buffer)))))
- ;; Make this the current dead summary.
- (setq gnus-dead-summary (current-buffer))
- (gnus-dead-summary-mode 1)
- (let ((name (buffer-name)))
- (when (string-match "Summary" name)
- (rename-buffer
- (concat (substring name 0 (match-beginning 0)) "Dead "
- (substring name (match-beginning 0)))
- t)
- (bury-buffer))))
- (defun gnus-kill-or-deaden-summary (buffer)
- "Kill or deaden the summary BUFFER."
- (save-excursion
- (when (and (buffer-name buffer)
- (not gnus-single-article-buffer))
- (with-current-buffer buffer
- (gnus-kill-buffer gnus-article-buffer)
- (gnus-kill-buffer gnus-original-article-buffer)))
- (cond
- ;; Kill the buffer.
- (gnus-kill-summary-on-exit
- (when (and gnus-use-trees
- (gnus-buffer-exists-p buffer))
- (with-current-buffer buffer
- (gnus-tree-close)))
- (gnus-kill-buffer buffer))
- ;; Deaden the buffer.
- ((gnus-buffer-exists-p buffer)
- (with-current-buffer buffer
- (gnus-deaden-summary))))))
- (defun gnus-summary-wake-up-the-dead (&rest args)
- "Wake up the dead summary buffer."
- (interactive)
- (gnus-dead-summary-mode -1)
- (let ((name (buffer-name)))
- (when (string-match "Dead " name)
- (rename-buffer
- (concat (substring name 0 (match-beginning 0))
- (substring name (match-end 0)))
- t)))
- (gnus-message 3 "This dead summary is now alive again"))
- ;; Suggested by Per Abrahamsen <amanda@iesd.auc.dk>.
- (defun gnus-summary-describe-group (&optional force)
- "Describe the current newsgroup."
- (interactive "P")
- (gnus-group-describe-group force gnus-newsgroup-name))
- (defun gnus-summary-describe-briefly ()
- "Describe summary mode commands briefly."
- (interactive)
- (gnus-message 6 "%s" (substitute-command-keys "\\<gnus-summary-mode-map>\\[gnus-summary-next-page]:Select \\[gnus-summary-next-unread-article]:Forward \\[gnus-summary-prev-unread-article]:Backward \\[gnus-summary-exit]:Exit \\[gnus-info-find-node]:Run Info \\[gnus-summary-describe-briefly]:This help")))
- ;; Walking around group mode buffer from summary mode.
- (defun gnus-summary-next-group (&optional no-article target-group backward)
- "Exit current newsgroup and then select next unread newsgroup.
- If prefix argument NO-ARTICLE is non-nil, no article is selected
- initially. If TARGET-GROUP, go to this group. If BACKWARD, go to
- previous group instead."
- (interactive "P")
- ;; Stop pre-fetching.
- (gnus-async-halt-prefetch)
- (let ((current-group gnus-newsgroup-name)
- (current-buffer (current-buffer))
- entered)
- ;; First we semi-exit this group to update Xrefs and all variables.
- ;; We can't do a real exit, because the window conf must remain
- ;; the same in case the user is prompted for info, and we don't
- ;; want the window conf to change before that...
- (gnus-summary-exit t)
- (while (not entered)
- ;; Then we find what group we are supposed to enter.
- (set-buffer gnus-group-buffer)
- (gnus-group-jump-to-group current-group)
- (setq target-group
- (or target-group
- (if (eq gnus-keep-same-level 'best)
- (gnus-summary-best-group gnus-newsgroup-name)
- (gnus-summary-search-group backward gnus-keep-same-level))))
- (if (not target-group)
- ;; There are no further groups, so we return to the group
- ;; buffer.
- (progn
- (gnus-message 5 "Returning to the group buffer")
- (setq entered t)
- (when (gnus-buffer-live-p current-buffer)
- (set-buffer current-buffer)
- (gnus-summary-exit))
- (gnus-run-hooks 'gnus-group-no-more-groups-hook))
- ;; We try to enter the target group.
- (gnus-group-jump-to-group target-group)
- (let ((unreads (gnus-group-group-unread)))
- (if (and (or (eq t unreads)
- (and unreads (not (zerop unreads))))
- (gnus-summary-read-group
- target-group nil no-article
- (and (buffer-name current-buffer) current-buffer)
- nil backward))
- (setq entered t)
- (setq current-group target-group
- target-group nil)))))))
- (defun gnus-summary-prev-group (&optional no-article)
- "Exit current newsgroup and then select previous unread newsgroup.
- If prefix argument NO-ARTICLE is non-nil, no article is selected initially."
- (interactive "P")
- (gnus-summary-next-group no-article nil t))
- ;; Walking around summary lines.
- (defun gnus-summary-first-subject (&optional unread undownloaded unseen)
- "Go to the first subject satisfying any non-nil constraint.
- If UNREAD is non-nil, the article should be unread.
- If UNDOWNLOADED is non-nil, the article should be undownloaded.
- If UNSEEN is non-nil, the article should be unseen as well as unread.
- Returns the article selected or nil if there are no matching articles."
- (interactive "P")
- (cond
- ;; Empty summary.
- ((null gnus-newsgroup-data)
- (gnus-message 3 "No articles in the group")
- nil)
- ;; Pick the first article.
- ((not (or unread undownloaded unseen))
- (goto-char (gnus-data-pos (car gnus-newsgroup-data)))
- (gnus-data-number (car gnus-newsgroup-data)))
- ;; Find the first unread article.
- (t
- (let ((data gnus-newsgroup-data))
- (while (and data
- (let ((num (gnus-data-number (car data))))
- (or (memq num gnus-newsgroup-unfetched)
- (not (or (and unread
- (memq num gnus-newsgroup-unreads))
- (and undownloaded
- (memq num gnus-newsgroup-undownloaded))
- (and unseen
- (memq num gnus-newsgroup-unseen)
- (memq num gnus-newsgroup-unreads)))))))
- (setq data (cdr data)))
- (prog1
- (if data
- (progn
- (goto-char (gnus-data-pos (car data)))
- (gnus-data-number (car data)))
- (gnus-message 3 "No more%s articles"
- (let* ((r (when unread " unread"))
- (d (when undownloaded " undownloaded"))
- (s (when unseen " unseen"))
- (l (delq nil (list r d s))))
- (cond ((= 3 (length l))
- (concat r "," d ", or" s))
- ((= 2 (length l))
- (concat (car l) ", or" (cadr l)))
- ((= 1 (length l))
- (car l))
- (t
- ""))))
- nil
- )
- (gnus-summary-position-point))))))
- (defun gnus-summary-next-subject (n &optional unread dont-display)
- "Go to next N'th summary line.
- If N is negative, go to the previous N'th subject line.
- If UNREAD is non-nil, only unread articles are selected.
- The difference between N and the actual number of steps taken is
- returned."
- (interactive "p")
- (let ((backward (< n 0))
- (n (abs n)))
- (while (and (> n 0)
- (if backward
- (gnus-summary-find-prev unread)
- (gnus-summary-find-next unread)))
- (unless (zerop (setq n (1- n)))
- (gnus-summary-show-thread)))
- (when (/= 0 n)
- (gnus-message 7 "No more%s articles"
- (if unread " unread" "")))
- (unless dont-display
- (gnus-summary-recenter)
- (gnus-summary-position-point))
- n))
- (defun gnus-summary-next-unread-subject (n)
- "Go to next N'th unread summary line."
- (interactive "p")
- (gnus-summary-next-subject n t))
- (defun gnus-summary-prev-subject (n &optional unread)
- "Go to previous N'th summary line.
- If optional argument UNREAD is non-nil, only unread article is selected."
- (interactive "p")
- (gnus-summary-next-subject (- n) unread))
- (defun gnus-summary-prev-unread-subject (n)
- "Go to previous N'th unread summary line."
- (interactive "p")
- (gnus-summary-next-subject (- n) t))
- (defun gnus-summary-goto-subjects (articles)
- "Insert the subject header for ARTICLES in the current buffer."
- (save-excursion
- (dolist (article articles)
- (gnus-summary-goto-subject article t)))
- (gnus-summary-limit (append articles gnus-newsgroup-limit))
- (gnus-summary-position-point))
- (defun gnus-summary-goto-subject (article &optional force silent)
- "Go to the subject line of ARTICLE.
- If FORCE, also allow jumping to articles not currently shown."
- (interactive "nArticle number: ")
- (unless (numberp article)
- (error "Article %s is not a number" article))
- (let ((b (point))
- (data (gnus-data-find article)))
- ;; We read in the article if we have to.
- (and (not data)
- force
- (gnus-summary-insert-subject
- article
- (if (or (numberp force) (vectorp force)) force)
- t)
- (setq data (gnus-data-find article)))
- (goto-char b)
- (if (not data)
- (progn
- (unless silent
- (gnus-message 3 "Can't find article %d" article))
- nil)
- (let ((pt (gnus-data-pos data)))
- (goto-char pt)
- (gnus-summary-set-article-display-arrow pt))
- (gnus-summary-position-point)
- article)))
- ;; Walking around summary lines with displaying articles.
- (defun gnus-summary-expand-window (&optional arg)
- "Make the summary buffer take up the entire Emacs frame.
- Given a prefix, will force an `article' buffer configuration."
- (interactive "P")
- (if arg
- (gnus-configure-windows 'article 'force)
- (gnus-configure-windows 'summary 'force)))
- (defun gnus-summary-display-article (article &optional all-header)
- "Display ARTICLE in article buffer."
- (unless (and (gnus-buffer-live-p gnus-article-buffer)
- (with-current-buffer gnus-article-buffer
- (derived-mode-p 'gnus-article-mode)))
- (gnus-article-setup-buffer))
- (gnus-set-global-variables)
- (with-current-buffer gnus-article-buffer
- (setq gnus-article-charset gnus-newsgroup-charset)
- (setq gnus-article-ignored-charsets gnus-newsgroup-ignored-charsets)
- (mm-enable-multibyte))
- (if (null article)
- nil
- (prog1
- (if gnus-summary-display-article-function
- (funcall gnus-summary-display-article-function article all-header)
- (gnus-article-prepare article all-header))
- (gnus-run-hooks 'gnus-select-article-hook)
- (when (and gnus-current-article
- (not (zerop gnus-current-article)))
- (gnus-summary-goto-subject gnus-current-article))
- (gnus-summary-recenter)
- (when (and gnus-use-trees gnus-show-threads)
- (gnus-possibly-generate-tree article)
- (gnus-highlight-selected-tree article))
- ;; Successfully display article.
- (gnus-article-set-window-start
- (cdr (assq article gnus-newsgroup-bookmarks))))))
- (defun gnus-summary-select-article (&optional all-headers force pseudo article)
- "Select the current article.
- If ALL-HEADERS is non-nil, show all header fields. If FORCE is
- non-nil, the article will be re-fetched even if it already present in
- the article buffer. If PSEUDO is non-nil, pseudo-articles will also
- be displayed."
- ;; Make sure we are in the summary buffer to work around bbdb bug.
- (unless (derived-mode-p 'gnus-summary-mode)
- (set-buffer gnus-summary-buffer))
- (let ((article (or article (gnus-summary-article-number)))
- (all-headers (not (not all-headers))) ;Must be t or nil.
- gnus-summary-display-article-function)
- (and (not pseudo)
- (gnus-summary-article-pseudo-p article)
- (error "This is a pseudo-article"))
- (with-current-buffer gnus-summary-buffer
- (if (or (and gnus-single-article-buffer
- (or (null gnus-current-article)
- (null gnus-article-current)
- (null (get-buffer gnus-article-buffer))
- (not (eq article (cdr gnus-article-current)))
- (not (equal (car gnus-article-current)
- gnus-newsgroup-name))
- (not (get-buffer gnus-original-article-buffer))))
- (and (not gnus-single-article-buffer)
- (or (null gnus-current-article)
- (not (get-buffer gnus-original-article-buffer))
- (not (eq gnus-current-article article))))
- force)
- ;; The requested article is different from the current article.
- (progn
- (gnus-summary-display-article article all-headers)
- (when (gnus-buffer-live-p gnus-article-buffer)
- (with-current-buffer gnus-article-buffer
- (if (not gnus-article-decoded-p) ;; a local variable
- (mm-disable-multibyte))))
- (gnus-article-set-window-start
- (cdr (assq article gnus-newsgroup-bookmarks)))
- article)
- 'old))))
- (defun gnus-summary-force-verify-and-decrypt ()
- "Display buttons for signed/encrypted parts and verify/decrypt them."
- (interactive)
- (let ((mm-verify-option 'known)
- (mm-decrypt-option 'known)
- (gnus-article-emulate-mime t)
- (gnus-buttonized-mime-types (append (list "multipart/signed"
- "multipart/encrypted")
- gnus-buttonized-mime-types)))
- (gnus-summary-select-article nil 'force)))
- (defun gnus-summary-next-article (&optional unread subject backward push)
- "Select the next article.
- If UNREAD, only unread articles are selected.
- If SUBJECT, only articles with SUBJECT are selected.
- If BACKWARD, the previous article is selected instead of the next."
- (interactive "P")
- ;; Make sure we are in the summary buffer.
- (unless (derived-mode-p 'gnus-summary-mode)
- (set-buffer gnus-summary-buffer))
- (cond
- ;; Is there such an article?
- ((and (gnus-summary-search-forward unread subject backward)
- (or (gnus-summary-display-article (gnus-summary-article-number))
- (eq (gnus-summary-article-mark) gnus-canceled-mark)))
- (gnus-summary-position-point))
- ;; If not, we try the first unread, if that is wanted.
- ((and subject
- gnus-auto-select-same
- (gnus-summary-first-unread-article))
- (gnus-summary-position-point)
- (gnus-message 6 "Wrapped"))
- ;; Try to get next/previous article not displayed in this group.
- ((and gnus-auto-extend-newsgroup
- (not unread) (not subject))
- (gnus-summary-goto-article
- (if backward (1- gnus-newsgroup-begin) (1+ gnus-newsgroup-end))
- nil (count-lines (point-min) (point))))
- ;; Go to next/previous group.
- (t
- (unless (gnus-ephemeral-group-p gnus-newsgroup-name)
- (gnus-summary-jump-to-group gnus-newsgroup-name))
- (let ((cmd (if (featurep 'xemacs)
- last-command-char
- last-command-event))
- (point
- (with-current-buffer gnus-group-buffer
- (point)))
- (current-summary (current-buffer))
- (group
- (if (eq gnus-keep-same-level 'best)
- (gnus-summary-best-group gnus-newsgroup-name)
- (gnus-summary-search-group backward gnus-keep-same-level))))
- ;; Select next unread newsgroup automagically.
- (cond
- ((or (not gnus-auto-select-next)
- (not cmd))
- (gnus-message 7 "No more%s articles" (if unread " unread" "")))
- ((or (eq gnus-auto-select-next 'quietly)
- (and (eq gnus-auto-select-next 'slightly-quietly)
- push)
- (and (eq gnus-auto-select-next 'almost-quietly)
- (gnus-summary-last-article-p)))
- ;; Select quietly.
- (if (gnus-ephemeral-group-p gnus-newsgroup-name)
- (gnus-summary-exit)
- (gnus-message 7 "No more%s articles (%s)..."
- (if unread " unread" "")
- (if group (concat "selecting " group)
- "exiting"))
- (gnus-summary-next-group nil group backward)))
- (t
- (when (gnus-key-press-event-p last-input-event)
- ;; Somehow or other, we may now have selected a different
- ;; window. Make point go back to the summary buffer.
- (when (eq current-summary (current-buffer))
- ;; FIXME: This burps when get-buffer-window returns nil.
- (select-window (get-buffer-window current-summary 0)))
- (gnus-summary-walk-group-buffer
- gnus-newsgroup-name cmd unread backward point))))))))
- (defun gnus-summary-walk-group-buffer (from-group cmd unread backward start)
- (let ((keystrokes '((?\C-n (gnus-group-next-unread-group 1))
- (?\C-p (gnus-group-prev-unread-group 1))))
- (cursor-in-echo-area t)
- keve key group ended prompt)
- (with-current-buffer gnus-group-buffer
- (goto-char start)
- (setq group
- (if (eq gnus-keep-same-level 'best)
- (gnus-summary-best-group gnus-newsgroup-name)
- (gnus-summary-search-group backward gnus-keep-same-level))))
- (while (not ended)
- (setq prompt
- (format
- "No more%s articles%s " (if unread " unread" "")
- (if (and group
- (not (gnus-ephemeral-group-p gnus-newsgroup-name)))
- (format " (Type %s for %s [%s])"
- (single-key-description cmd)
- (gnus-group-decoded-name group)
- (gnus-group-unread group))
- (format " (Type %s to exit %s)"
- (single-key-description cmd)
- (gnus-group-decoded-name gnus-newsgroup-name)))))
- ;; Confirm auto selection.
- (setq key (car (setq keve (gnus-read-event-char prompt)))
- ended t)
- (cond
- ((assq key keystrokes)
- (let ((obuf (current-buffer)))
- (switch-to-buffer gnus-group-buffer)
- (when group
- (gnus-group-jump-to-group group))
- (eval (cadr (assq key keystrokes)))
- (setq group (gnus-group-group-name))
- (switch-to-buffer obuf))
- (setq ended nil))
- ((equal key cmd)
- (if (or (not group)
- (gnus-ephemeral-group-p gnus-newsgroup-name))
- (gnus-summary-exit)
- (gnus-summary-next-group nil group backward)))
- (t
- (push (cdr keve) unread-command-events))))))
- (defun gnus-summary-next-unread-article ()
- "Select unread article after current one."
- (interactive)
- (gnus-summary-next-article
- (or (not (eq gnus-summary-goto-unread 'never))
- (gnus-summary-last-article-p (gnus-summary-article-number)))
- (and gnus-auto-select-same
- (gnus-summary-article-subject))))
- (defun gnus-summary-prev-article (&optional unread subject)
- "Select the article before the current one.
- If UNREAD is non-nil, only unread articles are selected."
- (interactive "P")
- (gnus-summary-next-article unread subject t))
- (defun gnus-summary-prev-unread-article ()
- "Select unread article before current one."
- (interactive)
- (gnus-summary-prev-article
- (or (not (eq gnus-summary-goto-unread 'never))
- (gnus-summary-first-article-p (gnus-summary-article-number)))
- (and gnus-auto-select-same
- (gnus-summary-article-subject))))
- (declare-function gnus-article-only-boring-p "gnus-art" ())
- (defun gnus-summary-next-page (&optional lines circular stop)
- "Show next page of the selected article.
- If at the end of the current article, select the next article.
- LINES says how many lines should be scrolled up.
- If CIRCULAR is non-nil, go to the start of the article instead of
- selecting the next article when reaching the end of the current
- article.
- If STOP is non-nil, just stop when reaching the end of the message.
- Also see the variable `gnus-article-skip-boring'."
- (interactive "P")
- (gnus-set-global-variables)
- (let ((article (gnus-summary-article-number))
- (article-window (get-buffer-window gnus-article-buffer t))
- endp)
- ;; If the buffer is empty, we have no article.
- (unless article
- (error "No article to select"))
- (gnus-configure-windows 'article)
- (if (eq (cdr (assq article gnus-newsgroup-reads)) gnus-canceled-mark)
- (if (and (eq gnus-summary-goto-unread 'never)
- (not (gnus-summary-last-article-p article)))
- (gnus-summary-next-article)
- (gnus-summary-next-unread-article))
- (if (or (null gnus-current-article)
- (null gnus-article-current)
- (/= article (cdr gnus-article-current))
- (not (equal (car gnus-article-current) gnus-newsgroup-name)))
- ;; Selected subject is different from current article's.
- (gnus-summary-display-article article)
- (when article-window
- (gnus-eval-in-buffer-window gnus-article-buffer
- (setq endp (or (gnus-article-next-page lines)
- (gnus-article-only-boring-p))))
- (when endp
- (cond ((or stop gnus-summary-stop-at-end-of-message)
- (gnus-message 3 "End of message"))
- (circular
- (gnus-summary-beginning-of-article))
- (lines
- (gnus-message 3 "End of message"))
- ((null lines)
- (if (and (eq gnus-summary-goto-unread 'never)
- (not (gnus-summary-last-article-p article)))
- (gnus-summary-next-article)
- (gnus-summary-next-unread-article))))))))
- (gnus-summary-recenter)
- (gnus-summary-position-point)))
- (defun gnus-summary-prev-page (&optional lines move)
- "Show previous page of selected article.
- Argument LINES specifies lines to be scrolled down.
- If MOVE, move to the previous unread article if point is at
- the beginning of the buffer."
- (interactive "P")
- (let ((article (gnus-summary-article-number))
- (article-window (get-buffer-window gnus-article-buffer t))
- endp)
- (gnus-configure-windows 'article)
- (if (or (null gnus-current-article)
- (null gnus-article-current)
- (/= article (cdr gnus-article-current))
- (not (equal (car gnus-article-current) gnus-newsgroup-name)))
- ;; Selected subject is different from current article's.
- (gnus-summary-display-article article)
- (gnus-summary-recenter)
- (when article-window
- (gnus-eval-in-buffer-window gnus-article-buffer
- (setq endp (gnus-article-prev-page lines)))
- (when (and move endp)
- (cond (lines
- (gnus-message 3 "Beginning of message"))
- ((null lines)
- (if (and (eq gnus-summary-goto-unread 'never)
- (not (gnus-summary-first-article-p article)))
- (gnus-summary-prev-article)
- (gnus-summary-prev-unread-article))))))))
- (gnus-summary-position-point))
- (defun gnus-summary-prev-page-or-article (&optional lines)
- "Show previous page of selected article.
- Argument LINES specifies lines to be scrolled down.
- If at the beginning of the article, go to the next article."
- (interactive "P")
- (gnus-summary-prev-page lines t))
- (defun gnus-summary-scroll-up (lines)
- "Scroll up (or down) one line current article.
- Argument LINES specifies lines to be scrolled up (or down if negative).
- If no article is selected, then the current article will be selected first."
- (interactive "p")
- (gnus-configure-windows 'article)
- (gnus-summary-show-thread)
- (when (eq (gnus-summary-select-article nil nil 'pseudo) 'old)
- (gnus-eval-in-buffer-window gnus-article-buffer
- (cond ((> lines 0)
- (when (gnus-article-next-page lines)
- (gnus-message 3 "End of message")))
- ((< lines 0)
- (gnus-article-prev-page (- lines))))))
- (gnus-summary-recenter)
- (gnus-summary-position-point))
- (defun gnus-summary-scroll-down (lines)
- "Scroll down (or up) one line current article.
- Argument LINES specifies lines to be scrolled down (or up if negative).
- If no article is selected, then the current article will be selected first."
- (interactive "p")
- (gnus-summary-scroll-up (- lines)))
- (defun gnus-summary-next-same-subject ()
- "Select next article which has the same subject as current one."
- (interactive)
- (gnus-summary-next-article nil (gnus-summary-article-subject)))
- (defun gnus-summary-prev-same-subject ()
- "Select previous article which has the same subject as current one."
- (interactive)
- (gnus-summary-prev-article nil (gnus-summary-article-subject)))
- (defun gnus-summary-next-unread-same-subject ()
- "Select next unread article which has the same subject as current one."
- (interactive)
- (gnus-summary-next-article t (gnus-summary-article-subject)))
- (defun gnus-summary-prev-unread-same-subject ()
- "Select previous unread article which has the same subject as current one."
- (interactive)
- (gnus-summary-prev-article t (gnus-summary-article-subject)))
- (defun gnus-summary-first-unread-article ()
- "Select the first unread article.
- Return nil if there are no unread articles."
- (interactive)
- (prog1
- (when (gnus-summary-first-subject t)
- (gnus-summary-show-thread)
- (gnus-summary-first-subject t)
- (gnus-summary-display-article (gnus-summary-article-number)))
- (gnus-summary-position-point)))
- (defun gnus-summary-first-unread-subject ()
- "Place the point on the subject line of the first unread article.
- Return nil if there are no unread articles."
- (interactive)
- (prog1
- (when (gnus-summary-first-subject t)
- (gnus-summary-show-thread)
- (gnus-summary-first-subject t))
- (gnus-summary-position-point)))
- (defun gnus-summary-first-unseen-subject ()
- "Place the point on the subject line of the first unseen article.
- Return nil if there are no unseen articles."
- (interactive)
- (prog1
- (when (gnus-summary-first-subject nil nil t)
- (gnus-summary-show-thread)
- (gnus-summary-first-subject nil nil t))
- (gnus-summary-position-point)))
- (defun gnus-summary-first-unseen-or-unread-subject ()
- "Place the point on the subject line of the first unseen and unread article.
- If all article have been seen, on the subject line of the first unread
- article."
- (interactive)
- (prog1
- (unless (when (gnus-summary-first-subject nil nil t)
- (gnus-summary-show-thread)
- (gnus-summary-first-subject nil nil t))
- (when (gnus-summary-first-subject t)
- (gnus-summary-show-thread)
- (gnus-summary-first-subject t)))
- (gnus-summary-position-point)))
- (defun gnus-summary-first-article ()
- "Select the first article.
- Return nil if there are no articles."
- (interactive)
- (prog1
- (when (gnus-summary-first-subject)
- (gnus-summary-show-thread)
- (gnus-summary-first-subject)
- (gnus-summary-display-article (gnus-summary-article-number)))
- (gnus-summary-position-point)))
- (defun gnus-summary-best-unread-article (&optional arg)
- "Select the unread article with the highest score.
- If given a prefix argument, select the next unread article that has a
- score higher than the default score."
- (interactive "P")
- (let ((article (if arg
- (gnus-summary-better-unread-subject)
- (gnus-summary-best-unread-subject))))
- (if article
- (gnus-summary-goto-article article)
- (error "No unread articles"))))
- (defun gnus-summary-best-unread-subject ()
- "Select the unread subject with the highest score."
- (interactive)
- (let ((best -1000000)
- (data gnus-newsgroup-data)
- article score)
- (while data
- (and (gnus-data-unread-p (car data))
- (> (setq score
- (gnus-summary-article-score (gnus-data-number (car data))))
- best)
- (setq best score
- article (gnus-data-number (car data))))
- (setq data (cdr data)))
- (when article
- (gnus-summary-goto-subject article))
- (gnus-summary-position-point)
- article))
- (defun gnus-summary-better-unread-subject ()
- "Select the first unread subject that has a score over the default score."
- (interactive)
- (let ((data gnus-newsgroup-data)
- article score)
- (while (and (setq article (gnus-data-number (car data)))
- (or (gnus-data-read-p (car data))
- (not (> (gnus-summary-article-score article)
- gnus-summary-default-score))))
- (setq data (cdr data)))
- (when article
- (gnus-summary-goto-subject article))
- (gnus-summary-position-point)
- article))
- (defun gnus-summary-last-subject ()
- "Go to the last displayed subject line in the group."
- (let ((article (gnus-data-number (car (gnus-data-list t)))))
- (when article
- (gnus-summary-goto-subject article))))
- (defun gnus-summary-goto-article (article &optional all-headers force)
- "Fetch ARTICLE (article number or Message-ID) and display it if it exists.
- If ALL-HEADERS is non-nil, no header lines are hidden.
- If FORCE, go to the article even if it isn't displayed. If FORCE
- is a number, it is the line the article is to be displayed on."
- (interactive
- (list
- (gnus-completing-read
- "Article number or Message-ID"
- (mapcar 'int-to-string gnus-newsgroup-limit))
- current-prefix-arg
- t))
- (prog1
- (if (and (stringp article)
- (string-match "@\\|%40" article))
- (gnus-summary-refer-article article)
- (when (stringp article)
- (setq article (string-to-number article)))
- (if (gnus-summary-goto-subject article force)
- (gnus-summary-display-article article all-headers)
- (gnus-message 4 "Couldn't go to article %s" article) nil))
- (gnus-summary-position-point)))
- (defun gnus-summary-goto-last-article ()
- "Go to the previously read article."
- (interactive)
- (prog1
- (when gnus-last-article
- (gnus-summary-goto-article gnus-last-article nil t))
- (gnus-summary-position-point)))
- (defun gnus-summary-pop-article (number)
- "Pop one article off the history and go to the previous.
- NUMBER articles will be popped off."
- (interactive "p")
- (let (to)
- (setq gnus-newsgroup-history
- (cdr (setq to (nthcdr number gnus-newsgroup-history))))
- (if to
- (gnus-summary-goto-article (car to) nil t)
- (error "Article history empty")))
- (gnus-summary-position-point))
- ;; Summary commands and functions for limiting the summary buffer.
- (defun gnus-summary-limit-to-articles (n)
- "Limit the summary buffer to the next N articles.
- If not given a prefix, use the process marked articles instead."
- (interactive "P")
- (prog1
- (let ((articles (gnus-summary-work-articles n)))
- (setq gnus-newsgroup-processable nil)
- (gnus-summary-limit articles))
- (gnus-summary-position-point)))
- (defun gnus-summary-pop-limit (&optional total)
- "Restore the previous limit.
- If given a prefix, remove all limits."
- (interactive "P")
- (when total
- (setq gnus-newsgroup-limits
- (list (mapcar (lambda (h) (mail-header-number h))
- gnus-newsgroup-headers))))
- (unless gnus-newsgroup-limits
- (error "No limit to pop"))
- (prog1
- (gnus-summary-limit nil 'pop)
- (gnus-summary-position-point)))
- (defun gnus-summary-limit-to-subject (subject &optional header not-matching)
- "Limit the summary buffer to articles that have subjects that match a regexp.
- If NOT-MATCHING, excluding articles that have subjects that match a regexp."
- (interactive
- (list (read-string (if current-prefix-arg
- "Exclude subject (regexp): "
- "Limit to subject (regexp): "))
- nil current-prefix-arg))
- (unless header
- (setq header "subject"))
- (when (not (equal "" subject))
- (prog1
- (let ((articles (gnus-summary-find-matching
- (or header "subject") subject 'all nil nil
- not-matching)))
- (unless articles
- (error "Found no matches for \"%s\"" subject))
- (gnus-summary-limit articles))
- (gnus-summary-position-point))))
- (defun gnus-summary-limit-to-author (from &optional not-matching)
- "Limit the summary buffer to articles that have authors that match a regexp.
- If NOT-MATCHING, excluding articles that have authors that match a regexp."
- (interactive
- (list (let* ((header (gnus-summary-article-header))
- (default (and header (car (mail-header-parse-address
- (mail-header-from header))))))
- (read-string (concat (if current-prefix-arg
- "Exclude author (regexp"
- "Limit to author (regexp")
- (if default
- (concat ", default \"" default "\"): ")
- "): "))
- nil nil
- default))
- current-prefix-arg))
- (gnus-summary-limit-to-subject from "from" not-matching))
- (defun gnus-summary-limit-to-recipient (recipient &optional not-matching)
- "Limit the summary buffer to articles with the given RECIPIENT.
- If NOT-MATCHING, exclude RECIPIENT.
- To and Cc headers are checked. You need to include them in
- `nnmail-extra-headers'."
- ;; Unlike `rmail-summary-by-recipients', doesn't include From.
- (interactive
- (list (read-string (format "%s recipient (regexp): "
- (if current-prefix-arg "Exclude" "Limit to")))
- current-prefix-arg))
- (when (not (equal "" recipient))
- (prog1 (let* ((to
- (if (memq 'To nnmail-extra-headers)
- (gnus-summary-find-matching
- (cons 'extra 'To) recipient 'all nil nil
- not-matching)
- (gnus-message
- 1 "`To' isn't present in `nnmail-extra-headers'")
- (sit-for 1)
- nil))
- (cc
- (if (memq 'Cc nnmail-extra-headers)
- (gnus-summary-find-matching
- (cons 'extra 'Cc) recipient 'all nil nil
- not-matching)
- (gnus-message
- 1 "`Cc' isn't present in `nnmail-extra-headers'")
- (sit-for 1)
- nil))
- (articles
- (if not-matching
- ;; We need the numbers that are in both lists:
- (mapcar (lambda (a)
- (and (memq a to) a))
- cc)
- (nconc to cc))))
- (unless articles
- (error "Found no matches for \"%s\"" recipient))
- (gnus-summary-limit articles))
- (gnus-summary-position-point))))
- (defun gnus-summary-limit-to-address (address &optional not-matching)
- "Limit the summary buffer to articles with the given ADDRESS.
- If NOT-MATCHING, exclude ADDRESS.
- To, Cc and From headers are checked. You need to include `To' and `Cc'
- in `nnmail-extra-headers'."
- (interactive
- (list (read-string (format "%s address (regexp): "
- (if current-prefix-arg "Exclude" "Limit to")))
- current-prefix-arg))
- (when (not (equal "" address))
- (prog1 (let* ((to
- (if (memq 'To nnmail-extra-headers)
- (gnus-summary-find-matching
- (cons 'extra 'To) address 'all nil nil
- not-matching)
- (gnus-message
- 1 "`To' isn't present in `nnmail-extra-headers'")
- (sit-for 1)
- t))
- (cc
- (if (memq 'Cc nnmail-extra-headers)
- (gnus-summary-find-matching
- (cons 'extra 'Cc) address 'all nil nil
- not-matching)
- (gnus-message
- 1 "`Cc' isn't present in `nnmail-extra-headers'")
- (sit-for 1)
- t))
- (from
- (gnus-summary-find-matching "from" address
- 'all nil nil not-matching))
- (articles
- (if not-matching
- ;; We need the numbers that are in all lists:
- (if (eq cc t)
- (if (eq to t)
- from
- (mapcar (lambda (a) (car (memq a from))) to))
- (if (eq to t)
- (mapcar (lambda (a) (car (memq a from))) cc)
- (mapcar (lambda (a) (car (memq a from)))
- (mapcar (lambda (a) (car (memq a to)))
- cc))))
- (nconc (if (eq to t) nil to)
- (if (eq cc t) nil cc)
- from))))
- (unless articles
- (error "Found no matches for \"%s\"" address))
- (gnus-summary-limit articles))
- (gnus-summary-position-point))))
- (defun gnus-summary-limit-strange-charsets-predicate (header)
- (when (fboundp 'char-charset)
- (let ((string (concat (mail-header-subject header)
- (mail-header-from header)))
- charset found)
- (dotimes (i (1- (length string)))
- (setq charset (format "%s" (char-charset (aref string (1+ i)))))
- (when (string-match "unicode\\|big\\|japanese" charset)
- (setq found t)))
- found)))
- (defun gnus-summary-limit-to-predicate (predicate)
- "Limit to articles where PREDICATE returns non-nil.
- PREDICATE will be called with the header structures of the
- articles."
- (let ((articles nil)
- (case-fold-search t))
- (dolist (header gnus-newsgroup-headers)
- (when (funcall predicate header)
- (push (mail-header-number header) articles)))
- (gnus-summary-limit (nreverse articles))))
- (defun gnus-summary-limit-to-age (age &optional younger-p)
- "Limit the summary buffer to articles that are older than (or equal) AGE days.
- If YOUNGER-P (the prefix) is non-nil, limit the summary buffer to
- articles that are younger than AGE days."
- (interactive
- (let ((younger current-prefix-arg)
- (days-got nil)
- days)
- (while (not days-got)
- (setq days (if younger
- (read-string "Limit to articles younger than (in days, older when negative): ")
- (read-string
- "Limit to articles older than (in days, younger when negative): ")))
- (when (> (length days) 0)
- (setq days (read days)))
- (if (numberp days)
- (progn
- (setq days-got t)
- (when (< days 0)
- (setq younger (not younger))
- (setq days (* days -1))))
- (message "Please enter a number.")
- (sleep-for 1)))
- (list days younger)))
- (prog1
- (let ((data gnus-newsgroup-data)
- (cutoff (days-to-time age))
- articles d date is-younger)
- (while (setq d (pop data))
- (when (and (vectorp (gnus-data-header d))
- (setq date (mail-header-date (gnus-data-header d))))
- (setq is-younger (time-less-p
- (time-since (gnus-date-get-time date))
- cutoff))
- (when (if younger-p
- is-younger
- (not is-younger))
- (push (gnus-data-number d) articles))))
- (gnus-summary-limit (nreverse articles)))
- (gnus-summary-position-point)))
- (defun gnus-summary-limit-to-extra (header regexp &optional not-matching)
- "Limit the summary buffer to articles that match an `extra' header."
- (interactive
- (let ((header
- (intern
- (gnus-completing-read
- (if current-prefix-arg
- "Exclude extra header"
- "Limit extra header")
- (mapcar 'symbol-name gnus-extra-headers)
- t nil nil
- (symbol-name (car gnus-extra-headers))))))
- (list header
- (read-string (format "%s header %s (regexp): "
- (if current-prefix-arg "Exclude" "Limit to")
- header))
- current-prefix-arg)))
- (when (not (equal "" regexp))
- (prog1
- (let ((articles (gnus-summary-find-matching
- (cons 'extra header) regexp 'all nil nil
- not-matching)))
- (unless articles
- (error "Found no matches for \"%s\"" regexp))
- (gnus-summary-limit articles))
- (gnus-summary-position-point))))
- (defun gnus-summary-limit-to-display-predicate ()
- "Limit the summary buffer to the predicated in the `display' group parameter."
- (interactive)
- (unless gnus-newsgroup-display
- (error "There is no `display' group parameter"))
- (let (articles)
- (dolist (gnus-number gnus-newsgroup-articles)
- (when (funcall gnus-newsgroup-display)
- (push gnus-number articles)))
- (gnus-summary-limit articles))
- (gnus-summary-position-point))
- (defun gnus-summary-limit-to-unread (&optional all)
- "Limit the summary buffer to articles that are not marked as read.
- If ALL is non-nil, limit strictly to unread articles."
- (interactive "P")
- (if all
- (gnus-summary-limit-to-marks (char-to-string gnus-unread-mark))
- (gnus-summary-limit-to-marks
- ;; Concat all the marks that say that an article is read and have
- ;; those removed.
- (list gnus-del-mark gnus-read-mark gnus-ancient-mark
- gnus-killed-mark gnus-spam-mark gnus-kill-file-mark
- gnus-low-score-mark gnus-expirable-mark
- gnus-canceled-mark gnus-catchup-mark gnus-sparse-mark
- gnus-duplicate-mark)
- 'reverse)))
- (defun gnus-summary-limit-to-headers (match &optional reverse)
- "Limit the summary buffer to articles that have headers that match MATCH.
- If REVERSE (the prefix), limit to articles that don't match."
- (interactive "sMatch headers (regexp): \nP")
- (gnus-summary-limit-to-bodies match reverse t))
- (declare-function article-goto-body "gnus-art" ())
- (defun gnus-summary-limit-to-bodies (match &optional reverse headersp)
- "Limit the summary buffer to articles that have bodies that match MATCH.
- If REVERSE (the prefix), limit to articles that don't match."
- (interactive "sMatch body (regexp): \nP")
- (let ((articles nil)
- (gnus-select-article-hook nil) ;Disable hook.
- (gnus-article-prepare-hook nil)
- (gnus-use-article-prefetch nil)
- (gnus-keep-backlog nil)
- (gnus-break-pages nil)
- (gnus-summary-display-arrow nil)
- (gnus-updated-mode-lines nil)
- (gnus-auto-center-summary nil)
- (gnus-display-mime-function nil))
- (dolist (data gnus-newsgroup-data)
- (let (gnus-mark-article-hook)
- (gnus-summary-select-article t t nil (gnus-data-number data)))
- (with-current-buffer gnus-article-buffer
- (article-goto-body)
- (let* ((case-fold-search t)
- (found (if headersp
- (re-search-backward match nil t)
- (re-search-forward match nil t))))
- (when (or (and found
- (not reverse))
- (and (not found)
- reverse))
- (push (gnus-data-number data) articles)))))
- (if (not articles)
- (message "No messages matched")
- (gnus-summary-limit articles)))
- (gnus-summary-position-point))
- (defun gnus-summary-limit-to-singletons (&optional threadsp)
- "Limit the summary buffer to articles that aren't part on any thread.
- If THREADSP (the prefix), limit to articles that are in threads."
- (interactive "P")
- (let ((articles nil)
- thread-articles
- threads)
- (dolist (thread gnus-newsgroup-threads)
- (if (stringp (car thread))
- (dolist (thread (cdr thread))
- (push thread threads))
- (push thread threads)))
- (dolist (thread threads)
- (setq thread-articles (gnus-articles-in-thread thread))
- (when (or (and threadsp
- (> (length thread-articles) 1))
- (and (not threadsp)
- (= (length thread-articles) 1)))
- (setq articles (nconc thread-articles articles))))
- (if (not articles)
- (message "No messages matched")
- (gnus-summary-limit articles))
- (gnus-summary-position-point)))
- (defun gnus-summary-limit-to-replied (&optional unreplied)
- "Limit the summary buffer to replied articles.
- If UNREPLIED (the prefix), limit to unreplied articles."
- (interactive "P")
- (if unreplied
- (gnus-summary-limit
- (gnus-set-difference gnus-newsgroup-articles
- gnus-newsgroup-replied))
- (gnus-summary-limit gnus-newsgroup-replied))
- (gnus-summary-position-point))
- (defun gnus-summary-limit-exclude-marks (marks &optional reverse)
- "Exclude articles that are marked with MARKS (e.g. \"DK\").
- If REVERSE, limit the summary buffer to articles that are marked
- with MARKS. MARKS can either be a string of marks or a list of marks.
- Returns how many articles were removed."
- (interactive "sMarks: ")
- (gnus-summary-limit-to-marks marks t))
- (defun gnus-summary-limit-to-marks (marks &optional reverse)
- "Limit the summary buffer to articles that are marked with MARKS (e.g. \"DK\").
- If REVERSE (the prefix), limit the summary buffer to articles that are
- not marked with MARKS. MARKS can either be a string of marks or a
- list of marks.
- Returns how many articles were removed."
- (interactive "sMarks: \nP")
- (prog1
- (let ((data gnus-newsgroup-data)
- (marks (if (listp marks) marks
- (append marks nil))) ; Transform to list.
- articles)
- (while data
- (when (if reverse (not (memq (gnus-data-mark (car data)) marks))
- (memq (gnus-data-mark (car data)) marks))
- (push (gnus-data-number (car data)) articles))
- (setq data (cdr data)))
- (gnus-summary-limit articles))
- (gnus-summary-position-point)))
- (defun gnus-summary-limit-to-score (score)
- "Limit to articles with score at or above SCORE."
- (interactive "NLimit to articles with score of at least: ")
- (let ((data gnus-newsgroup-data)
- articles)
- (while data
- (when (>= (gnus-summary-article-score (gnus-data-number (car data)))
- score)
- (push (gnus-data-number (car data)) articles))
- (setq data (cdr data)))
- (prog1
- (gnus-summary-limit articles)
- (gnus-summary-position-point))))
- (defun gnus-summary-limit-to-unseen ()
- "Limit to unseen articles."
- (interactive)
- (prog1
- (gnus-summary-limit gnus-newsgroup-unseen)
- (gnus-summary-position-point)))
- (defun gnus-summary-limit-include-thread (id)
- "Display all the hidden articles that is in the thread with ID in it.
- When called interactively, ID is the Message-ID of the current
- article."
- (interactive (list (mail-header-id (gnus-summary-article-header))))
- (let ((articles (gnus-articles-in-thread
- (gnus-id-to-thread (gnus-root-id id))))
- ;;we REALLY want the whole thread---this prevents cut-threads
- ;;from removing the thread we want to include.
- (gnus-fetch-old-headers nil)
- (gnus-build-sparse-threads nil))
- (prog1
- (gnus-summary-limit (nconc articles gnus-newsgroup-limit))
- (gnus-summary-limit-include-matching-articles
- "subject"
- (regexp-quote (gnus-simplify-subject-re
- (mail-header-subject (gnus-id-to-header id)))))
- (gnus-summary-position-point))))
- (defun gnus-summary-limit-include-matching-articles (header regexp)
- "Display all the hidden articles that have HEADERs that match REGEXP."
- (interactive (list (read-string "Match on header: ")
- (read-string "Regexp: ")))
- (let ((articles (gnus-find-matching-articles header regexp)))
- (prog1
- (gnus-summary-limit (nconc articles gnus-newsgroup-limit))
- (gnus-summary-position-point))))
- (defun gnus-summary-insert-dormant-articles ()
- "Insert all the dormant articles for this group into the current buffer."
- (interactive)
- (let ((gnus-verbose (max 6 gnus-verbose)))
- (if (not gnus-newsgroup-dormant)
- (gnus-message 3 "No dormant articles for this group")
- (gnus-summary-goto-subjects gnus-newsgroup-dormant))))
- (defun gnus-summary-insert-ticked-articles ()
- "Insert ticked articles for this group into the current buffer."
- (interactive)
- (let ((gnus-verbose (max 6 gnus-verbose)))
- (if (not gnus-newsgroup-marked)
- (gnus-message 3 "No ticked articles for this group")
- (gnus-summary-goto-subjects gnus-newsgroup-marked))))
- (defun gnus-summary-limit-include-dormant ()
- "Display all the hidden articles that are marked as dormant.
- Note that this command only works on a subset of the articles currently
- fetched for this group."
- (interactive)
- (unless gnus-newsgroup-dormant
- (error "There are no dormant articles in this group"))
- (prog1
- (gnus-summary-limit (append gnus-newsgroup-dormant gnus-newsgroup-limit))
- (gnus-summary-position-point)))
- (defun gnus-summary-include-articles (articles)
- "Fetch the headers for ARTICLES and then display the summary lines."
- (let ((gnus-inhibit-demon t)
- (gnus-agent nil)
- (gnus-read-all-available-headers t))
- (setq gnus-newsgroup-headers
- (gnus-merge
- 'list gnus-newsgroup-headers
- (gnus-fetch-headers articles nil t)
- 'gnus-article-sort-by-number))
- (setq gnus-newsgroup-articles
- (gnus-sorted-nunion gnus-newsgroup-articles articles))
- (gnus-summary-limit (append articles gnus-newsgroup-limit))))
- (defun gnus-summary-limit-exclude-dormant ()
- "Hide all dormant articles."
- (interactive)
- (prog1
- (gnus-summary-limit-to-marks (list gnus-dormant-mark) 'reverse)
- (gnus-summary-position-point)))
- (defun gnus-summary-limit-exclude-childless-dormant ()
- "Hide all dormant articles that have no children."
- (interactive)
- (let ((data (gnus-data-list t))
- articles d children)
- ;; Find all articles that are either not dormant or have
- ;; children.
- (while (setq d (pop data))
- (when (or (not (= (gnus-data-mark d) gnus-dormant-mark))
- (and (setq children
- (gnus-article-children (gnus-data-number d)))
- (let (found)
- (while children
- (when (memq (car children) articles)
- (setq children nil
- found t))
- (pop children))
- found)))
- (push (gnus-data-number d) articles)))
- ;; Do the limiting.
- (prog1
- (gnus-summary-limit articles)
- (gnus-summary-position-point))))
- (defun gnus-summary-limit-mark-excluded-as-read (&optional all)
- "Mark all unread excluded articles as read.
- If ALL, mark even excluded ticked and dormants as read."
- (interactive "P")
- (setq gnus-newsgroup-limit (sort gnus-newsgroup-limit '<))
- (let ((articles (gnus-sorted-ndifference
- (sort
- (mapcar (lambda (h) (mail-header-number h))
- gnus-newsgroup-headers)
- '<)
- gnus-newsgroup-limit))
- article)
- (setq gnus-newsgroup-unreads
- (gnus-sorted-intersection gnus-newsgroup-unreads
- gnus-newsgroup-limit))
- (if all
- (setq gnus-newsgroup-dormant nil
- gnus-newsgroup-marked nil
- gnus-newsgroup-reads
- (nconc
- (mapcar (lambda (n) (cons n gnus-catchup-mark)) articles)
- gnus-newsgroup-reads))
- (while (setq article (pop articles))
- (unless (or (memq article gnus-newsgroup-dormant)
- (memq article gnus-newsgroup-marked))
- (push (cons article gnus-catchup-mark) gnus-newsgroup-reads))))))
- (defun gnus-summary-limit (articles &optional pop)
- (if pop
- ;; We pop the previous limit off the stack and use that.
- (setq articles (car gnus-newsgroup-limits)
- gnus-newsgroup-limits (cdr gnus-newsgroup-limits))
- ;; We use the new limit, so we push the old limit on the stack.
- (push gnus-newsgroup-limit gnus-newsgroup-limits))
- ;; Set the limit.
- (setq gnus-newsgroup-limit articles)
- (let ((total (length gnus-newsgroup-data))
- (data (gnus-data-find-list (gnus-summary-article-number)))
- (gnus-summary-mark-below nil) ; Inhibit this.
- found)
- ;; This will do all the work of generating the new summary buffer
- ;; according to the new limit.
- (gnus-summary-prepare)
- ;; Hide any threads, possibly.
- (gnus-summary-maybe-hide-threads)
- ;; Try to return to the article you were at, or one in the
- ;; neighborhood.
- (when data
- ;; We try to find some article after the current one.
- (while data
- (when (gnus-summary-goto-subject (gnus-data-number (car data)) nil t)
- (setq data nil
- found t))
- (setq data (cdr data))))
- (unless found
- ;; If there is no data, that means that we were after the last
- ;; article. The same goes when we can't find any articles
- ;; after the current one.
- (goto-char (point-max))
- (gnus-summary-find-prev))
- (gnus-set-mode-line 'summary)
- ;; We return how many articles were removed from the summary
- ;; buffer as a result of the new limit.
- (- total (length gnus-newsgroup-data))))
- (defsubst gnus-invisible-cut-children (threads)
- (let ((num 0))
- (while threads
- (when (memq (mail-header-number (caar threads)) gnus-newsgroup-limit)
- (incf num))
- (pop threads))
- (< num 2)))
- (defsubst gnus-cut-thread (thread)
- "Go forwards in the thread until we find an article that we want to display."
- (when (or (eq gnus-fetch-old-headers 'some)
- (eq gnus-fetch-old-headers 'invisible)
- (numberp gnus-fetch-old-headers)
- (eq gnus-build-sparse-threads 'some)
- (eq gnus-build-sparse-threads 'more))
- ;; Deal with old-fetched headers and sparse threads.
- (while (and
- thread
- (or
- (gnus-summary-article-sparse-p (mail-header-number (car thread)))
- (gnus-summary-article-ancient-p
- (mail-header-number (car thread))))
- (if (or (<= (length (cdr thread)) 1)
- (eq gnus-fetch-old-headers 'invisible))
- (setq gnus-newsgroup-limit
- (delq (mail-header-number (car thread))
- gnus-newsgroup-limit)
- thread (cadr thread))
- (when (gnus-invisible-cut-children (cdr thread))
- (let ((th (cdr thread)))
- (while th
- (if (memq (mail-header-number (caar th))
- gnus-newsgroup-limit)
- (setq thread (car th)
- th nil)
- (setq th (cdr th))))))))))
- thread)
- (defun gnus-cut-threads (threads)
- "Cut off all uninteresting articles from the beginning of THREADS."
- (when (or (eq gnus-fetch-old-headers 'some)
- (eq gnus-fetch-old-headers 'invisible)
- (numberp gnus-fetch-old-headers)
- (eq gnus-build-sparse-threads 'some)
- (eq gnus-build-sparse-threads 'more))
- (let ((th threads))
- (while th
- (setcar th (gnus-cut-thread (car th)))
- (setq th (cdr th)))))
- ;; Remove nixed out threads.
- (delq nil threads))
- (defun gnus-summary-initial-limit (&optional show-if-empty)
- "Figure out what the initial limit is supposed to be on group entry.
- This entails weeding out unwanted dormants, low-scored articles,
- fetch-old-headers verbiage, and so on."
- ;; Most groups have nothing to remove.
- (unless (or gnus-inhibit-limiting
- (and (null gnus-newsgroup-dormant)
- (eq gnus-newsgroup-display 'gnus-not-ignore)
- (not (eq gnus-fetch-old-headers 'some))
- (not (numberp gnus-fetch-old-headers))
- (not (eq gnus-fetch-old-headers 'invisible))
- (null gnus-summary-expunge-below)
- (not (eq gnus-build-sparse-threads 'some))
- (not (eq gnus-build-sparse-threads 'more))
- (null gnus-thread-expunge-below)))
- (push gnus-newsgroup-limit gnus-newsgroup-limits)
- (setq gnus-newsgroup-limit nil)
- (mapatoms
- (lambda (node)
- (unless (car (symbol-value node))
- ;; These threads have no parents -- they are roots.
- (let ((nodes (cdr (symbol-value node)))
- thread)
- (while nodes
- (if (and gnus-thread-expunge-below
- (< (gnus-thread-total-score (car nodes))
- gnus-thread-expunge-below))
- (gnus-expunge-thread (pop nodes))
- (setq thread (pop nodes))
- (gnus-summary-limit-children thread))))))
- gnus-newsgroup-dependencies)
- ;; If this limitation resulted in an empty group, we might
- ;; pop the previous limit and use it instead.
- (when (and (not gnus-newsgroup-limit)
- show-if-empty)
- (setq gnus-newsgroup-limit (pop gnus-newsgroup-limits)))
- gnus-newsgroup-limit))
- (defun gnus-summary-limit-children (thread)
- "Return 1 if this subthread is visible and 0 if it is not."
- ;; First we get the number of visible children to this thread. This
- ;; is done by recursing down the thread using this function, so this
- ;; will really go down to a leaf article first, before slowly
- ;; working its way up towards the root.
- (when thread
- (let* ((max-lisp-eval-depth (max 5000 max-lisp-eval-depth))
- (children
- (if (cdr thread)
- (apply '+ (mapcar 'gnus-summary-limit-children
- (cdr thread)))
- 0))
- (number (mail-header-number (car thread)))
- score)
- (if (and
- (not (memq number gnus-newsgroup-marked))
- (or
- ;; If this article is dormant and has absolutely no visible
- ;; children, then this article isn't visible.
- (and (memq number gnus-newsgroup-dormant)
- (zerop children))
- ;; If this is "fetch-old-headered" and there is no
- ;; visible children, then we don't want this article.
- (and (or (eq gnus-fetch-old-headers 'some)
- (numberp gnus-fetch-old-headers))
- (gnus-summary-article-ancient-p number)
- (zerop children))
- ;; If this is "fetch-old-headered" and `invisible', then
- ;; we don't want this article.
- (and (eq gnus-fetch-old-headers 'invisible)
- (gnus-summary-article-ancient-p number))
- ;; If this is a sparsely inserted article with no children,
- ;; we don't want it.
- (and (eq gnus-build-sparse-threads 'some)
- (gnus-summary-article-sparse-p number)
- (zerop children))
- ;; If we use expunging, and this article is really
- ;; low-scored, then we don't want this article.
- (when (and gnus-summary-expunge-below
- (< (setq score
- (or (cdr (assq number gnus-newsgroup-scored))
- gnus-summary-default-score))
- gnus-summary-expunge-below))
- ;; We increase the expunge-tally here, but that has
- ;; nothing to do with the limits, really.
- (incf gnus-newsgroup-expunged-tally)
- ;; We also mark as read here, if that's wanted.
- (when (and gnus-summary-mark-below
- (< score gnus-summary-mark-below))
- (setq gnus-newsgroup-unreads
- (delq number gnus-newsgroup-unreads))
- (if gnus-newsgroup-auto-expire
- (push number gnus-newsgroup-expirable)
- (push (cons number gnus-low-score-mark)
- gnus-newsgroup-reads)))
- t)
- ;; Do the `display' group parameter.
- (and gnus-newsgroup-display
- (let ((gnus-number number))
- (not (funcall gnus-newsgroup-display))))))
- ;; Nope, invisible article.
- 0
- ;; Ok, this article is to be visible, so we add it to the limit
- ;; and return 1.
- (push number gnus-newsgroup-limit)
- 1))))
- (defun gnus-expunge-thread (thread)
- "Mark all articles in THREAD as read."
- (let* ((number (mail-header-number (car thread))))
- (incf gnus-newsgroup-expunged-tally)
- ;; We also mark as read here, if that's wanted.
- (setq gnus-newsgroup-unreads
- (delq number gnus-newsgroup-unreads))
- (if gnus-newsgroup-auto-expire
- (push number gnus-newsgroup-expirable)
- (push (cons number gnus-low-score-mark)
- gnus-newsgroup-reads)))
- ;; Go recursively through all subthreads.
- (mapcar 'gnus-expunge-thread (cdr thread)))
- ;; Summary article oriented commands
- (defun gnus-summary-refer-parent-article (n)
- "Refer parent article N times.
- If N is negative, go to ancestor -N instead.
- The difference between N and the number of articles fetched is returned."
- (interactive "p")
- (let ((skip 1)
- error header ref)
- (when (not (natnump n))
- (setq skip (abs n)
- n 1))
- (while (and (> n 0)
- (not error))
- (setq header (gnus-summary-article-header))
- (if (and (eq (mail-header-number header)
- (cdr gnus-article-current))
- (equal gnus-newsgroup-name
- (car gnus-article-current)))
- ;; If we try to find the parent of the currently
- ;; displayed article, then we take a look at the actual
- ;; References header, since this is slightly more
- ;; reliable than the References field we got from the
- ;; server.
- (with-current-buffer gnus-original-article-buffer
- (nnheader-narrow-to-headers)
- (unless (setq ref (message-fetch-field "references"))
- (when (setq ref (message-fetch-field "in-reply-to"))
- (setq ref (gnus-extract-message-id-from-in-reply-to ref))))
- (widen))
- (setq ref
- ;; It's not the current article, so we take a bet on
- ;; the value we got from the server.
- (mail-header-references header)))
- (if (and ref
- (not (equal ref "")))
- (unless (gnus-summary-refer-article (gnus-parent-id ref skip))
- (gnus-message 1 "Couldn't find parent"))
- (gnus-message 1 "No references in article %d"
- (gnus-summary-article-number))
- (setq error t))
- (decf n))
- (gnus-summary-position-point)
- n))
- (defun gnus-summary-refer-references ()
- "Fetch all articles mentioned in the References header.
- Return the number of articles fetched."
- (interactive)
- (let ((ref (mail-header-references (gnus-summary-article-header)))
- (current (gnus-summary-article-number))
- (n 0))
- (if (or (not ref)
- (equal ref ""))
- (error "No References in the current article")
- ;; For each Message-ID in the References header...
- (while (string-match "<[^>]*>" ref)
- (incf n)
- ;; ... fetch that article.
- (gnus-summary-refer-article
- (prog1 (match-string 0 ref)
- (setq ref (substring ref (match-end 0))))))
- (gnus-summary-goto-subject current)
- (gnus-summary-position-point)
- n)))
- (defun gnus-delete-duplicate-headers (headers)
- ;; First remove leading duplicates.
- (while (and (> (length headers) 1)
- (= (mail-header-number (car headers))
- (mail-header-number (cadr headers))))
- (pop headers))
- ;; Then the rest.
- (let ((result headers))
- (while (> (length headers) 1)
- (if (= (mail-header-number (car headers))
- (mail-header-number (cadr headers)))
- (setcdr headers (cddr headers))
- (pop headers)))
- result))
- (defun gnus-summary-refer-thread (&optional limit)
- "Fetch all articles in the current thread. For backends that
- know how to search for threads (currently only 'nnimap) a
- non-numeric prefix arg will use nnir to search the entire
- server; without a prefix arg only the current group is
- searched. If the variable `gnus-refer-thread-use-nnir' is
- non-nil the prefix arg has the reverse meaning. If no
- backend-specific 'request-thread function is available fetch
- LIMIT (the numerical prefix) old headers. If LIMIT is
- non-numeric or nil fetch the number specified by the
- `gnus-refer-thread-limit' variable."
- (interactive "P")
- (gnus-warp-to-article)
- (let* ((header (gnus-summary-article-header))
- (id (mail-header-id header))
- (gnus-inhibit-demon t)
- (gnus-summary-ignore-duplicates t)
- (gnus-read-all-available-headers t)
- (gnus-refer-thread-use-nnir
- (if (and (not (null limit)) (listp limit))
- (not gnus-refer-thread-use-nnir) gnus-refer-thread-use-nnir))
- (new-headers
- (if (gnus-check-backend-function
- 'request-thread gnus-newsgroup-name)
- (gnus-request-thread header gnus-newsgroup-name)
- (let* ((limit (if (numberp limit) (prefix-numeric-value limit)
- gnus-refer-thread-limit))
- (last (if (numberp limit)
- (min (+ (mail-header-number header)
- limit)
- gnus-newsgroup-highest)
- gnus-newsgroup-highest))
- (subject (gnus-simplify-subject
- (mail-header-subject header)))
- (refs (split-string (or (mail-header-references header)
- "")))
- (gnus-parse-headers-hook
- `(lambda () (goto-char (point-min))
- (keep-lines
- (regexp-opt ',(append refs (list id subject)))))))
- (gnus-fetch-headers (list last) (if (numberp limit)
- (* 2 limit) limit) t))))
- article-ids new-unreads)
- (when (listp new-headers)
- (dolist (header new-headers)
- (push (mail-header-number header) article-ids))
- (setq article-ids (nreverse article-ids))
- (setq new-unreads
- (gnus-sorted-intersection gnus-newsgroup-unselected article-ids))
- (setq gnus-newsgroup-unselected
- (gnus-sorted-ndifference gnus-newsgroup-unselected new-unreads))
- (setq gnus-newsgroup-unreads
- (gnus-sorted-nunion gnus-newsgroup-unreads new-unreads))
- (setq gnus-newsgroup-headers
- (gnus-delete-duplicate-headers
- (gnus-merge
- 'list gnus-newsgroup-headers new-headers
- 'gnus-article-sort-by-number)))
- (setq gnus-newsgroup-articles
- (gnus-sorted-nunion gnus-newsgroup-articles article-ids))
- (gnus-summary-limit-include-thread id)))
- (gnus-summary-show-thread))
- (defun gnus-summary-open-group-with-article (message-id)
- "Open a group containing the article with the given MESSAGE-ID."
- (interactive "sMessage-ID: ")
- (require 'nndoc)
- (with-temp-buffer
- ;; Prepare a dummy article
- (erase-buffer)
- (insert "From nobody Tue Sep 13 22:05:34 2011\n\n")
- ;; Prepare pretty modelines for summary and article buffers
- (let ((gnus-summary-mode-line-format "Found %G")
- (gnus-article-mode-line-format
- ;; Group names just get in the way here, especially the
- ;; abbreviated ones
- (if (string-match "%[gG]" gnus-article-mode-line-format)
- (concat (substring gnus-article-mode-line-format
- 0 (match-beginning 0))
- (substring gnus-article-mode-line-format (match-end 0)))
- gnus-article-mode-line-format)))
- ;; Build an ephemeral group containing the dummy article (hidden)
- (gnus-group-read-ephemeral-group
- message-id
- `(nndoc ,message-id
- (nndoc-address ,(current-buffer))
- (nndoc-article-type mbox))
- :activate
- (cons (current-buffer) gnus-current-window-configuration)
- (not :request-only)
- '(-1) ; :select-articles
- (not :parameters)
- 0)) ; :number
- ;; Fetch the desired article
- (gnus-summary-refer-article message-id)))
- (defun gnus-summary-refer-article (message-id)
- "Fetch an article specified by MESSAGE-ID."
- (interactive "sMessage-ID: ")
- (gnus-warp-to-article)
- (when (and (stringp message-id)
- (not (zerop (length message-id))))
- (setq message-id (gnus-replace-in-string message-id " " ""))
- ;; Construct the correct Message-ID if necessary.
- ;; Suggested by tale@pawl.rpi.edu.
- (unless (string-match "^<" message-id)
- (setq message-id (concat "<" message-id)))
- (unless (string-match ">$" message-id)
- (setq message-id (concat message-id ">")))
- ;; People often post MIDs from URLs, so unhex it:
- (unless (string-match "@" message-id)
- (setq message-id (gnus-url-unhex-string message-id)))
- (let* ((header (gnus-id-to-header message-id))
- (sparse (and header
- (gnus-summary-article-sparse-p
- (mail-header-number header))
- (memq (mail-header-number header)
- gnus-newsgroup-limit)))
- number)
- (cond
- ;; If the article is present in the buffer we just go to it.
- ((and header
- (or (not (gnus-summary-article-sparse-p
- (mail-header-number header)))
- sparse))
- (prog1
- (gnus-summary-goto-article
- (mail-header-number header) nil t)
- (when sparse
- (gnus-summary-update-article (mail-header-number header)))))
- (t
- ;; We fetch the article.
- (catch 'found
- (dolist (gnus-override-method (gnus-refer-article-methods))
- (when (and (gnus-check-server gnus-override-method)
- ;; Fetch the header,
- (setq number (gnus-summary-insert-subject message-id)))
- ;; and display the article.
- (gnus-summary-select-article nil nil nil number)
- (throw 'found t)))
- (gnus-message 3 "Couldn't fetch article %s" message-id)))))))
- (defun gnus-refer-article-methods ()
- "Return a list of referable methods."
- (cond
- ;; No method, so we default to current and native.
- ((null gnus-refer-article-method)
- (list gnus-current-select-method gnus-select-method))
- ;; Current.
- ((eq 'current gnus-refer-article-method)
- (list gnus-current-select-method))
- ;; List of select methods.
- ((not (and (symbolp (car gnus-refer-article-method))
- (assq (car gnus-refer-article-method) nnoo-definition-alist)))
- (let (out)
- (dolist (method gnus-refer-article-method)
- (push (if (eq 'current method)
- gnus-current-select-method
- (if (eq 'nnir (car method))
- (list
- 'nnir
- (or (cadr method)
- (gnus-method-to-server gnus-current-select-method)))
- method))
- out))
- (nreverse out)))
- ;; One single select method.
- (t
- (list gnus-refer-article-method))))
- (defun gnus-summary-edit-parameters ()
- "Edit the group parameters of the current group."
- (interactive)
- (gnus-group-edit-group gnus-newsgroup-name 'params))
- (defun gnus-summary-customize-parameters ()
- "Customize the group parameters of the current group."
- (interactive)
- (gnus-group-customize gnus-newsgroup-name))
- (defun gnus-summary-enter-digest-group (&optional force)
- "Enter an nndoc group based on the current article.
- If FORCE, force a digest interpretation. If not, try to guess
- what the document format is.
- To control what happens when you exit the group, see the
- `gnus-auto-select-on-ephemeral-exit' variable."
- (interactive "P")
- (let ((conf gnus-current-window-configuration))
- (save-window-excursion
- (save-excursion
- (let (gnus-article-prepare-hook
- gnus-display-mime-function
- gnus-break-pages)
- (gnus-summary-select-article))))
- (setq gnus-current-window-configuration conf)
- (let* ((name (format "%s-%d"
- (gnus-group-prefixed-name
- gnus-newsgroup-name (list 'nndoc ""))
- (with-current-buffer gnus-summary-buffer
- gnus-current-article)))
- (ogroup gnus-newsgroup-name)
- (params (append (gnus-info-params (gnus-get-info ogroup))
- (list (cons 'to-group ogroup))
- (list (cons 'parent-group ogroup))
- (list (cons 'save-article-group ogroup))))
- (case-fold-search t)
- (buf (current-buffer))
- dig to-address charset)
- (with-current-buffer gnus-original-article-buffer
- ;; Have the digest group inherit the main mail address of
- ;; the parent article.
- (when (setq to-address (or (gnus-fetch-field "reply-to")
- (gnus-fetch-field "from")))
- (setq params
- (append
- params
- (list (cons 'to-address
- (funcall gnus-decode-encoded-address-function
- to-address))))))
- (setq dig (nnheader-set-temp-buffer " *gnus digest buffer*"))
- (insert-buffer-substring gnus-original-article-buffer)
- (narrow-to-region
- (goto-char (point-min))
- (or (search-forward "\n\n" nil t) (point)))
- ;; Remove lines that may lead nndoc to misinterpret the
- ;; document type.
- (goto-char (point-min))
- (delete-matching-lines "^Path:\\|^From ")
- ;; Parse charset, and decode content transfer encoding.
- (setq charset (mail-content-type-get
- (mail-header-parse-content-type
- (or (gnus-fetch-field "content-type") ""))
- 'charset))
- (let ((encoding (gnus-fetch-field "content-transfer-encoding")))
- (when encoding
- (message-remove-header "content-transfer-encoding")
- (goto-char (point-max))
- (widen)
- (narrow-to-region (point) (point-max))
- (mm-decode-content-transfer-encoding
- (intern (downcase (mail-header-strip encoding))))))
- (widen))
- (unwind-protect
- (if (let ((gnus-newsgroup-ephemeral-charset
- (if charset
- (intern (downcase (gnus-strip-whitespace charset)))
- gnus-newsgroup-charset))
- (gnus-newsgroup-ephemeral-ignored-charsets
- gnus-newsgroup-ignored-charsets))
- (gnus-group-read-ephemeral-group
- name `(nndoc ,name (nndoc-address ,(get-buffer dig))
- (nndoc-article-type
- ,(if force 'mbox 'guess)))
- t nil nil nil
- `((adapt-file . ,(gnus-score-file-name gnus-newsgroup-name
- "ADAPT")))))
- ;; Make all postings to this group go to the parent group.
- (nconc (gnus-info-params (gnus-get-info name))
- params)
- ;; Couldn't select this doc group.
- (switch-to-buffer buf)
- (gnus-set-global-variables)
- (gnus-configure-windows 'summary)
- (gnus-message 3 "Article couldn't be entered?"))
- (kill-buffer dig)))))
- (defun gnus-summary-read-document (n)
- "Open a new group based on the current article(s).
- This will allow you to read digests and other similar
- documents as newsgroups.
- Obeys the standard process/prefix convention."
- (interactive "P")
- (let* ((ogroup gnus-newsgroup-name)
- (params (append (gnus-info-params (gnus-get-info ogroup))
- (list (cons 'to-group ogroup))))
- group egroup groups vgroup)
- (dolist (article (gnus-summary-work-articles n))
- (setq group (format "%s-%d" gnus-newsgroup-name article))
- (gnus-summary-remove-process-mark article)
- (when (gnus-summary-display-article article)
- (save-excursion ;;What for?
- (with-temp-buffer
- (insert-buffer-substring gnus-original-article-buffer)
- ;; Remove some headers that may lead nndoc to make
- ;; the wrong guess.
- (message-narrow-to-head)
- (goto-char (point-min))
- (delete-matching-lines "^Path:\\|^From ")
- (widen)
- (if (setq egroup
- (gnus-group-read-ephemeral-group
- group `(nndoc ,group (nndoc-address ,(current-buffer))
- (nndoc-article-type guess))
- t nil t))
- (progn
- ;; Make all postings to this group go to the parent group.
- (nconc (gnus-info-params (gnus-get-info egroup))
- params)
- (push egroup groups))
- ;; Couldn't select this doc group.
- (gnus-error 3 "Article couldn't be entered"))))))
- ;; Now we have selected all the documents.
- (cond
- ((not groups)
- (error "None of the articles could be interpreted as documents"))
- ((gnus-group-read-ephemeral-group
- (setq vgroup (format
- "nnvirtual:%s-%s" gnus-newsgroup-name
- (format-time-string "%Y%m%dT%H%M%S")))
- `(nnvirtual ,vgroup (nnvirtual-component-groups ,groups))
- t
- (cons (current-buffer) 'summary)))
- (t
- (error "Couldn't select virtual nndoc group")))))
- (defun gnus-summary-widget-forward (arg)
- "Move point to the next field or button in the article.
- With optional ARG, move across that many fields."
- (interactive "p")
- (gnus-summary-select-article)
- (gnus-configure-windows 'article)
- (select-window (gnus-get-buffer-window gnus-article-buffer))
- (widget-forward arg))
- (defun gnus-summary-widget-backward (arg)
- "Move point to the previous field or button in the article.
- With optional ARG, move across that many fields."
- (interactive "p")
- (gnus-summary-select-article)
- (gnus-configure-windows 'article)
- (select-window (gnus-get-buffer-window gnus-article-buffer))
- (unless (widget-at (point))
- (goto-char (point-max)))
- (widget-backward arg))
- (defun gnus-summary-isearch-article (&optional regexp-p)
- "Do incremental search forward on the current article.
- If REGEXP-P (the prefix) is non-nil, do regexp isearch."
- (interactive "P")
- (gnus-summary-select-article)
- (gnus-configure-windows 'article)
- (gnus-eval-in-buffer-window gnus-article-buffer
- (save-restriction
- (widen)
- (isearch-forward regexp-p))))
- (defun gnus-summary-repeat-search-article-forward ()
- "Repeat the previous search forwards."
- (interactive)
- (unless gnus-last-search-regexp
- (error "No previous search"))
- (gnus-summary-search-article-forward gnus-last-search-regexp))
- (defun gnus-summary-repeat-search-article-backward ()
- "Repeat the previous search backwards."
- (interactive)
- (unless gnus-last-search-regexp
- (error "No previous search"))
- (gnus-summary-search-article-forward gnus-last-search-regexp t))
- (defun gnus-summary-search-article-forward (regexp &optional backward)
- "Search for an article containing REGEXP forward.
- If BACKWARD, search backward instead."
- (interactive
- (list (read-string
- (format "Search article %s (regexp%s): "
- (if current-prefix-arg "backward" "forward")
- (if gnus-last-search-regexp
- (concat ", default " gnus-last-search-regexp)
- "")))
- current-prefix-arg))
- (if (string-equal regexp "")
- (setq regexp (or gnus-last-search-regexp ""))
- (setq gnus-last-search-regexp regexp)
- (setq gnus-article-before-search gnus-current-article))
- ;; Intentionally set gnus-last-article.
- (setq gnus-last-article gnus-article-before-search)
- (let ((gnus-last-article gnus-last-article))
- (if (gnus-summary-search-article regexp backward)
- (gnus-summary-show-thread)
- (signal 'search-failed (list regexp)))))
- (defun gnus-summary-search-article-backward (regexp)
- "Search for an article containing REGEXP backward."
- (interactive
- (list (read-string
- (format "Search article backward (regexp%s): "
- (if gnus-last-search-regexp
- (concat ", default " gnus-last-search-regexp)
- "")))))
- (gnus-summary-search-article-forward regexp 'backward))
- (defun gnus-summary-search-article (regexp &optional backward)
- "Search for an article containing REGEXP.
- Optional argument BACKWARD means do search for backward.
- `gnus-select-article-hook' is not called during the search."
- ;; We have to require this here to make sure that the following
- ;; dynamic binding isn't shadowed by autoloading.
- (require 'gnus-async)
- (require 'gnus-art)
- (let ((gnus-select-article-hook nil) ;Disable hook.
- (gnus-article-prepare-hook nil)
- (gnus-mark-article-hook nil) ;Inhibit marking as read.
- (gnus-use-article-prefetch nil)
- (gnus-xmas-force-redisplay nil) ;Inhibit XEmacs redisplay.
- (gnus-use-trees nil) ;Inhibit updating tree buffer.
- (gnus-visual nil)
- (gnus-keep-backlog nil)
- (gnus-break-pages nil)
- (gnus-summary-display-arrow nil)
- (gnus-updated-mode-lines nil)
- (gnus-auto-center-summary nil)
- (sum (current-buffer))
- (gnus-display-mime-function nil)
- (found nil)
- point)
- (gnus-save-hidden-threads
- (gnus-summary-select-article)
- (set-buffer gnus-article-buffer)
- (goto-char (window-point (get-buffer-window (current-buffer))))
- (when backward
- (forward-line -1))
- (while (not found)
- (gnus-message 7 "Searching article: %d..." (cdr gnus-article-current))
- (if (if backward
- (re-search-backward regexp nil t)
- (re-search-forward regexp nil t))
- ;; We found the regexp.
- (progn
- (setq found 'found)
- (beginning-of-line)
- (set-window-start
- (get-buffer-window (current-buffer))
- (point))
- (forward-line 1)
- (set-window-point
- (get-buffer-window (current-buffer))
- (point))
- (set-buffer sum)
- (setq point (point)))
- ;; We didn't find it, so we go to the next article.
- (set-buffer sum)
- (setq found 'not)
- (while (eq found 'not)
- (if (not (if backward (gnus-summary-find-prev)
- (gnus-summary-find-next)))
- ;; No more articles.
- (setq found t)
- ;; Select the next article and adjust point.
- (unless (gnus-summary-article-sparse-p
- (gnus-summary-article-number))
- (setq found nil)
- (gnus-summary-select-article)
- (set-buffer gnus-article-buffer)
- (widen)
- (goto-char (if backward (point-max) (point-min))))))))
- (gnus-message 7 ""))
- ;; Return whether we found the regexp.
- (when (eq found 'found)
- (goto-char point)
- (gnus-summary-show-thread)
- (gnus-summary-goto-subject gnus-current-article)
- (gnus-summary-position-point)
- t)))
- (defun gnus-find-matching-articles (header regexp)
- "Return a list of all articles that match REGEXP on HEADER.
- This search includes all articles in the current group that Gnus has
- fetched headers for, whether they are displayed or not."
- (let ((articles nil)
- ;; Can't eta-reduce because it's a macro.
- (func `(lambda (h) (,(intern (concat "mail-header-" header)) h)))
- (case-fold-search t))
- (dolist (header gnus-newsgroup-headers)
- (when (string-match regexp (funcall func header))
- (push (mail-header-number header) articles)))
- (nreverse articles)))
- (defun gnus-summary-find-matching (header regexp &optional backward unread
- not-case-fold not-matching)
- "Return a list of all articles that match REGEXP on HEADER.
- The search stars on the current article and goes forwards unless
- BACKWARD is non-nil. If BACKWARD is `all', do all articles.
- If UNREAD is non-nil, only unread articles will
- be taken into consideration. If NOT-CASE-FOLD, case won't be folded
- in the comparisons. If NOT-MATCHING, return a list of all articles that
- not match REGEXP on HEADER."
- (let ((case-fold-search (not not-case-fold))
- articles d func)
- (if (consp header)
- (if (eq (car header) 'extra)
- (setq func
- `(lambda (h)
- (or (cdr (assq ',(cdr header) (mail-header-extra h)))
- "")))
- (error "%s is an invalid header" header))
- (unless (fboundp (intern (concat "mail-header-" header)))
- (error "%s is not a valid header" header))
- (setq func `(lambda (h) (,(intern (concat "mail-header-" header)) h))))
- (dolist (d (if (eq backward 'all)
- gnus-newsgroup-data
- (gnus-data-find-list
- (gnus-summary-article-number)
- (gnus-data-list backward))))
- (when (and (or (not unread) ; We want all articles...
- (gnus-data-unread-p d)) ; Or just unreads.
- (vectorp (gnus-data-header d)) ; It's not a pseudo.
- (if not-matching
- (not (string-match
- regexp
- (funcall func (gnus-data-header d))))
- (string-match regexp
- (funcall func (gnus-data-header d)))))
- (push (gnus-data-number d) articles))) ; Success!
- (nreverse articles)))
- (defun gnus-summary-execute-command (header regexp command &optional backward)
- "Search forward for an article whose HEADER matches REGEXP and execute COMMAND.
- If HEADER is an empty string (or nil), the match is done on the entire
- article. If BACKWARD (the prefix) is non-nil, search backward instead."
- (interactive
- (list (let ((completion-ignore-case t))
- (gnus-completing-read
- "Header name"
- (mapcar 'symbol-name
- (append
- '(Number Subject From Lines Date
- Message-ID Xref References Body)
- gnus-extra-headers))
- 'require-match))
- (read-string "Regexp: ")
- (read-key-sequence "Command: ")
- current-prefix-arg))
- (when (equal header "Body")
- (setq header ""))
- ;; Hidden thread subtrees must be searched as well.
- (gnus-summary-show-all-threads)
- ;; We don't want to change current point nor window configuration.
- (save-excursion
- (save-window-excursion
- (let (gnus-visual
- gnus-treat-strip-trailing-blank-lines
- gnus-treat-strip-leading-blank-lines
- gnus-treat-strip-multiple-blank-lines
- gnus-treat-hide-boring-headers
- gnus-treat-fold-newsgroups
- gnus-article-prepare-hook)
- (gnus-message 6 "Executing %s..." (key-description command))
- ;; We'd like to execute COMMAND interactively so as to give arguments.
- (gnus-execute header regexp
- `(call-interactively ',(key-binding command))
- backward)
- (gnus-message 6 "Executing %s...done" (key-description command))))))
- (defun gnus-summary-beginning-of-article ()
- "Scroll the article back to the beginning."
- (interactive)
- (gnus-summary-select-article)
- (gnus-configure-windows 'article)
- (gnus-eval-in-buffer-window gnus-article-buffer
- (widen)
- (goto-char (point-min))
- (when gnus-break-pages
- (gnus-narrow-to-page))))
- (defun gnus-summary-end-of-article ()
- "Scroll to the end of the article."
- (interactive)
- (gnus-summary-select-article)
- (gnus-configure-windows 'article)
- (gnus-eval-in-buffer-window gnus-article-buffer
- (widen)
- (goto-char (point-max))
- (recenter -3)
- (when gnus-break-pages
- (gnus-narrow-to-page))))
- (defun gnus-summary-print-truncate-and-quote (string &optional len)
- "Truncate to LEN and quote all \"(\"'s in STRING."
- (gnus-replace-in-string (if (and len (> (length string) len))
- (substring string 0 len)
- string)
- "[()]" "\\\\\\&"))
- (defun gnus-summary-print-article (&optional filename n)
- "Generate and print a PostScript image of the process-marked (mail) articles.
- If used interactively, print the current article if none are
- process-marked. With prefix arg, prompt the user for the name of the
- file to save in.
- When used from Lisp, accept two optional args FILENAME and N. N means
- to print the next N articles. If N is negative, print the N previous
- articles. If N is nil and articles have been marked with the process
- mark, print these instead.
- If the optional first argument FILENAME is nil, send the image to the
- printer. If FILENAME is a string, save the PostScript image in a file with
- that name. If FILENAME is a number, prompt the user for the name of the file
- to save in."
- (interactive (list (ps-print-preprint current-prefix-arg)))
- (dolist (article (gnus-summary-work-articles n))
- (gnus-summary-select-article nil nil 'pseudo article)
- (gnus-eval-in-buffer-window gnus-article-buffer
- (gnus-print-buffer))
- (gnus-summary-remove-process-mark article))
- (ps-despool filename))
- (defun gnus-print-buffer ()
- (let ((ps-left-header
- (list
- (concat "("
- (gnus-summary-print-truncate-and-quote
- (mail-header-subject gnus-current-headers)
- 66) ")")
- (concat "("
- (gnus-summary-print-truncate-and-quote
- (mail-header-from gnus-current-headers)
- 45) ")")))
- (ps-right-header
- (list
- "/pagenumberstring load"
- (concat "("
- (mail-header-date gnus-current-headers) ")"))))
- (gnus-run-hooks 'gnus-ps-print-hook)
- (save-excursion
- (if ps-print-color-p
- (ps-spool-buffer-with-faces)
- (ps-spool-buffer)))))
- (declare-function gnus-flush-original-article-buffer "gnus-art" ())
- (defun gnus-summary-show-complete-article ()
- "Show a complete version of the current article.
- This is only useful if you're looking at a partial version of the
- article currently."
- (interactive)
- (let ((gnus-keep-backlog nil)
- (gnus-use-cache nil)
- (gnus-agent nil)
- (variable (intern
- (format "%s-fetch-partial-articles"
- (car (gnus-find-method-for-group
- gnus-newsgroup-name)))
- obarray))
- old-val)
- (unwind-protect
- (progn
- (setq old-val (symbol-value variable))
- (set variable nil)
- (gnus-flush-original-article-buffer)
- (gnus-summary-show-article))
- (set variable old-val))))
- (defun gnus-summary-show-article (&optional arg)
- "Force redisplaying of the current article.
- If ARG (the prefix) is a number, show the article with the charset
- defined in `gnus-summary-show-article-charset-alist', or the charset
- input.
- If ARG (the prefix) is non-nil and not a number, show the article,
- but without running any of the article treatment functions
- article. Normally, the keystroke is `C-u g'. When using `C-u
- C-u g', show the raw article."
- (interactive "P")
- (cond
- ((numberp arg)
- (gnus-summary-show-article t)
- (let ((gnus-newsgroup-charset
- (or (cdr (assq arg gnus-summary-show-article-charset-alist))
- (mm-read-coding-system
- "View as charset: " ;; actually it is coding system.
- (with-current-buffer gnus-article-buffer
- (mm-detect-coding-region (point) (point-max))))))
- (gnus-newsgroup-ignored-charsets 'gnus-all))
- (gnus-summary-select-article nil 'force)
- (let ((deps gnus-newsgroup-dependencies)
- head header lines)
- (with-current-buffer gnus-original-article-buffer
- (save-restriction
- (message-narrow-to-head)
- (setq head (buffer-string))
- (goto-char (point-min))
- (unless (re-search-forward "^lines:[ \t]\\([0-9]+\\)" nil t)
- (goto-char (point-max))
- (widen)
- (setq lines (1- (count-lines (point) (point-max))))))
- (with-temp-buffer
- (insert (format "211 %d Article retrieved.\n"
- (cdr gnus-article-current)))
- (insert head)
- (if lines (insert (format "Lines: %d\n" lines)))
- (insert ".\n")
- (let ((nntp-server-buffer (current-buffer)))
- (setq header (car (gnus-get-newsgroup-headers deps t))))))
- (gnus-data-set-header
- (gnus-data-find (cdr gnus-article-current))
- header)
- (gnus-summary-update-article-line
- (cdr gnus-article-current) header)
- (when (gnus-summary-goto-subject (cdr gnus-article-current) nil t)
- (gnus-summary-update-secondary-mark (cdr gnus-article-current))))))
- ((not arg)
- ;; Select the article the normal way.
- (if (eq mm-text-html-renderer 'shr)
- (progn
- (require 'shr)
- (let ((shr-ignore-cache t))
- (gnus-summary-select-article nil 'force)))
- (gnus-summary-select-article nil 'force)))
- ((equal arg '(16))
- ;; C-u C-u g
- (let ((gnus-inhibit-article-treatments t))
- (gnus-summary-select-article nil 'force)))
- (t
- ;; We have to require this here to make sure that the following
- ;; dynamic binding isn't shadowed by autoloading.
- (require 'gnus-async)
- (require 'gnus-art)
- ;; Bind the article treatment functions to nil.
- (let ((gnus-have-all-headers t)
- gnus-article-prepare-hook
- gnus-article-decode-hook
- gnus-display-mime-function
- gnus-break-pages)
- ;; Destroy any MIME parts.
- (when (gnus-buffer-live-p gnus-article-buffer)
- (with-current-buffer gnus-article-buffer
- (gnus-article-stop-animations)
- (gnus-stop-downloads)
- (mm-destroy-parts gnus-article-mime-handles)
- ;; Set it to nil for safety reason.
- (setq gnus-article-mime-handle-alist nil)
- (setq gnus-article-mime-handles nil)))
- (gnus-summary-select-article nil 'force))))
- (gnus-summary-goto-subject gnus-current-article)
- (gnus-summary-position-point))
- (defun gnus-summary-show-raw-article ()
- "Show the raw article without any article massaging functions being run."
- (interactive)
- (gnus-summary-show-article t))
- (defun gnus-summary-verbose-headers (&optional arg)
- "Toggle permanent full header display.
- If ARG is a positive number, turn header display on.
- If ARG is a negative number, turn header display off."
- (interactive "P")
- (setq gnus-show-all-headers
- (cond ((or (not (numberp arg))
- (zerop arg))
- (not gnus-show-all-headers))
- ((natnump arg)
- t)))
- (gnus-summary-show-article))
- (declare-function article-narrow-to-head "gnus-art" ())
- (declare-function gnus-article-hidden-text-p "gnus-art" (type))
- (declare-function gnus-delete-wash-type "gnus-art" (type))
- (declare-function gnus-mime-buttonize-attachments-in-header
- "gnus-art" (&optional interactive))
- (defun gnus-summary-toggle-header (&optional arg)
- "Show the headers if they are hidden, or hide them if they are shown.
- If ARG is a positive number, show the entire header.
- If ARG is a negative number, hide the unwanted header lines."
- (interactive "P")
- (let ((window (and (gnus-buffer-live-p gnus-article-buffer)
- (get-buffer-window gnus-article-buffer t))))
- (with-current-buffer gnus-article-buffer
- (widen)
- (article-narrow-to-head)
- (let* ((inhibit-read-only t)
- (inhibit-point-motion-hooks t)
- (hidden (if (numberp arg)
- (>= arg 0)
- (or (not (looking-at "[^ \t\n]+:"))
- (gnus-article-hidden-text-p 'headers))))
- s e)
- (delete-region (point-min) (point-max))
- (with-current-buffer gnus-original-article-buffer
- (goto-char (setq s (point-min)))
- (setq e (if (search-forward "\n\n" nil t)
- (1- (point))
- (point-max))))
- (insert-buffer-substring gnus-original-article-buffer s e)
- (run-hooks 'gnus-article-decode-hook)
- (if hidden
- (let ((gnus-treat-hide-headers nil)
- (gnus-treat-hide-boring-headers nil))
- (gnus-delete-wash-type 'headers)
- (gnus-treat-article 'head))
- (gnus-treat-article 'head)
- ;; Add attachment buttons to the header.
- (when gnus-mime-display-attachment-buttons-in-header
- (gnus-mime-buttonize-attachments-in-header)))
- (widen)
- (if window
- (set-window-start window (goto-char (point-min))))
- (if gnus-break-pages
- (gnus-narrow-to-page)
- (when (gnus-visual-p 'page-marker)
- (let ((inhibit-read-only t))
- (gnus-remove-text-with-property 'gnus-prev)
- (gnus-remove-text-with-property 'gnus-next))))
- (gnus-set-mode-line 'article)))))
- (defun gnus-summary-show-all-headers ()
- "Make all header lines visible."
- (interactive)
- (gnus-summary-toggle-header 1))
- (defun gnus-summary-caesar-message (&optional arg)
- "Caesar rotate the current article by 13.
- With a non-numerical prefix, also rotate headers. A numerical
- prefix specifies how many places to rotate each letter forward."
- (interactive "P")
- (gnus-summary-select-article)
- (let ((mail-header-separator ""))
- (gnus-eval-in-buffer-window gnus-article-buffer
- (save-restriction
- (widen)
- (let ((start (window-start))
- (inhibit-read-only t))
- (if (equal arg '(4))
- (message-caesar-buffer-body nil t)
- (message-caesar-buffer-body arg))
- (set-window-start (get-buffer-window (current-buffer)) start)))))
- ;; Create buttons and stuff...
- (gnus-treat-article nil))
- (declare-function idna-to-unicode "ext:idna" (str))
- (defun gnus-summary-idna-message (&optional arg)
- "Decode IDNA encoded domain names in the current articles.
- IDNA encoded domain names looks like `xn--bar'. If a string
- remain unencoded after running this function, it is likely an
- invalid IDNA string (`xn--bar' is invalid).
- You must have GNU Libidn (URL `http://www.gnu.org/software/libidn/')
- installed for this command to work."
- (interactive "P")
- (if (not (and (mm-coding-system-p 'utf-8)
- (condition-case nil
- (require 'idna)
- (file-error)
- (invalid-operation))
- (symbol-value 'idna-program)
- (executable-find (symbol-value 'idna-program))))
- (gnus-message
- 5 "GNU Libidn not installed properly (`idn' or `idna.el' missing)")
- (gnus-summary-select-article)
- (let ((mail-header-separator ""))
- (gnus-eval-in-buffer-window gnus-article-buffer
- (save-restriction
- (widen)
- (let ((start (window-start))
- buffer-read-only)
- (while (re-search-forward "\\(xn--[-0-9a-z]+\\)" nil t)
- (replace-match (idna-to-unicode (match-string 1))))
- (set-window-start (get-buffer-window (current-buffer)) start)))))))
- (defun gnus-summary-morse-message (&optional arg)
- "Morse decode the current article."
- (interactive "P")
- (gnus-summary-select-article)
- (let ((mail-header-separator ""))
- (gnus-eval-in-buffer-window gnus-article-buffer
- (save-excursion
- (save-restriction
- (widen)
- (let ((pos (window-start))
- (inhibit-read-only t))
- (goto-char (point-min))
- (when (message-goto-body)
- (gnus-narrow-to-body))
- (goto-char (point-min))
- (while (search-forward "·" (point-max) t)
- (replace-match "."))
- (unmorse-region (point-min) (point-max))
- (widen)
- (set-window-start (get-buffer-window (current-buffer)) pos)))))))
- (defun gnus-summary-stop-page-breaking ()
- "Stop page breaking in the current article."
- (interactive)
- (gnus-summary-select-article)
- (gnus-eval-in-buffer-window gnus-article-buffer
- (widen)
- (when (gnus-visual-p 'page-marker)
- (let ((inhibit-read-only t))
- (gnus-remove-text-with-property 'gnus-prev)
- (gnus-remove-text-with-property 'gnus-next))
- (setq gnus-page-broken nil))))
- (defun gnus-summary-move-article (&optional n to-newsgroup
- select-method action)
- "Move the current article to a different newsgroup.
- If N is a positive number, move the N next articles.
- If N is a negative number, move the N previous articles.
- If N is nil and any articles have been marked with the process mark,
- move those articles instead.
- If TO-NEWSGROUP is string, do not prompt for a newsgroup to move to.
- If SELECT-METHOD is non-nil, do not move to a specific newsgroup, but
- re-spool using this method.
- When called interactively with TO-NEWSGROUP being nil, the value of
- the variable `gnus-move-split-methods' is used for finding a default
- for the target newsgroup.
- For this function to work, both the current newsgroup and the
- newsgroup that you want to move to have to support the `request-move'
- and `request-accept' functions.
- ACTION can be either `move' (the default), `crosspost' or `copy'."
- (interactive "P")
- (unless action
- (setq action 'move))
- ;; Check whether the source group supports the required functions.
- (cond ((and (eq action 'move)
- (not (gnus-check-backend-function
- 'request-move-article gnus-newsgroup-name)))
- (error "The current group does not support article moving"))
- ((and (eq action 'crosspost)
- (not (gnus-check-backend-function
- 'request-replace-article gnus-newsgroup-name)))
- (error "The current group does not support article editing")))
- (let ((articles (gnus-summary-work-articles n))
- (prefix (if (gnus-check-backend-function
- 'request-move-article gnus-newsgroup-name)
- (funcall gnus-move-group-prefix-function
- gnus-newsgroup-name)
- ""))
- (names '((move "Move" "Moving")
- (copy "Copy" "Copying")
- (crosspost "Crosspost" "Crossposting")))
- (copy-buf (save-excursion
- (nnheader-set-temp-buffer " *copy article*")))
- art-group to-method new-xref article to-groups
- articles-to-update-marks encoded)
- (unless (assq action names)
- (error "Unknown action %s" action))
- ;; Read the newsgroup name.
- (when (and (not to-newsgroup)
- (not select-method))
- (if (and gnus-move-split-methods
- (not
- (and (memq gnus-current-article articles)
- (gnus-buffer-live-p gnus-original-article-buffer))))
- ;; When `gnus-move-split-methods' is non-nil, we have to
- ;; select an article to give `gnus-read-move-group-name' an
- ;; opportunity to suggest an appropriate default. However,
- ;; we needn't render or mark the article.
- (let ((gnus-display-mime-function nil)
- (gnus-article-prepare-hook nil)
- (gnus-mark-article-hook nil))
- (gnus-summary-select-article nil nil nil (car articles))))
- (setq to-newsgroup (gnus-read-move-group-name
- (cadr (assq action names))
- (symbol-value
- (intern (format "gnus-current-%s-group" action)))
- articles prefix)
- encoded to-newsgroup
- to-method (gnus-server-to-method (gnus-group-method to-newsgroup)))
- (set (intern (format "gnus-current-%s-group" action))
- (mm-decode-coding-string
- to-newsgroup
- (gnus-group-name-charset to-method to-newsgroup))))
- (unless to-method
- (setq to-method (or select-method
- (gnus-server-to-method
- (gnus-group-method to-newsgroup)))))
- (setq to-newsgroup
- (or encoded
- (and to-newsgroup
- (mm-encode-coding-string
- to-newsgroup
- (gnus-group-name-charset to-method to-newsgroup)))))
- ;; Check the method we are to move this article to...
- (unless (gnus-check-backend-function
- 'request-accept-article (car to-method))
- (error "%s does not support article copying" (car to-method)))
- (unless (gnus-check-server to-method)
- (error "Can't open server %s" (car to-method)))
- (gnus-message 6 "%s to %s: %s..."
- (caddr (assq action names))
- (or (car select-method)
- (gnus-group-decoded-name to-newsgroup))
- articles)
- (while articles
- (setq article (pop articles))
- ;; Set any marks that may have changed in the summary buffer.
- (when gnus-preserve-marks
- (gnus-summary-push-marks-to-backend article))
- (setq
- art-group
- (cond
- ;; Move the article.
- ((eq action 'move)
- ;; Remove this article from future suppression.
- (gnus-dup-unsuppress-article article)
- (let* ((from-method (gnus-find-method-for-group
- gnus-newsgroup-name))
- (to-method (or select-method
- (gnus-find-method-for-group to-newsgroup)))
- (move-is-internal (gnus-server-equal from-method to-method)))
- (gnus-request-move-article
- article ; Article to move
- gnus-newsgroup-name ; From newsgroup
- (nth 1 (gnus-find-method-for-group
- gnus-newsgroup-name)) ; Server
- (list 'gnus-request-accept-article
- to-newsgroup (list 'quote select-method)
- (not articles) t) ; Accept form
- (not articles) ; Only save nov last time
- (and move-is-internal
- to-newsgroup ; Not respooling
- ; Is this move internal?
- (gnus-group-real-name to-newsgroup)))))
- ;; Copy the article.
- ((eq action 'copy)
- (with-current-buffer copy-buf
- (when (gnus-request-article-this-buffer article
- gnus-newsgroup-name)
- (save-restriction
- (nnheader-narrow-to-headers)
- (dolist (hdr gnus-copy-article-ignored-headers)
- (message-remove-header hdr t)))
- (gnus-request-accept-article
- to-newsgroup select-method (not articles) t))))
- ;; Crosspost the article.
- ((eq action 'crosspost)
- (let ((xref (message-tokenize-header
- (mail-header-xref (gnus-summary-article-header
- article))
- " ")))
- (setq new-xref (concat (gnus-group-real-name gnus-newsgroup-name)
- ":" (number-to-string article)))
- (unless xref
- (setq xref (list (system-name))))
- (setq new-xref
- (concat
- (mapconcat 'identity
- (delete "Xref:" (delete new-xref xref))
- " ")
- " " new-xref))
- (with-current-buffer copy-buf
- ;; First put the article in the destination group.
- (gnus-request-article-this-buffer article gnus-newsgroup-name)
- (when (consp (setq art-group
- (gnus-request-accept-article
- to-newsgroup select-method (not articles)
- t)))
- (setq new-xref (concat new-xref " " (car art-group)
- ":"
- (number-to-string (cdr art-group))))
- ;; Now we have the new Xrefs header, so we insert
- ;; it and replace the new article.
- (nnheader-replace-header "Xref" new-xref)
- (gnus-request-replace-article
- (cdr art-group) to-newsgroup (current-buffer) t)
- art-group))))))
- (cond
- ((not art-group)
- (gnus-message 1 "Couldn't %s article %s: %s"
- (cadr (assq action names)) article
- (nnheader-get-report (car to-method))))
- ((eq art-group 'junk)
- (when (eq action 'move)
- (gnus-summary-mark-article article gnus-canceled-mark)
- (gnus-message 4 "Deleted article %s" article)
- ;; run the delete hook
- (run-hook-with-args 'gnus-summary-article-delete-hook
- action
- (gnus-data-header
- (assoc article (gnus-data-list nil)))
- gnus-newsgroup-name nil
- select-method)))
- (t
- (let* ((pto-group (gnus-group-prefixed-name
- (car art-group) to-method))
- (info (gnus-get-info pto-group))
- (to-group (gnus-info-group info))
- to-marks)
- ;; Update the group that has been moved to.
- (when (and info
- (memq action '(move copy)))
- (unless (member to-group to-groups)
- (push to-group to-groups))
- (when (and (not (memq article gnus-newsgroup-unreads))
- (cdr art-group))
- (push 'read to-marks)
- (gnus-info-set-read
- info (gnus-add-to-range (gnus-info-read info)
- (list (cdr art-group)))))
- ;; See whether the article is to be put in the cache.
- (let* ((expirable (gnus-group-auto-expirable-p to-group))
- (marks (if expirable
- gnus-article-mark-lists
- (delete '(expirable . expire)
- (copy-sequence
- gnus-article-mark-lists))))
- (to-article (cdr art-group)))
- ;; Enter the article into the cache in the new group,
- ;; if that is required.
- (when (and to-article
- gnus-use-cache)
- (gnus-cache-possibly-enter-article
- to-group to-article
- (memq article gnus-newsgroup-marked)
- (memq article gnus-newsgroup-dormant)
- (memq article gnus-newsgroup-unreads)))
- (when (and gnus-preserve-marks
- to-article)
- ;; Copy any marks over to the new group.
- (when (and (equal to-group gnus-newsgroup-name)
- (not (memq article gnus-newsgroup-unreads)))
- ;; Mark this article as read in this group.
- (push (cons to-article gnus-read-mark)
- gnus-newsgroup-reads)
- ;; Increase the active status of this group.
- (setcdr (gnus-active to-group) to-article)
- (setcdr gnus-newsgroup-active to-article))
- (while marks
- (when (eq (gnus-article-mark-to-type (cdar marks)) 'list)
- (when (memq article (symbol-value
- (intern (format "gnus-newsgroup-%s"
- (caar marks)))))
- (push (cdar marks) to-marks)
- ;; If the other group is the same as this group,
- ;; then we have to add the mark to the list.
- (when (equal to-group gnus-newsgroup-name)
- (set (intern (format "gnus-newsgroup-%s"
- (caar marks)))
- (cons to-article
- (symbol-value
- (intern (format "gnus-newsgroup-%s"
- (caar marks)))))))
- ;; Copy the marks to other group.
- (gnus-add-marked-articles
- to-group (cdar marks) (list to-article) info)))
- (setq marks (cdr marks)))
- (when (and expirable
- gnus-mark-copied-or-moved-articles-as-expirable
- (not (memq 'expire to-marks)))
- ;; Mark this article as expirable.
- (push 'expire to-marks)
- (when (equal to-group gnus-newsgroup-name)
- (push to-article gnus-newsgroup-expirable))
- ;; Copy the expirable mark to other group.
- (gnus-add-marked-articles
- to-group 'expire (list to-article) info))
- (when (and to-marks
- (gnus-method-option-p
- (gnus-find-method-for-group to-group)
- 'server-marks))
- (gnus-request-set-mark
- to-group (list (list (list to-article) 'add to-marks)))))
- (gnus-dribble-enter
- (concat "(gnus-group-set-info '"
- (gnus-prin1-to-string (gnus-get-info to-group))
- ")")
- (concat "^(gnus-group-set-info '(\""
- (regexp-quote to-group) "\""))))
- ;; Update the Xref header in this article to point to
- ;; the new crossposted article we have just created.
- (when (eq action 'crosspost)
- (with-current-buffer copy-buf
- (gnus-request-article-this-buffer article gnus-newsgroup-name)
- (nnheader-replace-header "Xref" new-xref)
- (gnus-request-replace-article
- article gnus-newsgroup-name (current-buffer) t)))
- ;; run the move/copy/crosspost/respool hook
- (run-hook-with-args 'gnus-summary-article-move-hook
- action
- (gnus-data-header
- (assoc article (gnus-data-list nil)))
- gnus-newsgroup-name
- to-newsgroup
- select-method))
- ;;;!!!Why is this necessary?
- (set-buffer gnus-summary-buffer)
- (when (eq action 'move)
- (save-excursion
- (gnus-summary-goto-subject article)
- (gnus-summary-mark-article article gnus-canceled-mark)))))
- (push article articles-to-update-marks))
- (save-excursion
- (apply 'gnus-summary-remove-process-mark articles-to-update-marks))
- ;; Re-activate all groups that have been moved to.
- (with-current-buffer gnus-group-buffer
- (let ((gnus-group-marked to-groups))
- (gnus-group-get-new-news-this-group nil t)))
- (gnus-kill-buffer copy-buf)
- (gnus-summary-position-point)
- (gnus-set-mode-line 'summary)))
- (defun gnus-summary-push-marks-to-backend (article)
- (let ((set nil)
- (del nil)
- (marks gnus-article-mark-lists))
- (unless (memq article gnus-newsgroup-unreads)
- (push 'read set))
- (while marks
- (if (and (eq (gnus-article-mark-to-type (cdar marks)) 'list)
- (memq article (symbol-value
- (intern (format "gnus-newsgroup-%s"
- (caar marks))))))
- (push (cdar marks) set)
- (push (cdar marks) del))
- (pop marks))
- (gnus-request-set-mark gnus-newsgroup-name `(((,article) set ,set)
- ((,article) del ,del)))))
- (defun gnus-summary-copy-article (&optional n to-newsgroup select-method)
- "Copy the current article to some other group.
- If TO-NEWSGROUP is string, do not prompt for a newsgroup to copy to.
- When called interactively, if TO-NEWSGROUP is nil, use the value of
- the variable `gnus-move-split-methods' for finding a default target
- newsgroup.
- If SELECT-METHOD is non-nil, do not move to a specific newsgroup, but
- re-spool using this method."
- (interactive "P")
- (gnus-summary-move-article n to-newsgroup select-method 'copy))
- (defun gnus-summary-crosspost-article (&optional n)
- "Crosspost the current article to some other group."
- (interactive "P")
- (gnus-summary-move-article n nil nil 'crosspost))
- (defcustom gnus-summary-respool-default-method nil
- "Default method type for respooling an article.
- If nil, use to the current newsgroup method."
- :type 'symbol
- :group 'gnus-summary-mail)
- (defun gnus-summary-respool-article (&optional n method)
- "Respool the current article.
- The article will be squeezed through the mail spooling process again,
- which means that it will be put in some mail newsgroup or other
- depending on `nnmail-split-methods'.
- If N is a positive number, respool the N next articles.
- If N is a negative number, respool the N previous articles.
- If N is nil and any articles have been marked with the process mark,
- respool those articles instead.
- Respooling can be done both from mail groups and \"real\" newsgroups.
- In the former case, the articles in question will be moved from the
- current group into whatever groups they are destined to. In the
- latter case, they will be copied into the relevant groups."
- (interactive
- (list current-prefix-arg
- (let* ((methods (mapcar #'car (gnus-methods-using 'respool)))
- (methname
- (symbol-name (or gnus-summary-respool-default-method
- (car (gnus-find-method-for-group
- gnus-newsgroup-name)))))
- (method
- (gnus-completing-read
- "Backend to use when respooling"
- methods t nil 'gnus-mail-method-history methname))
- ms)
- (cond
- ((zerop (length (setq ms (gnus-servers-using-backend
- (intern method)))))
- (list (intern method) ""))
- ((= 1 (length ms))
- (car ms))
- (t
- (let ((ms-alist (mapcar (lambda (m) (cons (cadr m) m)) ms)))
- (cdr (assoc (gnus-completing-read "Server name" ms-alist t)
- ms-alist))))))))
- (unless method
- (error "No method given for respooling"))
- (if (assoc (symbol-name
- (car (gnus-find-method-for-group gnus-newsgroup-name)))
- (gnus-methods-using 'respool))
- (gnus-summary-move-article n nil method)
- (gnus-summary-copy-article n nil method)))
- (defun gnus-summary-import-article (file &optional edit)
- "Import an arbitrary file into a mail newsgroup."
- (interactive "fImport file: \nP")
- (let ((group gnus-newsgroup-name)
- (now (current-time))
- atts lines group-art)
- (unless (gnus-check-backend-function 'request-accept-article group)
- (error "%s does not support article importing" group))
- (or (file-readable-p file)
- (not (file-regular-p file))
- (error "Can't read %s" file))
- (with-current-buffer (gnus-get-buffer-create " *import file*")
- (erase-buffer)
- (nnheader-insert-file-contents file)
- (goto-char (point-min))
- (if (nnheader-article-p)
- (save-restriction
- (goto-char (point-min))
- (search-forward "\n\n" nil t)
- (narrow-to-region (point-min) (1- (point)))
- (goto-char (point-min))
- (unless (re-search-forward "^date:" nil t)
- (goto-char (point-max))
- (insert "Date: " (message-make-date (nth 5 atts)) "\n")))
- ;; This doesn't look like an article, so we fudge some headers.
- (setq atts (file-attributes file)
- lines (count-lines (point-min) (point-max)))
- (insert "From: " (read-string "From: ") "\n"
- "Subject: " (read-string "Subject: ") "\n"
- "Date: " (message-make-date (nth 5 atts)) "\n"
- "Message-ID: " (message-make-message-id) "\n"
- "Lines: " (int-to-string lines) "\n"
- "Chars: " (int-to-string (nth 7 atts)) "\n\n"))
- (setq group-art (gnus-request-accept-article group nil t))
- (kill-buffer (current-buffer)))
- (setq gnus-newsgroup-active (gnus-activate-group group))
- (forward-line 1)
- (gnus-summary-goto-article (cdr group-art) nil t)
- (when edit
- (gnus-summary-edit-article))))
- (defun gnus-summary-create-article ()
- "Create an article in a mail newsgroup."
- (interactive)
- (let ((group gnus-newsgroup-name)
- (now (current-time))
- group-art)
- (unless (gnus-check-backend-function 'request-accept-article group)
- (error "%s does not support article importing" group))
- (with-current-buffer (gnus-get-buffer-create " *import file*")
- (erase-buffer)
- (goto-char (point-min))
- ;; This doesn't look like an article, so we fudge some headers.
- (insert "From: " (read-string "From: ") "\n"
- "Subject: " (read-string "Subject: ") "\n"
- "Date: " (message-make-date now) "\n"
- "Message-ID: " (message-make-message-id) "\n")
- (setq group-art (gnus-request-accept-article group nil t))
- (kill-buffer (current-buffer)))
- (setq gnus-newsgroup-active (gnus-activate-group group))
- (forward-line 1)
- (gnus-summary-goto-article (cdr group-art) nil t)
- (gnus-summary-edit-article)))
- (defun gnus-summary-article-posted-p ()
- "Say whether the current (mail) article is available from news as well.
- This will be the case if the article has both been mailed and posted."
- (interactive)
- (let ((id (mail-header-references (gnus-summary-article-header)))
- (gnus-override-method (car (gnus-refer-article-methods))))
- (if (gnus-request-head id "")
- (gnus-message 2 "The current message was found on %s"
- gnus-override-method)
- (gnus-message 2 "The current message couldn't be found on %s"
- gnus-override-method)
- nil)))
- (defun gnus-summary-expire-articles (&optional now)
- "Expire all articles that are marked as expirable in the current group."
- (interactive)
- (when (and (not gnus-group-is-exiting-without-update-p)
- (gnus-check-backend-function
- 'request-expire-articles gnus-newsgroup-name))
- ;; This backend supports expiry.
- (let* ((total (gnus-group-total-expirable-p gnus-newsgroup-name))
- (expirable
- (gnus-list-range-difference
- (if total
- (progn
- ;; We need to update the info for
- ;; this group for `gnus-list-of-read-articles'
- ;; to give us the right answer.
- (gnus-run-hooks 'gnus-exit-group-hook)
- (gnus-summary-update-info)
- (gnus-list-of-read-articles gnus-newsgroup-name))
- (setq gnus-newsgroup-expirable
- (sort gnus-newsgroup-expirable '<)))
- gnus-newsgroup-unexist))
- (expiry-wait (if now 'immediate
- (gnus-group-find-parameter
- gnus-newsgroup-name 'expiry-wait)))
- (nnmail-expiry-target
- (or (gnus-group-find-parameter gnus-newsgroup-name 'expiry-target)
- nnmail-expiry-target))
- es)
- (when expirable
- ;; There are expirable articles in this group, so we run them
- ;; through the expiry process.
- (gnus-message 6 "Expiring articles...")
- (when (gnus-check-group gnus-newsgroup-name)
- ;; The list of articles that weren't expired is returned.
- (save-excursion
- (if expiry-wait
- (let ((nnmail-expiry-wait-function nil)
- (nnmail-expiry-wait expiry-wait))
- (setq es (gnus-request-expire-articles
- expirable gnus-newsgroup-name)))
- (setq es (gnus-request-expire-articles
- expirable gnus-newsgroup-name)))
- (unless total
- (setq gnus-newsgroup-expirable es))
- ;; We go through the old list of expirable, and mark all
- ;; really expired articles as nonexistent.
- (unless (eq es expirable) ;If nothing was expired, we don't mark.
- (let ((gnus-use-cache nil))
- (dolist (article expirable)
- (when (and (not (memq article es))
- (gnus-data-find article))
- (gnus-summary-mark-article article gnus-canceled-mark)
- (run-hook-with-args
- 'gnus-summary-article-expire-hook
- 'delete
- (gnus-data-header (assoc article (gnus-data-list nil)))
- gnus-newsgroup-name
- (cond
- ((stringp nnmail-expiry-target) nnmail-expiry-target)
- ((eq nnmail-expiry-target 'delete) nil)
- (t
- (let ((rescall (funcall nnmail-expiry-target
- gnus-newsgroup-name)))
- (if (stringp rescall) rescall nil))))
- nil)))))))
- (gnus-message 6 "Expiring articles...done")))))
- (defun gnus-summary-expire-articles-now ()
- "Expunge all expirable articles in the current group.
- This means that *all* articles that are marked as expirable will be
- deleted forever, right now."
- (interactive)
- (or gnus-expert-user
- (gnus-yes-or-no-p
- "Are you really, really sure you want to delete all expirable messages? ")
- (error "Phew!"))
- (gnus-summary-expire-articles t))
- ;; Suggested by Jack Vinson <vinson@unagi.cis.upenn.edu>.
- (defun gnus-summary-delete-article (&optional n)
- "Delete the N next (mail) articles.
- This command actually deletes articles. This is not a marking
- command. The article will disappear forever from your life, never to
- return.
- If N is negative, delete backwards.
- If N is nil and articles have been marked with the process mark,
- delete these instead.
- If `gnus-novice-user' is non-nil you will be asked for
- confirmation before the articles are deleted."
- (interactive "P")
- (unless (gnus-check-backend-function 'request-expire-articles
- gnus-newsgroup-name)
- (error "The current newsgroup does not support article deletion"))
- (unless (gnus-check-server (gnus-find-method-for-group gnus-newsgroup-name))
- (error "Couldn't open server"))
- ;; Compute the list of articles to delete.
- (let ((articles (sort (copy-sequence (gnus-summary-work-articles n)) '<))
- (nnmail-expiry-target 'delete)
- not-deleted)
- (if (and gnus-novice-user
- (not (gnus-yes-or-no-p
- (format "Do you really want to delete %s forever? "
- (if (> (length articles) 1)
- (format "these %s articles" (length articles))
- "this article")))))
- ()
- ;; Delete the articles.
- (setq not-deleted (gnus-request-expire-articles
- articles gnus-newsgroup-name 'force))
- (save-excursion
- (while articles
- (gnus-summary-remove-process-mark (car articles))
- ;; The backend might not have been able to delete the article
- ;; after all.
- (unless (memq (car articles) not-deleted)
- (gnus-summary-mark-article (car articles) gnus-canceled-mark)
- (let* ((article (car articles))
- (ghead (gnus-data-header
- (assoc article (gnus-data-list nil)))))
- (run-hook-with-args 'gnus-summary-article-delete-hook
- 'delete ghead gnus-newsgroup-name nil
- nil)))
- (setq articles (cdr articles))))
- (when not-deleted
- (gnus-message 4 "Couldn't delete articles %s" not-deleted)))
- (gnus-summary-position-point)
- (gnus-set-mode-line 'summary)
- not-deleted))
- (defun gnus-summary-edit-article (&optional arg)
- "Edit the current article.
- This will have permanent effect only in mail groups.
- If ARG is nil, edit the decoded articles.
- If ARG is 1, edit the raw articles.
- If ARG is 2, edit the raw articles even in read-only groups.
- If ARG is 3, edit the articles with the current handles.
- Otherwise, allow editing of articles even in read-only
- groups."
- (interactive "P")
- (let (force raw current-handles)
- (cond
- ((null arg))
- ((eq arg 1)
- (setq raw t))
- ((eq arg 2)
- (setq raw t
- force t))
- ((eq arg 3)
- (setq current-handles
- (and (gnus-buffer-live-p gnus-article-buffer)
- (with-current-buffer gnus-article-buffer
- (prog1
- gnus-article-mime-handles
- (setq gnus-article-mime-handles nil))))))
- (t
- (setq force t)))
- (when (and raw (not force)
- (member gnus-newsgroup-name '("nndraft:delayed"
- "nndraft:drafts"
- "nndraft:queue")))
- (error "Can't edit the raw article in group %s"
- gnus-newsgroup-name))
- (with-current-buffer gnus-summary-buffer
- (let ((mail-parse-charset gnus-newsgroup-charset)
- (mail-parse-ignored-charsets gnus-newsgroup-ignored-charsets))
- (gnus-set-global-variables)
- (when (and (not force)
- (gnus-group-read-only-p))
- (error "The current newsgroup does not support article editing"))
- (gnus-summary-show-article t)
- (when (and (not raw) (gnus-buffer-live-p gnus-article-buffer))
- (with-current-buffer gnus-article-buffer
- (mm-enable-multibyte)))
- (if (member gnus-newsgroup-name '("nndraft:delayed" "nndraft:drafts"))
- (setq raw t))
- (gnus-article-edit-article
- (if raw 'ignore
- `(lambda ()
- (let ((mbl mml-buffer-list))
- (setq mml-buffer-list nil)
- (let ((rfc2047-quote-decoded-words-containing-tspecials t))
- (mime-to-mml ,'current-handles))
- (let ((mbl1 mml-buffer-list))
- (setq mml-buffer-list mbl)
- (set (make-local-variable 'mml-buffer-list) mbl1))
- (gnus-make-local-hook 'kill-buffer-hook)
- (add-hook 'kill-buffer-hook 'mml-destroy-buffers t t))))
- `(lambda (no-highlight)
- (let ((mail-parse-charset ',gnus-newsgroup-charset)
- (message-options message-options)
- (message-options-set-recipient)
- (mail-parse-ignored-charsets
- ',gnus-newsgroup-ignored-charsets)
- (rfc2047-header-encoding-alist
- ',(let ((charset (gnus-group-name-charset
- (gnus-find-method-for-group
- gnus-newsgroup-name)
- gnus-newsgroup-name)))
- (append (list (cons "Newsgroups" charset)
- (cons "Followup-To" charset)
- (cons "Xref" charset))
- rfc2047-header-encoding-alist))))
- ,(if (not raw) '(progn
- (mml-to-mime)
- (mml-destroy-buffers)
- (remove-hook 'kill-buffer-hook
- 'mml-destroy-buffers t)
- (kill-local-variable 'mml-buffer-list)))
- (gnus-summary-edit-article-done
- ,(or (mail-header-references gnus-current-headers) "")
- ,(gnus-group-read-only-p)
- ,gnus-summary-buffer no-highlight))))))))
- (defalias 'gnus-summary-edit-article-postpone 'gnus-article-edit-exit)
- (defun gnus-summary-edit-article-done (&optional references read-only buffer
- no-highlight)
- "Make edits to the current article permanent."
- (interactive)
- (save-excursion
- ;; The buffer restriction contains the entire article if it exists.
- (when (article-goto-body)
- (let ((lines (count-lines (point) (point-max)))
- (length (- (point-max) (point)))
- (case-fold-search t)
- (body (point-marker)))
- (goto-char (point-min))
- (when (re-search-forward "^content-length:[ \t]\\([0-9]+\\)" body t)
- (delete-region (match-beginning 1) (match-end 1))
- (insert (number-to-string length)))
- (goto-char (point-min))
- (when (re-search-forward
- "^x-content-length:[ \t]\\([0-9]+\\)" body t)
- (delete-region (match-beginning 1) (match-end 1))
- (insert (number-to-string length)))
- (goto-char (point-min))
- (when (re-search-forward "^lines:[ \t]\\([0-9]+\\)" body t)
- (delete-region (match-beginning 1) (match-end 1))
- (insert (number-to-string lines))))))
- ;; Replace the article.
- (let ((buf (current-buffer))
- (article (cdr gnus-article-current))
- replace-result)
- (with-temp-buffer
- (insert-buffer-substring buf)
- (if (and (not read-only)
- (not (setq replace-result
- (gnus-request-replace-article
- article (car gnus-article-current)
- (current-buffer) t))))
- (error "Couldn't replace article")
- ;; If we got a number back, then that's the new article number
- ;; for this article. Otherwise, the article number didn't change.
- (when (numberp replace-result)
- (with-current-buffer gnus-summary-buffer
- (setq gnus-newsgroup-limit (delq article gnus-newsgroup-limit))
- (gnus-summary-limit gnus-newsgroup-limit)
- (setq article replace-result)
- (gnus-summary-goto-subject article t)))
- ;; Update the summary buffer.
- (if (and references
- (equal (message-tokenize-header references " ")
- (message-tokenize-header
- (or (message-fetch-field "references") "") " ")))
- ;; We only have to update this line.
- (save-excursion
- (save-restriction
- (message-narrow-to-head)
- (let ((head (buffer-substring-no-properties
- (point-min) (point-max)))
- header)
- (with-temp-buffer
- (insert (format "211 %d Article retrieved.\n" article))
- (insert head)
- (insert ".\n")
- (let ((nntp-server-buffer (current-buffer)))
- (setq header (car (gnus-get-newsgroup-headers nil t))))
- (with-current-buffer gnus-summary-buffer
- (gnus-data-set-header (gnus-data-find article) header)
- (gnus-summary-update-article-line article header)
- (if (gnus-summary-goto-subject article nil t)
- (gnus-summary-update-secondary-mark article)))))))
- ;; Update threads.
- (set-buffer (or buffer gnus-summary-buffer))
- (gnus-summary-update-article article)
- (if (gnus-summary-goto-subject article nil t)
- (gnus-summary-update-secondary-mark article)))
- ;; Prettify the article buffer again.
- (unless no-highlight
- (with-current-buffer gnus-article-buffer
- ;;!!! Fix this -- article should be rehighlighted.
- ;;(gnus-run-hooks 'gnus-article-display-hook)
- (set-buffer gnus-original-article-buffer)
- (gnus-request-article
- article (car gnus-article-current) (current-buffer))))
- ;; Prettify the summary buffer line.
- (when (gnus-visual-p 'summary-highlight 'highlight)
- (gnus-run-hooks 'gnus-visual-mark-article-hook))))))
- (defun gnus-summary-edit-wash (key)
- "Perform editing command KEY in the article buffer."
- (interactive
- (list
- (progn
- (message "%s" (concat (this-command-keys) "- "))
- (read-char))))
- (message "")
- (gnus-summary-edit-article)
- (execute-kbd-macro (concat (this-command-keys) key))
- (gnus-article-edit-done))
- ;;; Respooling
- (defvar nnimap-split-fancy)
- (defvar nnimap-split-methods)
- (defun gnus-summary-respool-query (&optional silent trace)
- "Query where the respool algorithm would put this article."
- (interactive)
- (let (gnus-mark-article-hook)
- (gnus-summary-select-article)
- (with-current-buffer gnus-original-article-buffer
- (let ((groups
- (if (eq (car (gnus-find-method-for-group gnus-newsgroup-name))
- 'nnimap)
- ;; nnimap has its own splitting variables.
- (let ((nnmail-split-methods
- (cond
- ((eq nnimap-split-methods 'default)
- nnmail-split-methods)
- (nnimap-split-methods
- nnimap-split-methods)
- (nnimap-split-fancy
- 'nnmail-split-fancy)))
- (nnmail-split-fancy (or nnimap-split-fancy
- nnmail-split-fancy)))
- (nnmail-article-group 'identity trace))
- (nnmail-article-group 'identity trace))))
- (unless silent
- (if groups
- (message "This message would go to %s"
- (mapconcat 'car groups ", "))
- (message "This message would go to no groups"))
- groups)))))
- (defun gnus-summary-respool-trace ()
- "Trace where the respool algorithm would put this article.
- Display a buffer showing all fancy splitting patterns which matched."
- (interactive)
- (gnus-summary-respool-query nil t))
- ;; Summary marking commands.
- (defun gnus-summary-kill-same-subject-and-select (&optional unmark)
- "Mark articles which has the same subject as read, and then select the next.
- If UNMARK is positive, remove any kind of mark.
- If UNMARK is negative, tick articles."
- (interactive "P")
- (when unmark
- (setq unmark (prefix-numeric-value unmark)))
- (let ((count
- (gnus-summary-mark-same-subject
- (gnus-summary-article-subject) unmark)))
- ;; Select next unread article. If auto-select-same mode, should
- ;; select the first unread article.
- (gnus-summary-next-article t (and gnus-auto-select-same
- (gnus-summary-article-subject)))
- (gnus-message 7 "%d article%s marked as %s"
- count (if (= count 1) " is" "s are")
- (if unmark "unread" "read"))))
- (defun gnus-summary-kill-same-subject (&optional unmark)
- "Mark articles which has the same subject as read.
- If UNMARK is positive, remove any kind of mark.
- If UNMARK is negative, tick articles."
- (interactive "P")
- (when unmark
- (setq unmark (prefix-numeric-value unmark)))
- (let ((count
- (gnus-summary-mark-same-subject
- (gnus-summary-article-subject) unmark)))
- ;; If marked as read, go to next unread subject.
- (when (null unmark)
- ;; Go to next unread subject.
- (gnus-summary-next-subject 1 t))
- (gnus-message 7 "%d articles are marked as %s"
- count (if unmark "unread" "read"))))
- (defun gnus-summary-mark-same-subject (subject &optional unmark)
- "Mark articles with same SUBJECT as read, and return marked number.
- If optional argument UNMARK is positive, remove any kinds of marks.
- If optional argument UNMARK is negative, mark articles as unread instead."
- (let ((count 1))
- (save-excursion
- (cond
- ((null unmark) ; Mark as read.
- (while (and
- (progn
- (gnus-summary-mark-article-as-read gnus-killed-mark)
- (gnus-summary-show-thread) t)
- (gnus-summary-find-subject subject))
- (setq count (1+ count))))
- ((> unmark 0) ; Tick.
- (while (and
- (progn
- (gnus-summary-mark-article-as-unread gnus-ticked-mark)
- (gnus-summary-show-thread) t)
- (gnus-summary-find-subject subject))
- (setq count (1+ count))))
- (t ; Mark as unread.
- (while (and
- (progn
- (gnus-summary-mark-article-as-unread gnus-unread-mark)
- (gnus-summary-show-thread) t)
- (gnus-summary-find-subject subject))
- (setq count (1+ count)))))
- (gnus-set-mode-line 'summary)
- ;; Return the number of marked articles.
- count)))
- (defun gnus-summary-mark-as-processable (n &optional unmark)
- "Set the process mark on the next N articles.
- If N is negative, mark backward instead. If UNMARK is non-nil, remove
- the process mark instead. The difference between N and the actual
- number of articles marked is returned."
- (interactive "P")
- (if (and (null n) (gnus-region-active-p))
- (gnus-uu-mark-region (region-beginning) (region-end) unmark)
- (setq n (prefix-numeric-value n))
- (let ((backward (< n 0))
- (n (abs n)))
- (while (and
- (> n 0)
- (if unmark
- (gnus-summary-remove-process-mark
- (gnus-summary-article-number))
- (gnus-summary-set-process-mark (gnus-summary-article-number)))
- (zerop (gnus-summary-next-subject (if backward -1 1) nil t)))
- (setq n (1- n)))
- (when (/= 0 n)
- (gnus-message 7 "No more articles"))
- (gnus-summary-recenter)
- (gnus-summary-position-point)
- n)))
- (defun gnus-summary-unmark-as-processable (n)
- "Remove the process mark from the next N articles.
- If N is negative, unmark backward instead. The difference between N and
- the actual number of articles unmarked is returned."
- (interactive "P")
- (gnus-summary-mark-as-processable n t))
- (defun gnus-summary-unmark-all-processable ()
- "Remove the process mark from all articles."
- (interactive)
- (save-excursion
- (while gnus-newsgroup-processable
- (gnus-summary-remove-process-mark (car gnus-newsgroup-processable))))
- (gnus-summary-position-point))
- (defun gnus-summary-add-mark (article type)
- "Mark ARTICLE with a mark of TYPE."
- (let ((vtype (car (assq type gnus-article-mark-lists)))
- var)
- (if (not vtype)
- (error "No such mark type: %s" type)
- (setq var (intern (format "gnus-newsgroup-%s" type)))
- (set var (cons article (symbol-value var)))
- (if (memq type '(processable cached replied forwarded recent saved))
- (gnus-summary-update-secondary-mark article)
- ;;; !!! This is bogus. We should find out what primary
- ;;; !!! mark we want to set.
- (gnus-summary-update-mark gnus-del-mark 'unread)))))
- (defun gnus-summary-mark-as-expirable (n)
- "Mark N articles forward as expirable.
- If N is negative, mark backward instead. The difference between N and
- the actual number of articles marked is returned."
- (interactive "p")
- (gnus-summary-mark-forward n gnus-expirable-mark))
- (defun gnus-summary-mark-as-spam (n)
- "Mark N articles forward as spam.
- If N is negative, mark backward instead. The difference between N and
- the actual number of articles marked is returned."
- (interactive "p")
- (gnus-summary-mark-forward n gnus-spam-mark))
- (defun gnus-summary-mark-article-as-replied (article)
- "Mark ARTICLE as replied to and update the summary line.
- ARTICLE can also be a list of articles."
- (interactive (list (gnus-summary-article-number)))
- (let ((articles (if (listp article) article (list article))))
- (dolist (article articles)
- (unless (numberp article)
- (error "%s is not a number" article))
- (push article gnus-newsgroup-replied)
- (let ((inhibit-read-only t))
- (when (gnus-summary-goto-subject article nil t)
- (gnus-summary-update-secondary-mark article))))))
- (defun gnus-summary-mark-article-as-forwarded (article)
- "Mark ARTICLE as forwarded and update the summary line.
- ARTICLE can also be a list of articles."
- (let ((articles (if (listp article) article (list article))))
- (dolist (article articles)
- (push article gnus-newsgroup-forwarded)
- (let ((inhibit-read-only t))
- (when (gnus-summary-goto-subject article nil t)
- (gnus-summary-update-secondary-mark article))))))
- (defun gnus-summary-set-bookmark (article)
- "Set a bookmark in current article."
- (interactive (list (gnus-summary-article-number)))
- (when (or (not (get-buffer gnus-article-buffer))
- (not gnus-current-article)
- (not gnus-article-current)
- (not (equal gnus-newsgroup-name (car gnus-article-current))))
- (error "No current article selected"))
- ;; Remove old bookmark, if one exists.
- (gnus-alist-pull article gnus-newsgroup-bookmarks)
- ;; Set the new bookmark, which is on the form
- ;; (article-number . line-number-in-body).
- (push
- (cons article
- (with-current-buffer gnus-article-buffer
- (count-lines
- (min (point)
- (save-excursion
- (article-goto-body)
- (point)))
- (point))))
- gnus-newsgroup-bookmarks)
- (gnus-message 6 "A bookmark has been added to the current article."))
- (defun gnus-summary-remove-bookmark (article)
- "Remove the bookmark from the current article."
- (interactive (list (gnus-summary-article-number)))
- ;; Remove old bookmark, if one exists.
- (if (not (assq article gnus-newsgroup-bookmarks))
- (gnus-message 6 "No bookmark in current article.")
- (gnus-alist-pull article gnus-newsgroup-bookmarks)
- (gnus-message 6 "Removed bookmark.")))
- ;; Suggested by Daniel Quinlan <quinlan@best.com>.
- (defun gnus-summary-mark-as-dormant (n)
- "Mark N articles forward as dormant.
- If N is negative, mark backward instead. The difference between N and
- the actual number of articles marked is returned."
- (interactive "p")
- (gnus-summary-mark-forward n gnus-dormant-mark))
- (defun gnus-summary-set-process-mark (article)
- "Set the process mark on ARTICLE and update the summary line."
- (setq gnus-newsgroup-processable
- (cons article
- (delq article gnus-newsgroup-processable)))
- (when (gnus-summary-goto-subject article)
- (gnus-summary-show-thread)
- (gnus-summary-goto-subject article)
- (gnus-summary-update-secondary-mark article)))
- (defun gnus-summary-remove-process-mark (&rest articles)
- "Remove the process mark from ARTICLES and update the summary line."
- (dolist (article articles)
- (setq gnus-newsgroup-processable (delq article gnus-newsgroup-processable))
- (when (gnus-summary-goto-subject article)
- (gnus-summary-show-thread)
- (gnus-summary-goto-subject article)
- (gnus-summary-update-secondary-mark article)))
- t)
- (defun gnus-summary-set-saved-mark (article)
- "Set the process mark on ARTICLE and update the summary line."
- (push article gnus-newsgroup-saved)
- (when (gnus-summary-goto-subject article)
- (gnus-summary-update-secondary-mark article)))
- (defun gnus-summary-mark-forward (n &optional mark no-expire)
- "Mark N articles as read forwards.
- If N is negative, mark backwards instead. Mark with MARK, ?r by default.
- The difference between N and the actual number of articles marked is
- returned.
- If NO-EXPIRE, auto-expiry will be inhibited."
- (interactive "p")
- (gnus-summary-show-thread)
- (let ((backward (< n 0))
- (gnus-summary-goto-unread
- (and gnus-summary-goto-unread
- (not (eq gnus-summary-goto-unread 'never))
- (not (memq mark (list gnus-unread-mark gnus-spam-mark
- gnus-ticked-mark gnus-dormant-mark)))))
- (n (abs n))
- (mark (or mark gnus-del-mark)))
- (while (and (> n 0)
- (gnus-summary-mark-article nil mark no-expire)
- (zerop (gnus-summary-next-subject
- (if backward -1 1)
- (and gnus-summary-goto-unread
- (not (eq gnus-summary-goto-unread 'never)))
- t)))
- (setq n (1- n)))
- (when (/= 0 n)
- (gnus-message 7 "No more %sarticles" (if mark "" "unread ")))
- (gnus-summary-recenter)
- (gnus-summary-position-point)
- (gnus-set-mode-line 'summary)
- n))
- (defun gnus-summary-mark-article-as-read (mark)
- "Mark the current article quickly as read with MARK."
- (let ((article (gnus-summary-article-number)))
- (setq gnus-newsgroup-unreads (delq article gnus-newsgroup-unreads))
- (setq gnus-newsgroup-marked (delq article gnus-newsgroup-marked))
- (setq gnus-newsgroup-spam-marked (delq article gnus-newsgroup-spam-marked))
- (setq gnus-newsgroup-dormant (delq article gnus-newsgroup-dormant))
- (push (cons article mark) gnus-newsgroup-reads)
- ;; Possibly remove from cache, if that is used.
- (when gnus-use-cache
- (gnus-cache-enter-remove-article article))
- ;; Allow the backend to change the mark.
- (setq mark (gnus-request-update-mark gnus-newsgroup-name article mark))
- ;; Check for auto-expiry.
- (when (and gnus-newsgroup-auto-expire
- (memq mark gnus-auto-expirable-marks))
- (setq mark gnus-expirable-mark)
- ;; Let the backend know about the mark change.
- (setq mark (gnus-request-update-mark gnus-newsgroup-name article mark))
- (push article gnus-newsgroup-expirable))
- ;; Set the mark in the buffer.
- (gnus-summary-update-mark mark 'unread)
- t))
- (defun gnus-summary-mark-article-as-unread (mark)
- "Mark the current article quickly as unread with MARK."
- (let* ((article (gnus-summary-article-number))
- (old-mark (gnus-summary-article-mark article)))
- ;; Allow the backend to change the mark.
- (setq mark (gnus-request-update-mark gnus-newsgroup-name article mark))
- (if (eq mark old-mark)
- t
- (if (<= article 0)
- (progn
- (gnus-error 1 "Can't mark negative article numbers")
- nil)
- (setq gnus-newsgroup-marked (delq article gnus-newsgroup-marked))
- (setq gnus-newsgroup-spam-marked
- (delq article gnus-newsgroup-spam-marked))
- (setq gnus-newsgroup-dormant (delq article gnus-newsgroup-dormant))
- (setq gnus-newsgroup-expirable (delq article gnus-newsgroup-expirable))
- (setq gnus-newsgroup-reads (delq article gnus-newsgroup-reads))
- (setq gnus-newsgroup-unreads (delq article gnus-newsgroup-unreads))
- (cond ((= mark gnus-ticked-mark)
- (setq gnus-newsgroup-marked
- (gnus-add-to-sorted-list gnus-newsgroup-marked
- article)))
- ((= mark gnus-spam-mark)
- (setq gnus-newsgroup-spam-marked
- (gnus-add-to-sorted-list gnus-newsgroup-spam-marked
- article)))
- ((= mark gnus-dormant-mark)
- (setq gnus-newsgroup-dormant
- (gnus-add-to-sorted-list gnus-newsgroup-dormant
- article)))
- (t
- (setq gnus-newsgroup-unreads
- (gnus-add-to-sorted-list gnus-newsgroup-unreads
- article))))
- (gnus-alist-pull article gnus-newsgroup-reads)
- ;; See whether the article is to be put in the cache.
- (and gnus-use-cache
- (vectorp (gnus-summary-article-header article))
- (save-excursion
- (gnus-cache-possibly-enter-article
- gnus-newsgroup-name article
- (= mark gnus-ticked-mark)
- (= mark gnus-dormant-mark) (= mark gnus-unread-mark))))
- ;; Fix the mark.
- (gnus-summary-update-mark mark 'unread)
- t))))
- (defun gnus-summary-mark-article (&optional article mark no-expire)
- "Mark ARTICLE with MARK. MARK can be any character.
- Four MARK strings are reserved: `? ' (unread), `?!' (ticked),
- `??' (dormant) and `?E' (expirable).
- If MARK is nil, then the default character `?r' is used.
- If ARTICLE is nil, then the article on the current line will be
- marked.
- If NO-EXPIRE, auto-expiry will be inhibited."
- ;; The mark might be a string.
- (when (stringp mark)
- (setq mark (aref mark 0)))
- ;; If no mark is given, then we check auto-expiring.
- (when (null mark)
- (setq mark gnus-del-mark))
- (when (and (not no-expire)
- gnus-newsgroup-auto-expire
- (memq mark gnus-auto-expirable-marks))
- (setq mark gnus-expirable-mark))
- (let ((article (or article (gnus-summary-article-number)))
- (old-mark (gnus-summary-article-mark article)))
- ;; Allow the backend to change the mark.
- (setq mark (gnus-request-update-mark gnus-newsgroup-name article mark))
- (if (eq mark old-mark)
- t
- (unless article
- (error "No article on current line"))
- (if (not (if (or (= mark gnus-unread-mark)
- (= mark gnus-ticked-mark)
- (= mark gnus-spam-mark)
- (= mark gnus-dormant-mark))
- (gnus-mark-article-as-unread article mark)
- (gnus-mark-article-as-read article mark)))
- t
- ;; See whether the article is to be put in the cache.
- (and gnus-use-cache
- (not (= mark gnus-canceled-mark))
- (vectorp (gnus-summary-article-header article))
- (save-excursion
- (gnus-cache-possibly-enter-article
- gnus-newsgroup-name article
- (= mark gnus-ticked-mark)
- (= mark gnus-dormant-mark) (= mark gnus-unread-mark))))
- (when (gnus-summary-goto-subject article nil t)
- (let ((inhibit-read-only t))
- (gnus-summary-show-thread)
- ;; Fix the mark.
- (gnus-summary-update-mark mark 'unread)
- t))))))
- (defun gnus-summary-update-secondary-mark (article)
- "Update the secondary (read, process, cache) mark."
- (gnus-summary-update-mark
- (cond ((memq article gnus-newsgroup-processable)
- gnus-process-mark)
- ((memq article gnus-newsgroup-cached)
- gnus-cached-mark)
- ((memq article gnus-newsgroup-replied)
- gnus-replied-mark)
- ((memq article gnus-newsgroup-forwarded)
- gnus-forwarded-mark)
- ((memq article gnus-newsgroup-saved)
- gnus-saved-mark)
- ((memq article gnus-newsgroup-unseen)
- gnus-unseen-mark)
- (t gnus-no-mark))
- 'replied)
- (when (gnus-visual-p 'summary-highlight 'highlight)
- (gnus-summary-highlight-line)
- (gnus-run-hooks 'gnus-summary-update-hook))
- t)
- (defun gnus-summary-update-download-mark (article)
- "Update the download mark."
- (gnus-summary-update-mark
- (cond ((memq article gnus-newsgroup-undownloaded)
- gnus-undownloaded-mark)
- (gnus-newsgroup-agentized
- gnus-downloaded-mark)
- (t
- gnus-no-mark))
- 'download)
- (gnus-summary-update-line t)
- t)
- (defun gnus-summary-update-mark (mark type)
- (let ((forward (cdr (assq type gnus-summary-mark-positions)))
- (inhibit-read-only t))
- (re-search-backward "[\n\r]" (point-at-bol) 'move-to-limit)
- (when forward
- (when (looking-at "\r")
- (incf forward))
- (when (<= (+ forward (point)) (point-max))
- ;; Go to the right position on the line.
- (goto-char (+ forward (point)))
- ;; Replace the old mark with the new mark.
- (let ((to-insert
- (mm-subst-char-in-string
- (char-after) mark
- (buffer-substring (point) (1+ (point))))))
- (delete-region (point) (1+ (point)))
- (insert to-insert))
- ;; Optionally update the marks by some user rule.
- (when (eq type 'unread)
- (gnus-data-set-mark
- (gnus-data-find (gnus-summary-article-number)) mark)
- (gnus-summary-update-line (eq mark gnus-unread-mark)))))))
- (defun gnus-mark-article-as-read (article &optional mark)
- "Enter ARTICLE in the pertinent lists and remove it from others."
- ;; Make the article expirable.
- (let ((mark (or mark gnus-del-mark)))
- (setq gnus-newsgroup-expirable
- (if (= mark gnus-expirable-mark)
- (gnus-add-to-sorted-list gnus-newsgroup-expirable article)
- (delq article gnus-newsgroup-expirable)))
- ;; Remove from unread and marked lists.
- (setq gnus-newsgroup-unreads (delq article gnus-newsgroup-unreads))
- (setq gnus-newsgroup-marked (delq article gnus-newsgroup-marked))
- (setq gnus-newsgroup-spam-marked (delq article gnus-newsgroup-spam-marked))
- (setq gnus-newsgroup-dormant (delq article gnus-newsgroup-dormant))
- (push (cons article mark) gnus-newsgroup-reads)
- ;; Possibly remove from cache, if that is used.
- (when gnus-use-cache
- (gnus-cache-enter-remove-article article))
- t))
- (defun gnus-mark-article-as-unread (article &optional mark)
- "Enter ARTICLE in the pertinent lists and remove it from others."
- (let ((mark (or mark gnus-ticked-mark)))
- (if (<= article 0)
- (progn
- (gnus-error 1 "Can't mark negative article numbers")
- nil)
- (setq gnus-newsgroup-marked (delq article gnus-newsgroup-marked)
- gnus-newsgroup-spam-marked (delq article gnus-newsgroup-spam-marked)
- gnus-newsgroup-dormant (delq article gnus-newsgroup-dormant)
- gnus-newsgroup-expirable (delq article gnus-newsgroup-expirable)
- gnus-newsgroup-unreads (delq article gnus-newsgroup-unreads))
- ;; Unsuppress duplicates?
- (when gnus-suppress-duplicates
- (gnus-dup-unsuppress-article article))
- (cond ((= mark gnus-ticked-mark)
- (setq gnus-newsgroup-marked
- (gnus-add-to-sorted-list gnus-newsgroup-marked article)))
- ((= mark gnus-spam-mark)
- (setq gnus-newsgroup-spam-marked
- (gnus-add-to-sorted-list gnus-newsgroup-spam-marked
- article)))
- ((= mark gnus-dormant-mark)
- (setq gnus-newsgroup-dormant
- (gnus-add-to-sorted-list gnus-newsgroup-dormant article)))
- (t
- (setq gnus-newsgroup-unreads
- (gnus-add-to-sorted-list gnus-newsgroup-unreads article))))
- (gnus-alist-pull article gnus-newsgroup-reads)
- t)))
- (defun gnus-summary-tick-article-forward (n)
- "Tick N articles forwards.
- If N is negative, tick backwards instead.
- The difference between N and the number of articles ticked is returned."
- (interactive "p")
- (gnus-summary-mark-forward n gnus-ticked-mark))
- (defun gnus-summary-tick-article-backward (n)
- "Tick N articles backwards.
- The difference between N and the number of articles ticked is returned."
- (interactive "p")
- (gnus-summary-mark-forward (- n) gnus-ticked-mark))
- (defun gnus-summary-tick-article (&optional article clear-mark)
- "Mark current article as unread.
- Optional 1st argument ARTICLE specifies article number to be marked as unread.
- Optional 2nd argument CLEAR-MARK remove any kinds of mark."
- (interactive)
- (gnus-summary-mark-article article (if clear-mark gnus-unread-mark
- gnus-ticked-mark)))
- (defun gnus-summary-mark-as-read-forward (n)
- "Mark N articles as read forwards.
- If N is negative, mark backwards instead.
- The difference between N and the actual number of articles marked is
- returned."
- (interactive "p")
- (gnus-summary-mark-forward n gnus-del-mark gnus-inhibit-user-auto-expire))
- (defun gnus-summary-mark-as-read-backward (n)
- "Mark the N articles as read backwards.
- The difference between N and the actual number of articles marked is
- returned."
- (interactive "p")
- (gnus-summary-mark-forward
- (- n) gnus-del-mark gnus-inhibit-user-auto-expire))
- (defun gnus-summary-mark-as-read (&optional article mark)
- "Mark current article as read.
- ARTICLE specifies the article to be marked as read.
- MARK specifies a string to be inserted at the beginning of the line."
- (gnus-summary-mark-article article mark))
- (defun gnus-summary-clear-mark-forward (n)
- "Clear marks from N articles forward.
- If N is negative, clear backward instead.
- The difference between N and the number of marks cleared is returned."
- (interactive "p")
- (gnus-summary-mark-forward n gnus-unread-mark))
- (defun gnus-summary-clear-mark-backward (n)
- "Clear marks from N articles backward.
- The difference between N and the number of marks cleared is returned."
- (interactive "p")
- (gnus-summary-mark-forward (- n) gnus-unread-mark))
- (defun gnus-summary-mark-unread-as-read ()
- "Intended to be used by `gnus-mark-article-hook'."
- (when (memq gnus-current-article gnus-newsgroup-unreads)
- (gnus-summary-mark-article gnus-current-article gnus-read-mark)))
- (defun gnus-summary-mark-read-and-unread-as-read (&optional new-mark)
- "Intended to be used by `gnus-mark-article-hook'."
- (let ((mark (gnus-summary-article-mark)))
- (when (or (gnus-unread-mark-p mark)
- (gnus-read-mark-p mark))
- (gnus-summary-mark-article gnus-current-article
- (or new-mark gnus-read-mark)))))
- (defun gnus-summary-mark-current-read-and-unread-as-read (&optional new-mark)
- "Intended to be used by `gnus-mark-article-hook'."
- (let ((mark (gnus-summary-article-mark)))
- (when (or (gnus-unread-mark-p mark)
- (gnus-read-mark-p mark))
- (gnus-summary-mark-article (gnus-summary-article-number)
- (or new-mark gnus-read-mark)))))
- (defun gnus-summary-mark-unread-as-ticked ()
- "Intended to be used by `gnus-mark-article-hook'."
- (when (memq gnus-current-article gnus-newsgroup-unreads)
- (gnus-summary-mark-article gnus-current-article gnus-ticked-mark)))
- (defun gnus-summary-mark-region-as-read (point mark all)
- "Mark all unread articles between point and mark as read.
- If given a prefix, mark all articles between point and mark as read,
- even ticked and dormant ones."
- (interactive "r\nP")
- (save-excursion
- (let (article)
- (goto-char point)
- (beginning-of-line)
- (while (and
- (< (point) mark)
- (progn
- (when (or all
- (memq (setq article (gnus-summary-article-number))
- gnus-newsgroup-unreads))
- (gnus-summary-mark-article article gnus-del-mark))
- t)
- (gnus-summary-find-next))))))
- (defun gnus-summary-mark-below (score mark)
- "Mark articles with score less than SCORE with MARK."
- (interactive "P\ncMark: ")
- (setq score (if score
- (prefix-numeric-value score)
- (or gnus-summary-default-score 0)))
- (with-current-buffer gnus-summary-buffer
- (goto-char (point-min))
- (while
- (progn
- (and (< (gnus-summary-article-score) score)
- (gnus-summary-mark-article nil mark))
- (gnus-summary-find-next)))))
- (defun gnus-summary-kill-below (&optional score)
- "Mark articles with score below SCORE as read."
- (interactive "P")
- (gnus-summary-mark-below score gnus-killed-mark))
- (defun gnus-summary-clear-above (&optional score)
- "Clear all marks from articles with score above SCORE."
- (interactive "P")
- (gnus-summary-mark-above score gnus-unread-mark))
- (defun gnus-summary-tick-above (&optional score)
- "Tick all articles with score above SCORE."
- (interactive "P")
- (gnus-summary-mark-above score gnus-ticked-mark))
- (defun gnus-summary-mark-above (score mark)
- "Mark articles with score over SCORE with MARK."
- (interactive "P\ncMark: ")
- (setq score (if score
- (prefix-numeric-value score)
- (or gnus-summary-default-score 0)))
- (with-current-buffer gnus-summary-buffer
- (goto-char (point-min))
- (while (and (progn
- (when (> (gnus-summary-article-score) score)
- (gnus-summary-mark-article nil mark))
- t)
- (gnus-summary-find-next)))))
- ;; Suggested by Daniel Quinlan <quinlan@best.com>.
- (defalias 'gnus-summary-show-all-expunged 'gnus-summary-limit-include-expunged)
- (defun gnus-summary-limit-include-expunged (&optional no-error)
- "Display all the hidden articles that were expunged for low scores."
- (interactive)
- (let ((inhibit-read-only t))
- (let ((scored gnus-newsgroup-scored)
- headers h)
- (while scored
- (unless (gnus-summary-article-header (caar scored))
- (and (setq h (gnus-number-to-header (caar scored)))
- (< (cdar scored) gnus-summary-expunge-below)
- (push h headers)))
- (setq scored (cdr scored)))
- (if (not headers)
- (when (not no-error)
- (error "No expunged articles hidden"))
- (goto-char (point-min))
- (push gnus-newsgroup-limit gnus-newsgroup-limits)
- (setq gnus-newsgroup-limit (copy-sequence gnus-newsgroup-limit))
- (dolist (x headers)
- (push (mail-header-number x) gnus-newsgroup-limit))
- (gnus-summary-prepare-unthreaded (nreverse headers))
- (goto-char (point-min))
- (gnus-summary-position-point)
- t))))
- (defun gnus-summary-catchup (&optional all quietly to-here not-mark reverse)
- "Mark all unread articles in this newsgroup as read.
- If prefix argument ALL is non-nil, ticked and dormant articles will
- also be marked as read.
- If QUIETLY is non-nil, no questions will be asked.
- If TO-HERE is non-nil, it should be a point in the buffer. All
- articles before (after, if REVERSE is set) this point will be marked
- as read.
- Note that this function will only catch up the unread article
- in the current summary buffer limitation.
- The number of articles marked as read is returned."
- (interactive "P")
- (prog1
- (save-excursion
- (when (or quietly
- (not gnus-interactive-catchup) ;Without confirmation?
- gnus-expert-user
- (gnus-y-or-n-p
- (if all
- "Mark absolutely all articles as read? "
- "Mark all unread articles as read? ")))
- (if (and not-mark
- (not gnus-newsgroup-adaptive)
- (not gnus-newsgroup-auto-expire)
- (not gnus-suppress-duplicates)
- (or (not gnus-use-cache)
- (eq gnus-use-cache 'passive)))
- (progn
- (when all
- (setq gnus-newsgroup-marked nil
- gnus-newsgroup-spam-marked nil
- gnus-newsgroup-dormant nil))
- (setq gnus-newsgroup-unreads
- (gnus-sorted-nunion
- (gnus-sorted-intersection gnus-newsgroup-unreads
- gnus-newsgroup-downloadable)
- (gnus-sorted-difference gnus-newsgroup-unfetched
- gnus-newsgroup-cached))))
- ;; We actually mark all articles as canceled, which we
- ;; have to do when using auto-expiry or adaptive scoring.
- (gnus-summary-show-all-threads)
- (if (and to-here reverse)
- (progn
- (goto-char to-here)
- (gnus-summary-mark-current-read-and-unread-as-read
- gnus-catchup-mark)
- (while (gnus-summary-find-next (not all))
- (gnus-summary-mark-article-as-read gnus-catchup-mark)))
- (when (gnus-summary-first-subject (not all))
- (while (and
- (if to-here (< (point) to-here) t)
- (gnus-summary-mark-article-as-read gnus-catchup-mark)
- (gnus-summary-find-next (not all))))))
- (gnus-set-mode-line 'summary))
- t))
- (gnus-summary-position-point)))
- (defun gnus-summary-catchup-to-here (&optional all)
- "Mark all unticked articles before the current one as read.
- If ALL is non-nil, also mark ticked and dormant articles as read."
- (interactive "P")
- (save-excursion
- (gnus-save-hidden-threads
- (let ((beg (point)))
- ;; We check that there are unread articles.
- (when (or all (gnus-summary-find-prev))
- (gnus-summary-catchup all t beg)))))
- (gnus-summary-position-point))
- (defun gnus-summary-catchup-from-here (&optional all)
- "Mark all unticked articles after (and including) the current one as read.
- If ALL is non-nil, also mark ticked and dormant articles as read."
- (interactive "P")
- (save-excursion
- (gnus-save-hidden-threads
- (let ((beg (point)))
- ;; We check that there are unread articles.
- (when (or all (gnus-summary-find-next))
- (gnus-summary-catchup all t beg nil t)))))
- (gnus-summary-position-point))
- (defun gnus-summary-catchup-all (&optional quietly)
- "Mark all articles in this newsgroup as read.
- This command is dangerous. Normally, you want \\[gnus-summary-catchup]
- instead, which marks only unread articles as read."
- (interactive "P")
- (gnus-summary-catchup t quietly))
- (defun gnus-summary-catchup-and-exit (&optional all quietly)
- "Mark all unread articles in this group as read, then exit.
- If prefix argument ALL is non-nil, all articles are marked as read.
- If QUIETLY is non-nil, no questions will be asked."
- (interactive "P")
- (when (gnus-summary-catchup all quietly nil 'fast)
- ;; Select next newsgroup or exit.
- (if (and (not (gnus-group-quit-config gnus-newsgroup-name))
- (eq gnus-auto-select-next 'quietly))
- (gnus-summary-next-group nil)
- (gnus-summary-exit))))
- (defun gnus-summary-catchup-all-and-exit (&optional quietly)
- "Mark all articles in this newsgroup as read, and then exit.
- This command is dangerous. Normally, you want \\[gnus-summary-catchup-and-exit]
- instead, which marks only unread articles as read."
- (interactive "P")
- (gnus-summary-catchup-and-exit t quietly))
- (defun gnus-summary-catchup-and-goto-next-group (&optional all)
- "Mark all articles in this group as read and select the next group.
- If given a prefix, mark all articles, unread as well as ticked, as
- read."
- (interactive "P")
- (save-excursion
- (gnus-summary-catchup all))
- (gnus-summary-next-group))
- (defun gnus-summary-catchup-and-goto-prev-group (&optional all)
- "Mark all articles in this group as read and select the previous group.
- If given a prefix, mark all articles, unread as well as ticked, as
- read."
- (interactive "P")
- (save-excursion
- (gnus-summary-catchup all))
- (gnus-summary-next-group nil nil t))
- ;;;
- ;;; with article
- ;;;
- (defmacro gnus-with-article (article &rest forms)
- "Select ARTICLE and perform FORMS in the original article buffer.
- Then replace the article with the result."
- `(progn
- ;; We don't want the article to be marked as read.
- (let (gnus-mark-article-hook)
- (gnus-summary-select-article t t nil ,article))
- (set-buffer gnus-original-article-buffer)
- ,@forms
- (if (not (gnus-check-backend-function
- 'request-replace-article (car gnus-article-current)))
- (gnus-message 5 "Read-only group; not replacing")
- (unless (gnus-request-replace-article
- ,article (car gnus-article-current)
- (current-buffer) t)
- (error "Couldn't replace article")))
- ;; The cache and backlog have to be flushed somewhat.
- (when gnus-keep-backlog
- (gnus-backlog-remove-article
- (car gnus-article-current) (cdr gnus-article-current)))
- (when gnus-use-cache
- (gnus-cache-update-article
- (car gnus-article-current) (cdr gnus-article-current)))))
- (put 'gnus-with-article 'lisp-indent-function 1)
- (put 'gnus-with-article 'edebug-form-spec '(form body))
- ;; Thread-based commands.
- (defun gnus-summary-articles-in-thread (&optional article)
- "Return a list of all articles in the current thread.
- If ARTICLE is non-nil, return all articles in the thread that starts
- with that article."
- (let* ((article (or article (gnus-summary-article-number)))
- (data (gnus-data-find-list article))
- (top-level (gnus-data-level (car data)))
- (top-subject
- (cond ((null gnus-thread-operation-ignore-subject)
- (gnus-simplify-subject-re
- (mail-header-subject (gnus-data-header (car data)))))
- ((eq gnus-thread-operation-ignore-subject 'fuzzy)
- (gnus-simplify-subject-fuzzy
- (mail-header-subject (gnus-data-header (car data)))))
- (t nil)))
- (end-point (save-excursion
- (goto-char (gnus-data-pos (car data)))
- (if (gnus-summary-go-to-next-thread)
- (point) (point-max))))
- articles)
- (while (and data
- (< (gnus-data-pos (car data)) end-point))
- (when (or (not top-subject)
- (string= top-subject
- (if (eq gnus-thread-operation-ignore-subject 'fuzzy)
- (gnus-simplify-subject-fuzzy
- (mail-header-subject
- (gnus-data-header (car data))))
- (gnus-simplify-subject-re
- (mail-header-subject
- (gnus-data-header (car data)))))))
- (push (gnus-data-number (car data)) articles))
- (unless (and (setq data (cdr data))
- (> (gnus-data-level (car data)) top-level))
- (setq data nil)))
- ;; Return the list of articles.
- (nreverse articles)))
- (defun gnus-summary-rethread-current ()
- "Rethread the thread the current article is part of."
- (interactive)
- (let* ((gnus-show-threads t)
- (article (gnus-summary-article-number))
- (id (mail-header-id (gnus-summary-article-header)))
- (gnus-newsgroup-threads (list (gnus-id-to-thread (gnus-root-id id)))))
- (unless id
- (error "No article on the current line"))
- (gnus-rebuild-thread id)
- (gnus-summary-goto-subject article)))
- (defun gnus-summary-reparent-thread ()
- "Make the current article child of the marked (or previous) article.
- Note that the re-threading will only work if `gnus-thread-ignore-subject'
- is non-nil or the Subject: of both articles are the same."
- (interactive)
- (unless (not (gnus-group-read-only-p))
- (error "The current newsgroup does not support article editing"))
- (unless (<= (length gnus-newsgroup-processable) 1)
- (error "No more than one article may be marked"))
- (let ((child (gnus-summary-article-number))
- ;; First grab the marked article, otherwise one line up.
- (parent (if (not (null gnus-newsgroup-processable))
- (car gnus-newsgroup-processable)
- (save-excursion
- (if (eq (forward-line -1) 0)
- (gnus-summary-article-number)
- (error "Beginning of summary buffer"))))))
- (gnus-summary-reparent-children parent (list child))))
- (defun gnus-summary-reparent-children (parent children)
- "Make PARENT the parent of CHILDREN.
- When called interactively, PARENT is the current article and CHILDREN
- are the process-marked articles."
- (interactive
- (list (gnus-summary-article-number)
- (gnus-summary-work-articles nil)))
- (dolist (child children)
- (save-window-excursion
- (let ((gnus-article-buffer " *reparent*"))
- (unless (not (eq parent child))
- (error "An article may not be self-referential"))
- (let ((message-id (mail-header-id
- (gnus-summary-article-header parent))))
- (unless (and message-id (not (equal message-id "")))
- (error "No message-id in desired parent"))
- (gnus-with-article child
- (save-restriction
- (goto-char (point-min))
- (message-narrow-to-head)
- (if (re-search-forward "^References: " nil t)
- (progn
- (re-search-forward "^[^ \t]" nil t)
- (forward-line -1)
- (end-of-line)
- (insert " " message-id))
- (insert "References: " message-id "\n"))))
- (set-buffer gnus-summary-buffer)
- (gnus-summary-unmark-all-processable)
- (gnus-summary-update-article child)
- (when (gnus-summary-goto-subject (cdr gnus-article-current) nil t)
- (gnus-summary-update-secondary-mark (cdr gnus-article-current)))
- (gnus-summary-rethread-current)
- (gnus-message 3 "Article %d is now the child of article %d"
- child parent))))))
- (defun gnus-summary-toggle-threads (&optional arg)
- "Toggle showing conversation threads.
- If ARG is positive number, turn showing conversation threads on."
- (interactive "P")
- (let ((current (or (gnus-summary-article-number) gnus-newsgroup-end)))
- (setq gnus-show-threads
- (if (null arg) (not gnus-show-threads)
- (> (prefix-numeric-value arg) 0)))
- (gnus-summary-prepare)
- (gnus-summary-goto-subject current)
- (gnus-message 6 "Threading is now %s" (if gnus-show-threads "on" "off"))
- (gnus-summary-position-point)))
- (defun gnus-summary-show-all-threads ()
- "Show all threads."
- (interactive)
- (remove-overlays (point-min) (point-max) 'invisible 'gnus-sum)
- (gnus-summary-position-point))
- (defsubst gnus-summary--inv (p)
- (and (eq (get-char-property p 'invisible) 'gnus-sum) p))
- (defun gnus-summary-show-thread ()
- "Show thread subtrees.
- Returns nil if no thread was there to be shown."
- (interactive)
- (let* ((orig (point))
- (end (point-at-eol))
- (end (or (gnus-summary--inv end) (gnus-summary--inv (1- end))))
- ;; Leave point at bol
- (beg (progn (beginning-of-line) (if (bobp) (point) (1- (point)))))
- (eoi (when end
- (if (fboundp 'next-single-char-property-change)
- ;; Note: XEmacs version of n-s-c-p-c may return nil
- (or (next-single-char-property-change end 'invisible)
- (point-max))
- (while (progn
- (end-of-line 2)
- (and (not (eobp))
- (eq (get-char-property (point) 'invisible)
- 'gnus-sum))))
- (point)))))
- (when eoi
- (remove-overlays beg eoi 'invisible 'gnus-sum)
- (goto-char orig)
- (gnus-summary-position-point)
- eoi)))
- (defun gnus-summary-maybe-hide-threads ()
- "If requested, hide the threads that should be hidden."
- (when (and gnus-show-threads
- gnus-thread-hide-subtree)
- (gnus-summary-hide-all-threads
- (if (or (consp gnus-thread-hide-subtree)
- (functionp gnus-thread-hide-subtree))
- (gnus-make-predicate gnus-thread-hide-subtree)
- nil))))
- ;;; Hiding predicates.
- (defun gnus-article-unread-p (header)
- (memq (mail-header-number header) gnus-newsgroup-unreads))
- (defun gnus-article-unseen-p (header)
- (memq (mail-header-number header) gnus-newsgroup-unseen))
- (defun gnus-map-articles (predicate articles)
- "Map PREDICATE over ARTICLES and return non-nil if any predicate is non-nil."
- (apply 'gnus-or (mapcar predicate
- (mapcar (lambda (number)
- (gnus-summary-article-header number))
- articles))))
- (defun gnus-summary-hide-all-threads (&optional predicate)
- "Hide all thread subtrees.
- If PREDICATE is supplied, threads that satisfy this predicate
- will not be hidden."
- (interactive)
- (save-excursion
- (goto-char (point-min))
- (let ((end nil)
- (count 0))
- (while (not end)
- (incf count)
- (when (zerop (mod count 1000))
- (message "Hiding all threads... %d" count))
- (when (or (not predicate)
- (gnus-map-articles
- predicate (gnus-summary-article-children)))
- (gnus-summary-hide-thread))
- (setq end (not (zerop (gnus-summary-next-thread 1 t)))))))
- (gnus-summary-position-point))
- (defun gnus-summary-hide-thread ()
- "Hide thread subtrees.
- If PREDICATE is supplied, threads that satisfy this predicate
- will not be hidden.
- Returns nil if no threads were there to be hidden."
- (interactive)
- (beginning-of-line)
- (let ((start (point))
- (starteol (line-end-position))
- (article (gnus-summary-article-number)))
- ;; Go forward until either the buffer ends or the subthread ends.
- (when (and (not (eobp))
- (or (zerop (gnus-summary-next-thread 1 t))
- (goto-char (point-max))))
- (if (and (> (point) start)
- ;; FIXME: this should actually search for a non-invisible \n.
- (search-backward "\n" start t))
- (progn
- (when (> (point) starteol)
- (remove-overlays starteol (point) 'invisible 'gnus-sum)
- (let ((ol (make-overlay starteol (point) nil t nil)))
- (overlay-put ol 'invisible 'gnus-sum)
- (overlay-put ol 'evaporate t)))
- (gnus-summary-goto-subject article)
- (when (> start (point))
- (message "Hiding the thread moved us backwards, aborting!")
- (goto-char (point-max))))
- (goto-char start)
- nil))))
- (defun gnus-summary-go-to-next-thread (&optional previous)
- "Go to the same level (or less) next thread.
- If PREVIOUS is non-nil, go to previous thread instead.
- Return the article number moved to, or nil if moving was impossible."
- (let ((level (gnus-summary-thread-level))
- (way (if previous -1 1))
- (beg (point)))
- (forward-line way)
- (while (and (not (eobp))
- (< level (gnus-summary-thread-level)))
- (forward-line way))
- (if (eobp)
- (progn
- (goto-char beg)
- nil)
- (setq beg (point))
- (prog1
- (gnus-summary-article-number)
- (goto-char beg)))))
- (defun gnus-summary-next-thread (n &optional silent)
- "Go to the same level next N'th thread.
- If N is negative, search backward instead.
- Returns the difference between N and the number of skips actually
- done.
- If SILENT, don't output messages."
- (interactive "p")
- (let ((backward (< n 0))
- (n (abs n)))
- (while (and (> n 0)
- (gnus-summary-go-to-next-thread backward))
- (decf n))
- (unless silent
- (gnus-summary-position-point))
- (when (and (not silent) (/= 0 n))
- (gnus-message 7 "No more threads"))
- n))
- (defun gnus-summary-prev-thread (n)
- "Go to the same level previous N'th thread.
- Returns the difference between N and the number of skips actually
- done."
- (interactive "p")
- (gnus-summary-next-thread (- n)))
- (defun gnus-summary-go-down-thread ()
- "Go down one level in the current thread."
- (let ((children (gnus-summary-article-children)))
- (when children
- (gnus-summary-goto-subject (car children)))))
- (defun gnus-summary-go-up-thread ()
- "Go up one level in the current thread."
- (let ((parent (gnus-summary-article-parent)))
- (when parent
- (gnus-summary-goto-subject parent))))
- (defun gnus-summary-down-thread (n)
- "Go down thread N steps.
- If N is negative, go up instead.
- Returns the difference between N and how many steps down that were
- taken."
- (interactive "p")
- (let ((up (< n 0))
- (n (abs n)))
- (while (and (> n 0)
- (if up (gnus-summary-go-up-thread)
- (gnus-summary-go-down-thread)))
- (setq n (1- n)))
- (gnus-summary-position-point)
- (when (/= 0 n)
- (gnus-message 7 "Can't go further"))
- n))
- (defun gnus-summary-up-thread (n)
- "Go up thread N steps.
- If N is negative, go down instead.
- Returns the difference between N and how many steps down that were
- taken."
- (interactive "p")
- (gnus-summary-down-thread (- n)))
- (defun gnus-summary-top-thread ()
- "Go to the top of the thread."
- (interactive)
- (while (gnus-summary-go-up-thread))
- (gnus-summary-article-number))
- (defun gnus-summary-expire-thread ()
- "Mark articles under current thread as expired."
- (interactive)
- (gnus-summary-kill-thread 0))
- (defun gnus-summary-kill-thread (&optional unmark)
- "Mark articles under current thread as read.
- If the prefix argument is positive, remove any kinds of marks.
- If the prefix argument is zero, mark thread as expired.
- If the prefix argument is negative, tick articles instead."
- (interactive "P")
- (when unmark
- (setq unmark (prefix-numeric-value unmark)))
- (let ((articles (gnus-summary-articles-in-thread))
- (hide (or (null unmark) (= unmark 0))))
- (save-excursion
- ;; Expand the thread.
- (gnus-summary-show-thread)
- ;; Mark all the articles.
- (while articles
- (gnus-summary-goto-subject (car articles))
- (cond ((null unmark)
- (gnus-summary-mark-article-as-read gnus-killed-mark))
- ((> unmark 0)
- (gnus-summary-mark-article-as-unread gnus-unread-mark))
- ((= unmark 0)
- (gnus-summary-mark-article nil gnus-expirable-mark))
- (t
- (gnus-summary-mark-article-as-unread gnus-ticked-mark)))
- (setq articles (cdr articles))))
- ;; Hide killed subtrees when hide is true.
- (and hide
- gnus-thread-hide-killed
- (gnus-summary-hide-thread))
- ;; If hide is t, go to next unread subject.
- (when hide
- ;; Go to next unread subject.
- (gnus-summary-next-subject 1 t)))
- (gnus-set-mode-line 'summary))
- ;; Summary sorting commands
- (defun gnus-summary-sort-by-number (&optional reverse)
- "Sort the summary buffer by article number.
- Argument REVERSE means reverse order."
- (interactive "P")
- (gnus-summary-sort 'number reverse))
- (defun gnus-summary-sort-by-most-recent-number (&optional reverse)
- "Sort the summary buffer by most recent article number.
- Argument REVERSE means reverse order."
- (interactive "P")
- (gnus-summary-sort 'most-recent-number reverse))
- (defun gnus-summary-sort-by-random (&optional reverse)
- "Randomize the order in the summary buffer.
- Argument REVERSE means to randomize in reverse order."
- (interactive "P")
- (gnus-summary-sort 'random reverse))
- (defun gnus-summary-sort-by-author (&optional reverse)
- "Sort the summary buffer by author name alphabetically.
- If `case-fold-search' is non-nil, case of letters is ignored.
- Argument REVERSE means reverse order."
- (interactive "P")
- (gnus-summary-sort 'author reverse))
- (defun gnus-summary-sort-by-recipient (&optional reverse)
- "Sort the summary buffer by recipient name alphabetically.
- If `case-fold-search' is non-nil, case of letters is ignored.
- Argument REVERSE means reverse order."
- (interactive "P")
- (gnus-summary-sort 'recipient reverse))
- (defun gnus-summary-sort-by-subject (&optional reverse)
- "Sort the summary buffer by subject alphabetically. `Re:'s are ignored.
- If `case-fold-search' is non-nil, case of letters is ignored.
- Argument REVERSE means reverse order."
- (interactive "P")
- (gnus-summary-sort 'subject reverse))
- (defun gnus-summary-sort-by-date (&optional reverse)
- "Sort the summary buffer by date.
- Argument REVERSE means reverse order."
- (interactive "P")
- (gnus-summary-sort 'date reverse))
- (defun gnus-summary-sort-by-most-recent-date (&optional reverse)
- "Sort the summary buffer by most recent date.
- Argument REVERSE means reverse order."
- (interactive "P")
- (gnus-summary-sort 'most-recent-date reverse))
- (defun gnus-summary-sort-by-score (&optional reverse)
- "Sort the summary buffer by score.
- Argument REVERSE means reverse order."
- (interactive "P")
- (gnus-summary-sort 'score reverse))
- (defun gnus-summary-sort-by-lines (&optional reverse)
- "Sort the summary buffer by the number of lines.
- Argument REVERSE means reverse order."
- (interactive "P")
- (gnus-summary-sort 'lines reverse))
- (defun gnus-summary-sort-by-chars (&optional reverse)
- "Sort the summary buffer by article length.
- Argument REVERSE means reverse order."
- (interactive "P")
- (gnus-summary-sort 'chars reverse))
- (defun gnus-summary-sort-by-original (&optional reverse)
- "Sort the summary buffer using the default sorting method.
- Argument REVERSE means reverse order."
- (interactive "P")
- (let* ((inhibit-read-only t)
- (gnus-summary-prepare-hook nil))
- ;; We do the sorting by regenerating the threads.
- (gnus-summary-prepare)
- ;; Hide subthreads if needed.
- (gnus-summary-maybe-hide-threads)))
- (defun gnus-summary-sort (predicate reverse)
- "Sort summary buffer by PREDICATE. REVERSE means reverse order."
- (let* ((thread (intern (format "gnus-thread-sort-by-%s" predicate)))
- (article (intern (format "gnus-article-sort-by-%s" predicate)))
- (gnus-thread-sort-functions
- (if (not reverse)
- thread
- `(lambda (t1 t2)
- (,thread t2 t1))))
- (gnus-sort-gathered-threads-function
- gnus-thread-sort-functions)
- (gnus-article-sort-functions
- (if (not reverse)
- article
- `(lambda (t1 t2)
- (,article t2 t1))))
- (inhibit-read-only t)
- (gnus-summary-prepare-hook nil))
- ;; We do the sorting by regenerating the threads.
- (gnus-summary-prepare)
- ;; Hide subthreads if needed.
- (gnus-summary-maybe-hide-threads)))
- ;; Summary saving commands.
- (defun gnus-summary-save-article (&optional n not-saved)
- "Save the current article using the default saver function.
- If N is a positive number, save the N next articles.
- If N is a negative number, save the N previous articles.
- If N is nil and any articles have been marked with the process mark,
- save those articles instead.
- The variable `gnus-default-article-saver' specifies the saver function.
- If the optional second argument NOT-SAVED is non-nil, articles saved
- will not be marked as saved."
- (interactive "P")
- (require 'gnus-art)
- (let* ((articles (gnus-summary-work-articles n))
- (save-buffer (save-excursion
- (nnheader-set-temp-buffer " *Gnus Save*")))
- (num (length articles))
- ;; Whether to save decoded articles or raw articles.
- (decode (when gnus-article-save-coding-system
- (get gnus-default-article-saver :decode)))
- ;; When saving many articles in a single file, use the other
- ;; function to save articles other than the first one.
- (saver2 (get gnus-default-article-saver :function))
- (gnus-prompt-before-saving (if saver2
- t
- gnus-prompt-before-saving))
- (gnus-default-article-saver gnus-default-article-saver)
- header file)
- (dolist (article articles)
- (setq header (gnus-summary-article-header article))
- (if (not (vectorp header))
- ;; This is a pseudo-article.
- (if (assq 'name header)
- (gnus-copy-file (cdr (assq 'name header)))
- (gnus-message 1 "Article %d is unsavable" article))
- ;; This is a real article.
- (save-window-excursion
- (gnus-summary-select-article decode decode nil article)
- (gnus-summary-goto-subject article))
- (with-current-buffer save-buffer
- (erase-buffer)
- (insert-buffer-substring (if decode
- gnus-article-buffer
- gnus-original-article-buffer)))
- (setq file (gnus-article-save save-buffer file num))
- (gnus-summary-remove-process-mark article)
- (unless not-saved
- (gnus-summary-set-saved-mark article)))
- (when saver2
- (setq gnus-default-article-saver saver2
- saver2 nil)))
- (gnus-kill-buffer save-buffer)
- (gnus-summary-position-point)
- (gnus-set-mode-line 'summary)
- n))
- (declare-function gnus-summary-save-in-pipe "gnus-art" (&optional command raw))
- (defun gnus-summary-pipe-output (&optional n sym)
- "Pipe the current article to a subprocess.
- If N is a positive number, pipe the N next articles.
- If N is a negative number, pipe the N previous articles.
- If N is nil and any articles have been marked with the process mark,
- pipe those articles instead.
- The default command to which articles are piped is specified by the
- variable `gnus-summary-pipe-output-default-command'; if it is nil, you
- will be prompted for the command.
- The properties `:decode' and `:headers' that are put to the function
- symbol `gnus-summary-save-in-pipe' control whether this function
- decodes articles and what headers to keep (see the doc string for the
- `gnus-default-article-saver' variable). If SYM (the symbolic prefix)
- is neither omitted nor the symbol `r', force including all headers
- regardless of the `:headers' property. If it is the symbol `r',
- articles that are not decoded and include all headers will be piped
- no matter what the properties `:decode' and `:headers' are."
- (interactive (gnus-interactive "P\ny"))
- (require 'gnus-art)
- (let* ((articles (gnus-summary-work-articles n))
- (result-buffer "*Shell Command Output*")
- (all-headers (not (memq sym '(nil r))))
- (gnus-save-all-headers (or all-headers gnus-save-all-headers))
- (raw (eq sym 'r))
- (headers (get 'gnus-summary-save-in-pipe :headers))
- command result)
- (unless (numberp (car articles))
- (error "No article to pipe"))
- (setq command (gnus-read-shell-command
- (concat "Shell command on "
- (if (cdr articles)
- (format "these %d articles" (length articles))
- "this article")
- ": ")
- gnus-summary-pipe-output-default-command))
- (when (string-equal command "")
- (error "A command is required"))
- (when all-headers
- (put 'gnus-summary-save-in-pipe :headers nil))
- (unwind-protect
- (while articles
- (gnus-summary-goto-subject (pop articles))
- (save-window-excursion (gnus-summary-save-in-pipe command raw))
- (when (and (get-buffer result-buffer)
- (not (zerop (buffer-size (get-buffer result-buffer)))))
- (setq result (concat result (with-current-buffer result-buffer
- (buffer-string))))))
- (put 'gnus-summary-save-in-pipe :headers headers))
- (unless (zerop (length result))
- (if (with-current-buffer (get-buffer-create result-buffer)
- (erase-buffer)
- (insert result)
- (prog1
- (and (= (count-lines (point-min) (point)) 1)
- (progn
- (end-of-line 0)
- (<= (current-column)
- (window-width (minibuffer-window)))))
- (goto-char (point-min))))
- (message "%s" (substring result 0 -1))
- (message nil)
- (gnus-configure-windows 'pipe)))))
- (defun gnus-summary-save-article-mail (&optional arg)
- "Append the current article to a Unix mail box file.
- If N is a positive number, save the N next articles.
- If N is a negative number, save the N previous articles.
- If N is nil and any articles have been marked with the process mark,
- save those articles instead."
- (interactive "P")
- (require 'gnus-art)
- (let ((gnus-default-article-saver 'gnus-summary-save-in-mail))
- (gnus-summary-save-article arg)))
- (defun gnus-summary-save-article-rmail (&optional arg)
- "Append the current article to an rmail file.
- If N is a positive number, save the N next articles.
- If N is a negative number, save the N previous articles.
- If N is nil and any articles have been marked with the process mark,
- save those articles instead."
- (interactive "P")
- (require 'gnus-art)
- (let ((gnus-default-article-saver 'gnus-summary-save-in-rmail))
- (gnus-summary-save-article arg)))
- (defun gnus-summary-save-article-file (&optional arg)
- "Append the current article to a file.
- If N is a positive number, save the N next articles.
- If N is a negative number, save the N previous articles.
- If N is nil and any articles have been marked with the process mark,
- save those articles instead."
- (interactive "P")
- (require 'gnus-art)
- (let ((gnus-default-article-saver 'gnus-summary-save-in-file))
- (gnus-summary-save-article arg)))
- (defun gnus-summary-write-article-file (&optional arg)
- "Write the current article to a file, deleting the previous file.
- If N is a positive number, save the N next articles.
- If N is a negative number, save the N previous articles.
- If N is nil and any articles have been marked with the process mark,
- save those articles instead."
- (interactive "P")
- (require 'gnus-art)
- (let ((gnus-default-article-saver 'gnus-summary-write-to-file))
- (gnus-summary-save-article arg)))
- (defun gnus-summary-save-article-body-file (&optional arg)
- "Append the current article body to a file.
- If N is a positive number, save the N next articles.
- If N is a negative number, save the N previous articles.
- If N is nil and any articles have been marked with the process mark,
- save those articles instead."
- (interactive "P")
- (require 'gnus-art)
- (let ((gnus-default-article-saver 'gnus-summary-save-body-in-file))
- (gnus-summary-save-article arg)))
- (defun gnus-summary-write-article-body-file (&optional arg)
- "Write the current article body to a file, deleting the previous file.
- If N is a positive number, save the N next articles.
- If N is a negative number, save the N previous articles.
- If N is nil and any articles have been marked with the process mark,
- save those articles instead."
- (interactive "P")
- (require 'gnus-art)
- (let ((gnus-default-article-saver 'gnus-summary-write-body-to-file))
- (gnus-summary-save-article arg)))
- (defun gnus-summary-muttprint (&optional arg)
- "Print the current article using Muttprint.
- If N is a positive number, save the N next articles.
- If N is a negative number, save the N previous articles.
- If N is nil and any articles have been marked with the process mark,
- save those articles instead."
- (interactive "P")
- (require 'gnus-art)
- (let ((gnus-default-article-saver 'gnus-summary-pipe-to-muttprint))
- (gnus-summary-save-article arg t)))
- (defun gnus-summary-pipe-message (program)
- "Pipe the current article through PROGRAM."
- (interactive "sProgram: ")
- (gnus-summary-select-article)
- (let ((mail-header-separator ""))
- (gnus-eval-in-buffer-window gnus-article-buffer
- (save-restriction
- (widen)
- (let ((start (window-start))
- (inhibit-read-only t))
- (message-pipe-buffer-body program)
- (set-window-start (get-buffer-window (current-buffer)) start))))))
- (defun gnus-get-split-value (methods)
- "Return a value based on the split METHODS."
- (let (split-name method result match)
- (when methods
- (with-current-buffer gnus-original-article-buffer
- (save-restriction
- (nnheader-narrow-to-headers)
- (while (and methods (not split-name))
- (goto-char (point-min))
- (setq method (pop methods))
- (setq match (car method))
- (when (cond
- ((stringp match)
- ;; Regular expression.
- (ignore-errors
- (re-search-forward match nil t)))
- ((functionp match)
- ;; Function.
- (save-restriction
- (widen)
- (setq result (funcall match gnus-newsgroup-name))))
- ((consp match)
- ;; Form.
- (save-restriction
- (widen)
- (setq result (eval match)))))
- (setq split-name (cdr method))
- (cond ((stringp result)
- (push (expand-file-name
- result gnus-article-save-directory)
- split-name))
- ((consp result)
- (setq split-name (append result split-name)))))))))
- (nreverse split-name)))
- (defun gnus-valid-move-group-p (group)
- (and (symbolp group)
- (boundp group)
- (symbol-name group)
- (symbol-value group)
- (gnus-get-function (gnus-find-method-for-group
- (symbol-name group)) 'request-accept-article t)))
- (defun gnus-read-move-group-name (prompt default articles prefix)
- "Read a group name."
- (let* ((split-name (gnus-get-split-value gnus-move-split-methods))
- (minibuffer-confirm-incomplete nil) ; XEmacs
- (prom
- (format "%s %s to"
- prompt
- (if (> (length articles) 1)
- (format "these %d articles" (length articles))
- "this article")))
- (to-newsgroup
- (cond
- ((null split-name)
- (gnus-group-completing-read
- prom
- (gnus-remove-if-not 'gnus-valid-move-group-p gnus-active-hashtb t)
- nil prefix nil default))
- ((= 1 (length split-name))
- (gnus-group-completing-read
- prom
- (gnus-remove-if-not 'gnus-valid-move-group-p gnus-active-hashtb t)
- nil prefix 'gnus-group-history (car split-name)))
- (t
- (gnus-completing-read
- prom (nreverse split-name) nil nil 'gnus-group-history))))
- (to-method (gnus-server-to-method (gnus-group-method to-newsgroup)))
- encoded)
- (when to-newsgroup
- (if (or (string= to-newsgroup "")
- (string= to-newsgroup prefix))
- (setq to-newsgroup default))
- (unless to-newsgroup
- (error "No group name entered"))
- (setq encoded (mm-encode-coding-string
- to-newsgroup
- (gnus-group-name-charset to-method to-newsgroup)))
- (or (gnus-active encoded)
- (gnus-activate-group encoded nil nil to-method)
- (if (gnus-y-or-n-p (format "No such group: %s. Create it? "
- to-newsgroup))
- (or (and (gnus-request-create-group encoded to-method)
- (gnus-activate-group encoded nil nil to-method)
- (gnus-subscribe-group encoded))
- (error "Couldn't create group %s" to-newsgroup)))
- (error "No such group: %s" to-newsgroup))
- encoded)))
- (defvar gnus-summary-save-parts-counter)
- (declare-function mm-uu-dissect "mm-uu" (&optional noheader mime-type))
- (defun gnus-summary-save-parts (type dir n &optional reverse)
- "Save parts matching TYPE to DIR.
- If REVERSE, save parts that do not match TYPE."
- (interactive
- (list (read-string "Save parts of type: "
- (or (car gnus-summary-save-parts-type-history)
- gnus-summary-save-parts-default-mime)
- 'gnus-summary-save-parts-type-history)
- (setq gnus-summary-save-parts-last-directory
- (read-directory-name "Save to directory: "
- gnus-summary-save-parts-last-directory
- nil t))
- current-prefix-arg))
- (gnus-summary-iterate n
- (let ((gnus-display-mime-function nil)
- gnus-article-prepare-hook
- gnus-article-decode-hook
- gnus-display-mime-function
- gnus-break-pages
- (gnus-inhibit-treatment t))
- (gnus-summary-select-article))
- (with-current-buffer gnus-article-buffer
- (let ((handles (or gnus-article-mime-handles
- (mm-dissect-buffer nil gnus-article-loose-mime)
- (and gnus-article-emulate-mime
- (mm-uu-dissect))))
- (gnus-summary-save-parts-counter 1))
- (when handles
- (gnus-summary-save-parts-1 type dir handles reverse)
- (unless gnus-article-mime-handles ;; Don't destroy this case.
- (mm-destroy-parts handles)))))))
- (defun gnus-summary-save-parts-1 (type dir handle reverse)
- (if (stringp (car handle))
- (mapcar (lambda (h) (gnus-summary-save-parts-1 type dir h reverse))
- (cdr handle))
- (when (if reverse
- (not (string-match type (mm-handle-media-type handle)))
- (string-match type (mm-handle-media-type handle)))
- (let ((file (expand-file-name
- (gnus-map-function
- mm-file-name-rewrite-functions
- (file-name-nondirectory
- (or
- (mm-handle-filename handle)
- (format "%s.%d.%d" gnus-newsgroup-name
- (cdr gnus-article-current)
- gnus-summary-save-parts-counter))))
- dir)))
- (incf gnus-summary-save-parts-counter)
- (unless (file-exists-p file)
- (mm-save-part-to-file handle file))))))
- ;; Summary extract commands
- (defun gnus-summary-insert-pseudos (pslist &optional not-view)
- (let ((inhibit-read-only t)
- (article (gnus-summary-article-number))
- after-article b e)
- (unless (gnus-summary-goto-subject article)
- (error "No such article: %d" article))
- (gnus-summary-position-point)
- ;; If all commands are to be bunched up on one line, we collect
- ;; them here.
- (unless gnus-view-pseudos-separately
- (let ((ps (setq pslist (sort pslist 'gnus-pseudos<)))
- files action)
- (while ps
- (setq action (cdr (assq 'action (car ps))))
- (setq files (list (cdr (assq 'name (car ps)))))
- (while (and ps (cdr ps)
- (string= (or action "1")
- (or (cdr (assq 'action (cadr ps))) "2")))
- (push (cdr (assq 'name (cadr ps))) files)
- (setcdr ps (cddr ps)))
- (when files
- (when (not (string-match "%s" action))
- (push " " files))
- (push " " files)
- (when (assq 'execute (car ps))
- (setcdr (assq 'execute (car ps))
- (funcall (if (string-match "%s" action)
- 'format 'concat)
- action
- (mapconcat
- (lambda (f)
- (if (equal f " ")
- f
- (shell-quote-argument f)))
- files " ")))))
- (setq ps (cdr ps)))))
- (if (and gnus-view-pseudos (not not-view))
- (while pslist
- (when (assq 'execute (car pslist))
- (gnus-execute-command (cdr (assq 'execute (car pslist)))
- (eq gnus-view-pseudos 'not-confirm)))
- (setq pslist (cdr pslist)))
- (save-excursion
- (while pslist
- (setq after-article (or (cdr (assq 'article (car pslist)))
- (gnus-summary-article-number)))
- (gnus-summary-goto-subject after-article)
- (forward-line 1)
- (setq b (point))
- (insert " " (file-name-nondirectory
- (cdr (assq 'name (car pslist))))
- ": " (or (cdr (assq 'execute (car pslist))) "") "\n")
- (setq e (point))
- (forward-line -1) ; back to `b'
- (gnus-add-text-properties
- b (1- e) (list 'gnus-number gnus-reffed-article-number
- gnus-mouse-face-prop gnus-mouse-face))
- (gnus-data-enter
- after-article gnus-reffed-article-number
- gnus-unread-mark b (car pslist) 0 (- e b))
- (setq gnus-newsgroup-unreads
- (gnus-add-to-sorted-list gnus-newsgroup-unreads
- gnus-reffed-article-number))
- (setq gnus-reffed-article-number (1- gnus-reffed-article-number))
- (setq pslist (cdr pslist)))))))
- (defun gnus-pseudos< (p1 p2)
- (let ((c1 (cdr (assq 'action p1)))
- (c2 (cdr (assq 'action p2))))
- (and c1 c2 (string< c1 c2))))
- (defun gnus-request-pseudo-article (props)
- (cond ((assq 'execute props)
- (gnus-execute-command (cdr (assq 'execute props)))))
- (let ((gnus-current-article (gnus-summary-article-number)))
- (gnus-run-hooks 'gnus-mark-article-hook)))
- (defun gnus-execute-command (command &optional automatic)
- (save-excursion
- (gnus-article-setup-buffer)
- (set-buffer gnus-article-buffer)
- (setq buffer-read-only nil)
- (let ((command (if automatic command
- (read-string "Command: " (cons command 0)))))
- (erase-buffer)
- (insert "$ " command "\n\n")
- (if gnus-view-pseudo-asynchronously
- (start-process "gnus-execute" (current-buffer) shell-file-name
- shell-command-switch command)
- (call-process shell-file-name nil t nil
- shell-command-switch command)))))
- ;; Summary kill commands.
- (defun gnus-summary-edit-global-kill (article)
- "Edit the \"global\" kill file."
- (interactive (list (gnus-summary-article-number)))
- (gnus-group-edit-global-kill article))
- (defun gnus-summary-edit-local-kill ()
- "Edit a local kill file applied to the current newsgroup."
- (interactive)
- (setq gnus-current-headers (gnus-summary-article-header))
- (gnus-group-edit-local-kill
- (gnus-summary-article-number) gnus-newsgroup-name))
- ;;; Header reading.
- (defun gnus-read-header (id &optional header)
- "Read the headers of article ID and enter them into the Gnus system."
- (let ((group gnus-newsgroup-name)
- (gnus-override-method
- (or
- gnus-override-method
- (and (gnus-news-group-p gnus-newsgroup-name)
- (car (gnus-refer-article-methods)))))
- where)
- ;; First we check to see whether the header in question is already
- ;; fetched.
- (if (stringp id)
- ;; This is a Message-ID.
- (setq header (or header (gnus-id-to-header id)))
- ;; This is an article number.
- (setq header (or header (gnus-summary-article-header id))))
- (if (and header
- (not (gnus-summary-article-sparse-p (mail-header-number header))))
- ;; We have found the header.
- header
- ;; We have to really fetch the header to this article.
- (with-current-buffer nntp-server-buffer
- (when (setq where (gnus-request-head id group))
- (nnheader-fold-continuation-lines)
- (goto-char (point-max))
- (insert ".\n")
- (goto-char (point-min))
- (insert "211 ")
- (princ (cond
- ((numberp id) id)
- ((cdr where) (cdr where))
- (header (mail-header-number header))
- (t gnus-reffed-article-number))
- (current-buffer))
- (insert " Article retrieved.\n"))
- (if (or (not where)
- (not (setq header (car (gnus-get-newsgroup-headers nil t)))))
- () ; Malformed head.
- (unless (gnus-summary-article-sparse-p (mail-header-number header))
- (when (and (bound-and-true-p gnus-registry-enabled)
- (not (gnus-ephemeral-group-p (car where))))
- (gnus-registry-handle-action
- (mail-header-id header) nil
- (gnus-group-prefixed-name
- (car where)
- (or gnus-override-method (gnus-find-method-for-group group)))
- (mail-header-subject header)
- (mail-header-from header)))
- (when (and (stringp id)
- (or
- (not (string= (gnus-group-real-name group)
- (car where)))
- (not (gnus-server-equal gnus-override-method
- (gnus-group-method group)))))
- ;; If we fetched by Message-ID and the article came from
- ;; a different group (or server), we fudge some bogus
- ;; article numbers for this article.
- (mail-header-set-number header gnus-reffed-article-number))
- (with-current-buffer gnus-summary-buffer
- (decf gnus-reffed-article-number)
- (gnus-remove-header (mail-header-number header))
- (push header gnus-newsgroup-headers)
- (setq gnus-current-headers header)
- (push (mail-header-number header) gnus-newsgroup-limit)))
- header)))))
- (defun gnus-remove-header (number)
- "Remove header NUMBER from `gnus-newsgroup-headers'."
- (if (and gnus-newsgroup-headers
- (= number (mail-header-number (car gnus-newsgroup-headers))))
- (pop gnus-newsgroup-headers)
- (let ((headers gnus-newsgroup-headers))
- (while (and (cdr headers)
- (not (= number (mail-header-number (cadr headers)))))
- (pop headers))
- (when (cdr headers)
- (setcdr headers (cddr headers))))))
- ;;;
- ;;; summary highlights
- ;;;
- (defun gnus-highlight-selected-summary ()
- "Highlight selected article in summary buffer."
- ;; Added by Per Abrahamsen <amanda@iesd.auc.dk>.
- (when gnus-summary-selected-face
- (save-excursion
- (let* ((beg (point-at-bol))
- (end (point-at-eol))
- ;; Fix by Mike Dugan <dugan@bucrf16.bu.edu>.
- (from (if (get-text-property beg gnus-mouse-face-prop)
- beg
- (or (next-single-property-change
- beg gnus-mouse-face-prop nil end)
- beg)))
- (to
- (if (= from end)
- (- from 2)
- (or (next-single-property-change
- from gnus-mouse-face-prop nil end)
- end))))
- ;; If no mouse-face prop on line we will have to = from = end,
- ;; so we highlight the entire line instead.
- (when (= (+ to 2) from)
- (setq from beg)
- (setq to end))
- (if gnus-newsgroup-selected-overlay
- ;; Move old overlay.
- (move-overlay
- gnus-newsgroup-selected-overlay from to (current-buffer))
- ;; Create new overlay.
- (overlay-put
- (setq gnus-newsgroup-selected-overlay (make-overlay from to))
- 'face gnus-summary-selected-face))))))
- (defvar gnus-summary-highlight-line-cached nil)
- (defvar gnus-summary-highlight-line-trigger nil)
- (defun gnus-summary-highlight-line-0 ()
- (if (and (eq gnus-summary-highlight-line-trigger
- gnus-summary-highlight)
- gnus-summary-highlight-line-cached)
- gnus-summary-highlight-line-cached
- (setq gnus-summary-highlight-line-trigger gnus-summary-highlight
- gnus-summary-highlight-line-cached
- (let* ((cond (list 'cond))
- (c cond)
- (list gnus-summary-highlight))
- (while list
- (setcdr c (cons (list (caar list) (list 'quote (cdar list)))
- nil))
- (setq c (cdr c)
- list (cdr list)))
- (gnus-byte-compile (list 'lambda nil cond))))))
- (defun gnus-summary-highlight-line ()
- "Highlight current line according to `gnus-summary-highlight'."
- (let* ((beg (point-at-bol))
- (article (or (gnus-summary-article-number) gnus-current-article))
- (score (or (cdr (assq article
- gnus-newsgroup-scored))
- gnus-summary-default-score 0))
- (mark (or (gnus-summary-article-mark) gnus-unread-mark))
- (inhibit-read-only t)
- (default gnus-summary-default-score)
- (default-high gnus-summary-default-high-score)
- (default-low gnus-summary-default-low-score)
- (uncached (and gnus-summary-use-undownloaded-faces
- (memq article gnus-newsgroup-undownloaded)
- (not (memq article gnus-newsgroup-cached)))))
- (let ((face (funcall (gnus-summary-highlight-line-0))))
- (unless (eq face (gnus-get-text-property-excluding-characters-with-faces beg 'face))
- (gnus-put-text-property-excluding-characters-with-faces
- beg (point-at-eol) 'face
- (setq face (if (boundp face) (symbol-value face) face)))
- (when gnus-summary-highlight-line-function
- (funcall gnus-summary-highlight-line-function article face))))))
- (defun gnus-update-read-articles (group unread &optional compute)
- "Update the list of read articles in GROUP.
- UNREAD is a sorted list."
- (let ((active (or gnus-newsgroup-active (gnus-active group)))
- (info (gnus-get-info group))
- (prev 1)
- read)
- (if (or (not info) (not active))
- ;; There is no info on this group if it was, in fact,
- ;; killed. Gnus stores no information on killed groups, so
- ;; there's nothing to be done.
- ;; One could store the information somewhere temporarily,
- ;; perhaps... Hmmm...
- ()
- ;; Remove any negative articles numbers.
- (while (and unread (< (car unread) 0))
- (setq unread (cdr unread)))
- ;; Remove any expired article numbers
- (while (and unread (< (car unread) (car active)))
- (setq unread (cdr unread)))
- ;; Compute the ranges of read articles by looking at the list of
- ;; unread articles.
- (while unread
- (when (/= (car unread) prev)
- (push (if (= prev (1- (car unread))) prev
- (cons prev (1- (car unread))))
- read))
- (setq prev (1+ (car unread)))
- (setq unread (cdr unread)))
- (when (<= prev (cdr active))
- (push (cons prev (cdr active)) read))
- (setq read (if (> (length read) 1) (nreverse read) read))
- (if compute
- read
- (save-excursion
- (let (setmarkundo)
- ;; Propagate the read marks to the backend.
- (when (and (gnus-method-option-p
- (gnus-find-method-for-group group)
- 'server-marks)
- (gnus-check-backend-function 'request-set-mark group))
- (let ((del (gnus-remove-from-range (gnus-info-read info) read))
- (add (gnus-remove-from-range read (gnus-info-read info))))
- (when (or add del)
- (unless (gnus-check-group group)
- (error "Can't open server for %s" group))
- (gnus-request-set-mark
- group (delq nil (list (if add (list add 'add '(read)))
- (if del (list del 'del '(read))))))
- (setq setmarkundo
- `(gnus-request-set-mark
- ,group
- ',(delq nil (list
- (if del (list del 'add '(read)))
- (if add (list add 'del '(read))))))))))
- (set-buffer gnus-group-buffer)
- (gnus-undo-register
- `(progn
- (gnus-info-set-marks ',info ',(gnus-info-marks info) t)
- (gnus-info-set-read ',info ',(gnus-info-read info))
- (gnus-get-unread-articles-in-group ',info
- (gnus-active ,group))
- (gnus-group-update-group ,group t)
- ,setmarkundo))))
- ;; Enter this list into the group info.
- (gnus-info-set-read info read)
- ;; Set the number of unread articles in gnus-newsrc-hashtb.
- (gnus-get-unread-articles-in-group info (gnus-active group))
- t))))
- (defun gnus-offer-save-summaries ()
- "Offer to save all active summary buffers."
- (let (buffers)
- ;; Go through all buffers and find all summaries.
- (dolist (buffer (buffer-list))
- (when (and (setq buffer (buffer-name buffer))
- (string-match "Summary" buffer)
- (with-current-buffer buffer
- ;; We check that this is, indeed, a summary buffer.
- (and (derived-mode-p 'gnus-summary-mode)
- ;; Also make sure this isn't bogus.
- gnus-newsgroup-prepared
- ;; Also make sure that this isn't a
- ;; dead summary buffer.
- (not gnus-dead-summary-mode))))
- (push buffer buffers)))
- ;; Go through all these summary buffers and offer to save them.
- (when buffers
- (save-excursion
- (if (eq gnus-interactive-exit 'quiet)
- (dolist (buffer buffers)
- (switch-to-buffer buffer)
- (gnus-summary-exit))
- (map-y-or-n-p
- "Update summary buffer %s? "
- (lambda (buf)
- (switch-to-buffer buf)
- (gnus-summary-exit))
- buffers))))))
- (defun gnus-summary-setup-default-charset ()
- "Setup newsgroup default charset."
- (if (member gnus-newsgroup-name '("nndraft:delayed" "nndraft:drafts"))
- (setq gnus-newsgroup-charset nil)
- (let* ((ignored-charsets
- (or gnus-newsgroup-ephemeral-ignored-charsets
- (append
- (and gnus-newsgroup-name
- (gnus-parameter-ignored-charsets gnus-newsgroup-name))
- gnus-newsgroup-ignored-charsets))))
- (setq gnus-newsgroup-charset
- (or gnus-newsgroup-ephemeral-charset
- (and gnus-newsgroup-name
- (gnus-parameter-charset gnus-newsgroup-name))
- gnus-default-charset))
- (set (make-local-variable 'gnus-newsgroup-ignored-charsets)
- ignored-charsets))))
- ;;;
- ;;; Mime Commands
- ;;;
- (defun gnus-summary-display-buttonized (&optional show-all-parts)
- "Display the current article buffer fully MIME-buttonized.
- If SHOW-ALL-PARTS (the prefix) is non-nil, all multipart/* parts are
- treated as multipart/mixed."
- (interactive "P")
- (require 'gnus-art)
- (let ((gnus-unbuttonized-mime-types nil)
- (gnus-mime-display-multipart-as-mixed show-all-parts))
- (gnus-summary-show-article)))
- (defun gnus-summary-repair-multipart (article)
- "Add a Content-Type header to a multipart article without one."
- (interactive (list (gnus-summary-article-number)))
- (gnus-with-article article
- (message-narrow-to-head)
- (message-remove-header "Mime-Version")
- (goto-char (point-max))
- (insert "Mime-Version: 1.0\n")
- (widen)
- (when (search-forward "\n--" nil t)
- (let ((separator (buffer-substring (point) (point-at-eol))))
- (message-narrow-to-head)
- (message-remove-header "Content-Type")
- (goto-char (point-max))
- (insert (format "Content-Type: multipart/mixed; boundary=\"%s\"\n"
- separator))
- (widen))))
- (let (gnus-mark-article-hook)
- (gnus-summary-select-article t t nil article)))
- (defun gnus-summary-toggle-display-buttonized ()
- "Toggle the buttonizing of the article buffer."
- (interactive)
- (require 'gnus-art)
- (if (setq gnus-inhibit-mime-unbuttonizing
- (not gnus-inhibit-mime-unbuttonizing))
- (let ((gnus-unbuttonized-mime-types nil))
- (gnus-summary-show-article))
- (gnus-summary-show-article)))
- ;;;
- ;;; Generic summary marking commands
- ;;;
- (defvar gnus-summary-marking-alist
- '((read gnus-del-mark "d")
- (unread gnus-unread-mark "u")
- (ticked gnus-ticked-mark "!")
- (dormant gnus-dormant-mark "?")
- (expirable gnus-expirable-mark "e"))
- "An alist of names/marks/keystrokes.")
- (defvar gnus-summary-generic-mark-map (make-sparse-keymap))
- (defvar gnus-summary-mark-map)
- (defun gnus-summary-make-all-marking-commands ()
- (define-key gnus-summary-mark-map "M" gnus-summary-generic-mark-map)
- (dolist (elem gnus-summary-marking-alist)
- (apply 'gnus-summary-make-marking-command elem)))
- (defun gnus-summary-make-marking-command (name mark keystroke)
- (let ((map (make-sparse-keymap)))
- (define-key gnus-summary-generic-mark-map keystroke map)
- (dolist (lway `((next "next" next nil "n")
- (next-unread "next unread" next t "N")
- (prev "previous" prev nil "p")
- (prev-unread "previous unread" prev t "P")
- (nomove "" nil nil ,keystroke)))
- (let ((func (gnus-summary-make-marking-command-1
- mark (car lway) lway name)))
- (setq func (eval func))
- (define-key map (nth 4 lway) func)))))
- (defun gnus-summary-make-marking-command-1 (mark way lway name)
- `(defun ,(intern
- (format "gnus-summary-put-mark-as-%s%s"
- name (if (eq way 'nomove)
- ""
- (concat "-" (symbol-name way)))))
- (n)
- ,(format
- "Mark the current article as %s%s.
- If N, the prefix, then repeat N times.
- If N is negative, move in reverse order.
- The difference between N and the actual number of articles marked is
- returned."
- name (cadr lway))
- (interactive "p")
- (gnus-summary-generic-mark n ,mark ',(nth 2 lway) ,(nth 3 lway))))
- (defun gnus-summary-generic-mark (n mark move unread)
- "Mark N articles with MARK."
- (unless (derived-mode-p 'gnus-summary-mode)
- (error "This command can only be used in the summary buffer"))
- (gnus-summary-show-thread)
- (let ((nummove
- (cond
- ((eq move 'next) 1)
- ((eq move 'prev) -1)
- (t 0))))
- (if (zerop nummove)
- (setq n 1)
- (when (< n 0)
- (setq n (abs n)
- nummove (* -1 nummove))))
- (while (and (> n 0)
- (gnus-summary-mark-article nil mark)
- (zerop (gnus-summary-next-subject nummove unread t)))
- (setq n (1- n)))
- (when (/= 0 n)
- (gnus-message 7 "No more %sarticles" (if mark "" "unread ")))
- (gnus-summary-recenter)
- (gnus-summary-position-point)
- (gnus-set-mode-line 'summary)
- n))
- (defun gnus-summary-insert-articles (articles)
- (when (setq articles
- (gnus-sorted-difference articles
- (mapcar (lambda (h)
- (mail-header-number h))
- gnus-newsgroup-headers)))
- (setq gnus-newsgroup-headers
- (gnus-merge 'list
- gnus-newsgroup-headers
- (gnus-fetch-headers articles nil t)
- 'gnus-article-sort-by-number))
- (setq gnus-newsgroup-articles
- (gnus-sorted-nunion gnus-newsgroup-articles articles))
- ;; Suppress duplicates?
- (when gnus-suppress-duplicates
- (gnus-dup-suppress-articles))
- (if (and gnus-fetch-old-headers
- (eq gnus-headers-retrieved-by 'nov))
- ;; We might want to build some more threads first.
- (if (eq gnus-fetch-old-headers 'invisible)
- (gnus-build-all-threads)
- (gnus-build-old-threads))
- ;; Mark the inserted articles that are unread as unread.
- (setq gnus-newsgroup-unreads
- (gnus-sorted-nunion
- gnus-newsgroup-unreads
- (gnus-sorted-nintersection
- (gnus-list-of-unread-articles gnus-newsgroup-name)
- articles)))
- ;; Mark the inserted articles as selected so that the information
- ;; of the marks having been changed by a user may be updated when
- ;; exiting this group. See `gnus-summary-update-info'.
- (dolist (art articles)
- (setq gnus-newsgroup-unselected (delq art gnus-newsgroup-unselected))))
- ;; Let the Gnus agent mark articles as read.
- (when gnus-agent
- (gnus-agent-get-undownloaded-list))
- ;; Remove list identifiers from subject
- (gnus-summary-remove-list-identifiers)
- ;; First and last article in this newsgroup.
- (when gnus-newsgroup-headers
- (setq gnus-newsgroup-begin
- (mail-header-number (car gnus-newsgroup-headers))
- gnus-newsgroup-end
- (mail-header-number
- (gnus-last-element gnus-newsgroup-headers))))
- (when gnus-use-scoring
- (gnus-possibly-score-headers))))
- (defun gnus-summary-insert-old-articles (&optional all)
- "Insert all old articles in this group.
- If ALL is non-nil, already read articles become readable.
- If ALL is a number, fetch this number of articles."
- (interactive "P")
- (prog1
- (let ((old (sort (mapcar 'car gnus-newsgroup-data) '<))
- older len)
- (setq older
- ;; Some nntp servers lie about their active range. When
- ;; this happens, the active range can be in the millions.
- ;; Use a compressed range to avoid creating a huge list.
- (gnus-range-difference
- (gnus-range-difference (list gnus-newsgroup-active) old)
- gnus-newsgroup-unexist))
- (setq len (gnus-range-length older))
- (cond
- ((null older) nil)
- ((numberp all)
- (if (< all len)
- (let ((older-range (nreverse older)))
- (setq older nil)
- (while (> all 0)
- (let* ((r (pop older-range))
- (min (if (numberp r) r (car r)))
- (max (if (numberp r) r (cdr r))))
- (while (and (<= min max)
- (> all 0))
- (push max older)
- (setq all (1- all)
- max (1- max))))))
- (setq older (gnus-uncompress-range older))))
- (all
- (setq older (gnus-uncompress-range older)))
- (t
- (when (and (numberp gnus-large-newsgroup)
- (> len gnus-large-newsgroup))
- (let* ((cursor-in-echo-area nil)
- (initial (gnus-parameter-large-newsgroup-initial
- gnus-newsgroup-name))
- (input
- (read-string
- (format
- "How many articles from %s (%s %d): "
- (gnus-group-decoded-name gnus-newsgroup-name)
- (if initial "max" "default")
- len)
- nil nil
- (and initial
- (number-to-string initial)))))
- (unless (string-match "^[ \t]*$" input)
- (setq all (string-to-number input))
- (if (< all len)
- (let ((older-range (nreverse older)))
- (setq older nil)
- (while (> all 0)
- (let* ((r (pop older-range))
- (min (if (numberp r) r (car r)))
- (max (if (numberp r) r (cdr r))))
- (while (and (<= min max)
- (> all 0))
- (push max older)
- (setq all (1- all)
- max (1- max))))))))))
- (setq older (gnus-uncompress-range older))))
- (if (not older)
- (message "No old news.")
- (gnus-summary-insert-articles older)
- (gnus-summary-limit (gnus-sorted-nunion old older))))
- (gnus-summary-position-point)))
- (defun gnus-summary-insert-new-articles ()
- "Insert all new articles in this group."
- (interactive)
- (let ((old (sort (mapcar 'car gnus-newsgroup-data) '<))
- (old-high gnus-newsgroup-highest)
- (nnmail-fetched-sources (list t))
- (new-active (gnus-activate-group gnus-newsgroup-name 'scan))
- i new)
- (unless new-active
- (error "Couldn't fetch new data"))
- (setq gnus-newsgroup-active (gnus-copy-sequence new-active))
- (setq i (cdr gnus-newsgroup-active)
- gnus-newsgroup-highest i)
- (while (> i old-high)
- (push i new)
- (decf i))
- (if (not new)
- (message "No gnus is bad news")
- (gnus-summary-insert-articles new)
- (setq gnus-newsgroup-unreads
- (gnus-sorted-nunion gnus-newsgroup-unreads new))
- (gnus-summary-limit (gnus-sorted-nunion old new))))
- (gnus-summary-position-point))
- ;;; Bookmark support for Gnus.
- (declare-function gnus-article-show-summary "gnus-art" ())
- (declare-function bookmark-make-record-default
- "bookmark" (&optional no-file no-context posn))
- (declare-function bookmark-prop-get "bookmark" (bookmark prop))
- (declare-function bookmark-default-handler "bookmark" (bmk))
- (declare-function bookmark-get-bookmark-record "bookmark" (bmk))
- (defvar bookmark-yank-point)
- (defvar bookmark-current-buffer)
- (defun gnus-summary-bookmark-make-record ()
- "Make a bookmark entry for a Gnus summary buffer."
- (let (pos buf)
- (unless (and (derived-mode-p 'gnus-summary-mode) gnus-article-current)
- (save-restriction ; FIXME is it necessary to widen?
- (widen) (setq pos (point))) ; Set position in gnus-article buffer.
- (setq buf "art") ; We are recording bookmark from article buffer.
- (setq bookmark-yank-point (point))
- (setq bookmark-current-buffer (current-buffer))
- (gnus-article-show-summary)) ; Go back in summary buffer.
- ;; We are now recording bookmark from summary buffer.
- (unless buf (setq buf "sum"))
- (let* ((subject (elt (gnus-summary-article-header) 1))
- (grp (car gnus-article-current))
- (art (cdr gnus-article-current))
- (head (gnus-summary-article-header art))
- (id (mail-header-id head)))
- `(,subject
- ,@(condition-case nil
- (bookmark-make-record-default 'no-file 'no-context pos)
- (wrong-number-of-arguments
- (bookmark-make-record-default 'point-only)))
- (location . ,(format "Gnus-%s %s:%d:%s" buf grp art id))
- (group . ,grp) (article . ,art)
- (message-id . ,id) (handler . gnus-summary-bookmark-jump)))))
- ;;;###autoload
- (defun gnus-summary-bookmark-jump (bookmark)
- "Handler function for record returned by `gnus-summary-bookmark-make-record'.
- BOOKMARK is a bookmark name or a bookmark record."
- (let ((group (bookmark-prop-get bookmark 'group))
- (article (bookmark-prop-get bookmark 'article))
- (id (bookmark-prop-get bookmark 'message-id))
- (buf (car (split-string (bookmark-prop-get bookmark 'location)))))
- (gnus-fetch-group group (list article))
- (gnus-summary-insert-cached-articles)
- (gnus-summary-goto-article id nil 'force)
- ;; FIXME we have to wait article buffer is ready (only large buffer)
- ;; Is there a better solution to know that?
- ;; If we don't wait `bookmark-default-handler' will have no chance
- ;; to set position. However there is no error, just wrong pos.
- (sit-for 1)
- (when (string= buf "Gnus-art")
- (other-window 1))
- (bookmark-default-handler
- `(""
- (buffer . ,(current-buffer))
- . ,(bookmark-get-bookmark-record bookmark)))))
- (gnus-summary-make-all-marking-commands)
- (gnus-ems-redefine)
- (provide 'gnus-sum)
- (run-hooks 'gnus-sum-load-hook)
- ;; Local Variables:
- ;; coding: utf-8
- ;; End:
- ;;; gnus-sum.el ends here
|