You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

lua_task.c 145KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269
  1. /*-
  2. * Copyright 2016 Vsevolod Stakhov
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include "lua_common.h"
  17. #include "message.h"
  18. #include "images.h"
  19. #include "archives.h"
  20. #include "utlist.h"
  21. #include "unix-std.h"
  22. #include "libmime/smtp_parsers.h"
  23. #include "libserver/mempool_vars_internal.h"
  24. #include "libserver/dkim.h"
  25. #include "libserver/task.h"
  26. #include "libserver/cfg_file_private.h"
  27. #include "libmime/filter_private.h"
  28. #include "libstat/stat_api.h"
  29. #include "libutil/map_helpers.h"
  30. #include <math.h>
  31. /***
  32. * @module rspamd_task
  33. * This module provides routines for tasks manipulation in rspamd. Tasks usually
  34. * represent messages being scanned, and this API provides access to such elements
  35. * as headers, symbols, metrics and so on and so forth. Normally, task objects
  36. * are passed to the lua callbacks allowing to check specific properties of messages
  37. * and add the corresponding symbols to the scan's results.
  38. @example
  39. rspamd_config.DATE_IN_PAST = function(task)
  40. local dm = task:get_date{format = 'message', gmt = true}
  41. local dt = task:get_date{format = 'connect', gmt = true}
  42. -- A day
  43. if dt - dm > 86400 then
  44. return true
  45. end
  46. return false
  47. end
  48. */
  49. /* Task methods */
  50. /***
  51. * @function rspamd_task.create([cfg])
  52. * Create a new empty task
  53. * @return {rspamd_task} new task
  54. */
  55. LUA_FUNCTION_DEF (task, create);
  56. /***
  57. * @function rspamd_task.load_from_file(filename[, cfg])
  58. * Loads a message from specific file
  59. * @return {boolean,rspamd_task|error} status + new task or error message
  60. */
  61. LUA_FUNCTION_DEF (task, load_from_file);
  62. /***
  63. * @function rspamd_task.load_from_string(message[, cfg])
  64. * Loads a message from specific file
  65. * @return {boolean,rspamd_task|error} status + new task or error message
  66. */
  67. LUA_FUNCTION_DEF (task, load_from_string);
  68. LUA_FUNCTION_DEF (task, get_message);
  69. /***
  70. * @method task:process_message()
  71. * Parses message
  72. */
  73. LUA_FUNCTION_DEF (task, process_message);
  74. /***
  75. * @method task:get_cfg()
  76. * Get configuration object for a task.
  77. * @return {rspamd_config} (config.md)[configuration object] for the task
  78. */
  79. LUA_FUNCTION_DEF (task, get_cfg);
  80. LUA_FUNCTION_DEF (task, set_cfg);
  81. LUA_FUNCTION_DEF (task, destroy);
  82. /***
  83. * @method task:get_mempool()
  84. * Returns memory pool valid for a lifetime of task. It is used internally by
  85. * many rspamd routines.
  86. * @return {rspamd_mempool} memory pool object
  87. */
  88. LUA_FUNCTION_DEF (task, get_mempool);
  89. /***
  90. * @method task:get_session()
  91. * Returns asynchronous session object that is used by many rspamd asynchronous
  92. * utilities internally.
  93. * @return {rspamd_session} session object
  94. */
  95. LUA_FUNCTION_DEF (task, get_session);
  96. /***
  97. * @method task:set_session(session)
  98. * Sets new async session for a task
  99. */
  100. LUA_FUNCTION_DEF (task, set_session);
  101. /***
  102. * @method task:get_ev_base()
  103. * Return asynchronous event base for using in callbacks and resolver.
  104. * @return {rspamd_ev_base} event base
  105. */
  106. LUA_FUNCTION_DEF (task, get_ev_base);
  107. /***
  108. * @method task:get_worker()
  109. * Returns a worker object associated with the task
  110. * @return {rspamd_worker} worker object
  111. */
  112. LUA_FUNCTION_DEF (task, get_worker);
  113. /***
  114. * @method task:insert_result([enforce_symbol,]symbol, weight[, option1, ...])
  115. * Insert specific symbol to the tasks scanning results assigning the initial
  116. * weight to it.
  117. * @param {boolean} enforce_symbol if represented and true, then insert symbol even if it is not registered in the metric
  118. * @param {string} symbol symbol to insert
  119. * @param {number} weight initial weight (this weight is multiplied by the metric weight)
  120. * @param {string} options list of optional options attached to a symbol inserted
  121. @example
  122. local function cb(task)
  123. if task:get_header('Some header') then
  124. task:insert_result('SOME_HEADER', 1.0, 'Got some header')
  125. end
  126. end
  127. */
  128. LUA_FUNCTION_DEF (task, insert_result);
  129. /***
  130. * @method task:adjust_result(symbol, score[, option1, ...])
  131. * Alters the existing symbol's score to a new score. It is not affected by
  132. * metric score or grow factor. You can also add new options
  133. * using this method. Symbol must be already inserted into metric or an error
  134. * will be emitted.
  135. * @param {string} symbol symbol to adjust
  136. * @param {number} score this value is NOT multiplied by the metric score
  137. * @param {string/table} options list of optional options attached to a symbol adjusted
  138. */
  139. LUA_FUNCTION_DEF (task, adjust_result);
  140. /***
  141. * @method task:set_pre_result(action, description)
  142. * Sets pre-result for a task. It is used in pre-filters to specify early result
  143. * of the task scanned. If a pre-filter sets some result, then further processing
  144. * may be skipped. For selecting action it is possible to use global table
  145. * `rspamd_actions` or a string value:
  146. *
  147. * - `reject`: reject message permanently
  148. * - `add header`: add spam header
  149. * - `rewrite subject`: rewrite subject to spam subject
  150. * - `greylist`: greylist message
  151. * - `accept` or `no action`: whitelist message
  152. * @param {rspamd_action or string} action a numeric or string action value
  153. * @param {string} description optional description
  154. @example
  155. local function cb(task)
  156. local gr = task:get_header('Greylist')
  157. if gr and gr == 'greylist' then
  158. task:set_pre_result(rspamd_actions['greylist'], 'Greylisting required')
  159. end
  160. end
  161. */
  162. LUA_FUNCTION_DEF (task, set_pre_result);
  163. /***
  164. * @method task:has_pre_result()
  165. * Returns true if task has some pre-result being set
  166. *
  167. * @return {boolean} true if task has some pre-result being set
  168. */
  169. LUA_FUNCTION_DEF (task, has_pre_result);
  170. /***
  171. * @method task:append_message(message, [category])
  172. * Adds a message to scanning output.
  173. * @param {string} message
  174. * @param {category} message category
  175. @example
  176. local function cb(task)
  177. task:append_message('Example message')
  178. end
  179. */
  180. LUA_FUNCTION_DEF (task, append_message);
  181. /***
  182. * @method task:get_urls([need_emails|list_protos])
  183. * Get all URLs found in a message. Telephone urls and emails are not included unless explicitly asked in `list_protos`
  184. * @param {boolean} need_emails if `true` then reutrn also email urls, this can be a comma separated string of protocols desired or a table (e.g. `mailto` or `telephone`)
  185. * @return {table rspamd_url} list of all urls found
  186. @example
  187. local function phishing_cb(task)
  188. local urls = task:get_urls({'https', 'http'});
  189. if urls then
  190. for _,url in ipairs(urls) do
  191. if url:is_phished() then
  192. return true
  193. end
  194. end
  195. end
  196. return false
  197. end
  198. */
  199. LUA_FUNCTION_DEF (task, get_urls);
  200. /***
  201. * @method task:has_urls([need_emails])
  202. * Returns 'true' if a task has urls listed
  203. * @param {boolean} need_emails if `true` then reutrn also email urls
  204. * @return {boolean} true if a task has urls (urls or emails if `need_emails` is true)
  205. */
  206. LUA_FUNCTION_DEF (task, has_urls);
  207. /***
  208. * @method task:get_content()
  209. * Get raw content for the specified task
  210. * @return {text} the data contained in the task
  211. */
  212. LUA_FUNCTION_DEF (task, get_content);
  213. /***
  214. * @method task:get_filename()
  215. * Returns filename for a specific task
  216. * @return {string|nil} filename or nil if unknown
  217. */
  218. LUA_FUNCTION_DEF (task, get_filename);
  219. /***
  220. * @method task:get_rawbody()
  221. * Get raw body for the specified task
  222. * @return {text} the data contained in the task
  223. */
  224. LUA_FUNCTION_DEF (task, get_rawbody);
  225. /***
  226. * @method task:get_emails()
  227. * Get all email addresses found in a message.
  228. * @return {table rspamd_url} list of all email addresses found
  229. */
  230. LUA_FUNCTION_DEF (task, get_emails);
  231. /***
  232. * @method task:get_text_parts()
  233. * Get all text (and HTML) parts found in a message
  234. * @return {table rspamd_text_part} list of text parts
  235. */
  236. LUA_FUNCTION_DEF (task, get_text_parts);
  237. /***
  238. * @method task:get_parts()
  239. * Get all mime parts found in a message
  240. * @return {table rspamd_mime_part} list of mime parts
  241. */
  242. LUA_FUNCTION_DEF (task, get_parts);
  243. /***
  244. * @method task:get_meta_words([how='stem'])
  245. * Get meta words from task (subject and displayed names)
  246. * - `stem`: stemmed words (default)
  247. * - `norm`: normalised words (utf normalised + lowercased)
  248. * - `raw`: raw words in utf (if possible)
  249. * - `full`: list of tables, each table has the following fields:
  250. * - [1] - stemmed word
  251. * - [2] - normalised word
  252. * - [3] - raw word
  253. * - [4] - flags (table of strings)
  254. */
  255. LUA_FUNCTION_DEF (task, get_meta_words);
  256. /***
  257. * @method task:get_request_header(name)
  258. * Get value of a HTTP request header.
  259. * @param {string} name name of header to get
  260. * @return {rspamd_text} value of an HTTP header
  261. */
  262. LUA_FUNCTION_DEF (task, get_request_header);
  263. /***
  264. * @method task:set_request_header(name, value)
  265. * Set value of a HTTP request header. If value is omitted, then a header is removed
  266. * @param {string} name name of header to get
  267. * @param {rspamd_text/string} value new header's value
  268. */
  269. LUA_FUNCTION_DEF (task, set_request_header);
  270. /***
  271. * @method task:get_subject()
  272. * Returns task subject (either from the protocol override or from a header)
  273. * @return {string} value of a subject (decoded)
  274. */
  275. LUA_FUNCTION_DEF (task, get_subject);
  276. /***
  277. * @method task:get_header(name[, case_sensitive])
  278. * Get decoded value of a header specified with optional case_sensitive flag.
  279. * By default headers are searched in caseless matter.
  280. * @param {string} name name of header to get
  281. * @param {boolean} case_sensitive case sensitiveness flag to search for a header
  282. * @return {string} decoded value of a header
  283. */
  284. LUA_FUNCTION_DEF (task, get_header);
  285. /***
  286. * @method task:get_header_raw(name[, case_sensitive])
  287. * Get raw value of a header specified with optional case_sensitive flag.
  288. * By default headers are searched in caseless matter.
  289. * @param {string} name name of header to get
  290. * @param {boolean} case_sensitive case sensitiveness flag to search for a header
  291. * @return {string} raw value of a header
  292. */
  293. LUA_FUNCTION_DEF (task, get_header_raw);
  294. /***
  295. * @method task:get_header_full(name[, case_sensitive])
  296. * Get raw value of a header specified with optional case_sensitive flag.
  297. * By default headers are searched in caseless matter. This method returns more
  298. * information about the header as a list of tables with the following structure:
  299. *
  300. * - `name` - name of a header
  301. * - `value` - raw value of a header
  302. * - `decoded` - decoded value of a header
  303. * - `tab_separated` - `true` if a header and a value are separated by `tab` character
  304. * - `empty_separator` - `true` if there are no separator between a header and a value
  305. * @param {string} name name of header to get
  306. * @param {boolean} case_sensitive case sensitiveness flag to search for a header
  307. * @return {list of tables} all values of a header as specified above
  308. @example
  309. function check_header_delimiter_tab(task, header_name)
  310. for _,rh in ipairs(task:get_header_full(header_name)) do
  311. if rh['tab_separated'] then return true end
  312. end
  313. return false
  314. end
  315. */
  316. LUA_FUNCTION_DEF (task, get_header_full);
  317. /***
  318. * @method task:get_header_count(name[, case_sensitive])
  319. * Lightweight version if you need just a header's count
  320. * * By default headers are searched in caseless matter.
  321. * @param {string} name name of header to get
  322. * @param {boolean} case_sensitive case sensitiveness flag to search for a header
  323. * @return {number} number of header's occurrencies or 0 if not found
  324. */
  325. LUA_FUNCTION_DEF (task, get_header_count);
  326. /***
  327. * @method task:get_raw_headers()
  328. * Get all undecoded headers of a message as a string
  329. * @return {rspamd_text} all raw headers for a message as opaque text
  330. */
  331. LUA_FUNCTION_DEF (task, get_raw_headers);
  332. /***
  333. * @method task:get_received_headers()
  334. * Returns a list of tables of parsed received headers. A tables returned have
  335. * the following structure:
  336. *
  337. * - `from_hostname` - string that represents hostname provided by a peer
  338. * - `from_ip` - string representation of IP address as provided by a peer
  339. * - `real_hostname` - hostname as resolved by MTA
  340. * - `real_ip` - string representation of IP as resolved by PTR request of MTA
  341. * - `by_hostname` - MTA hostname
  342. * - `proto` - protocol, e.g. ESMTP or ESMTPS
  343. * - `timestamp` - received timestamp
  344. * - `for` - for value (unparsed mailbox)
  345. *
  346. * Please note that in some situations rspamd cannot parse all the fields of received headers.
  347. * In that case you should check all strings for validity.
  348. * @return {table of tables} list of received headers described above
  349. */
  350. LUA_FUNCTION_DEF (task, get_received_headers);
  351. /***
  352. * @method task:get_queue_id()
  353. * Returns queue ID of the message being processed.
  354. */
  355. LUA_FUNCTION_DEF (task, get_queue_id);
  356. /***
  357. * @method task:get_uid()
  358. * Returns ID of the task being processed.
  359. */
  360. LUA_FUNCTION_DEF (task, get_uid);
  361. /***
  362. * @method task:get_resolver()
  363. * Returns ready to use rspamd_resolver object suitable for making asynchronous DNS requests.
  364. * @return {rspamd_resolver} resolver object associated with the task's session
  365. * @example
  366. local logger = require "rspamd_logger"
  367. local function task_cb(task)
  368. local function dns_cb(resolver, to_resolve, results, err)
  369. -- task object is available due to closure
  370. task:inc_dns_req()
  371. if results then
  372. logger.info(string.format('<%s> [%s] resolved for symbol: %s',
  373. task:get_message_id(), to_resolve, 'EXAMPLE_SYMBOL'))
  374. task:insert_result('EXAMPLE_SYMBOL', 1)
  375. end
  376. end
  377. local r = task:get_resolver()
  378. r:resolve_a(task:get_session(), task:get_mempool(), 'example.com', dns_cb)
  379. end
  380. */
  381. LUA_FUNCTION_DEF (task, get_resolver);
  382. /***
  383. * @method task:set_resolver(resolver)
  384. * Sets rspamd_resolver for a specified task.
  385. */
  386. LUA_FUNCTION_DEF (task, set_resolver);
  387. /***
  388. * @method task:inc_dns_req()
  389. * Increment number of DNS requests for the task. Is used just for logging purposes.
  390. */
  391. LUA_FUNCTION_DEF (task, inc_dns_req);
  392. /***
  393. * @method task:get_dns_req()
  394. * Get number of dns requests being sent in the task
  395. * @return {number} number of DNS requests
  396. */
  397. LUA_FUNCTION_DEF (task, get_dns_req);
  398. /***
  399. * @method task:has_recipients([type])
  400. * Return true if there are SMTP or MIME recipients for a task.
  401. * @param {integer|string} type if specified has the following meaning: `0` or `any` means try SMTP recipients and fallback to MIME if failed, `1` or `smtp` means checking merely SMTP recipients and `2` or `mime` means MIME recipients only
  402. * @return {bool} `true` if there are recipients of the following type
  403. */
  404. LUA_FUNCTION_DEF (task, has_recipients);
  405. /***
  406. * @method task:get_recipients([type])
  407. * Return SMTP or MIME recipients for a task. This function returns list of internet addresses each one is a table with the following structure:
  408. *
  409. * - `name` - name of internet address in UTF8, e.g. for `Vsevolod Stakhov <blah@foo.com>` it returns `Vsevolod Stakhov`
  410. * - `addr` - address part of the address
  411. * - `user` - user part (if present) of the address, e.g. `blah`
  412. * - `domain` - domain part (if present), e.g. `foo.com`
  413. * @param {integer|string} type if specified has the following meaning: `0` or `any` means try SMTP recipients and fallback to MIME if failed, `1` or `smtp` means checking merely SMTP recipients and `2` or `mime` means MIME recipients only
  414. * @return {list of addresses} list of recipients or `nil`
  415. */
  416. LUA_FUNCTION_DEF (task, get_recipients);
  417. /***
  418. * @method task:get_principal_recipient()
  419. * Returns a single string with so called `principal recipient` for a message. The order
  420. * of check is the following:
  421. *
  422. * - deliver-to request header
  423. * - the first recipient (envelope)
  424. * - the first recipient (mime)
  425. * @return {string} principal recipient
  426. */
  427. LUA_FUNCTION_DEF (task, get_principal_recipient);
  428. /***
  429. * @method task:get_reply_sender()
  430. * Returns a single string with address that should be used to reply on a message
  431. *
  432. * - reply-to header
  433. * - from header
  434. * - smtp from as a last resort
  435. * @return {address} email address
  436. */
  437. LUA_FUNCTION_DEF (task, get_reply_sender);
  438. /***
  439. * @method task:set_recipients([type], {rcpt1, rcpt2...})
  440. * Sets sender for a task. This function accepts table that will be converted to the address.
  441. * If some fields are missing they are subsequently reconstructed by this function. E.g. if you
  442. * specify 'user' and 'domain', then address and raw string will be reconstructed
  443. *
  444. * - `name` - name of internet address in UTF8, e.g. for `Vsevolod Stakhov <blah@foo.com>` it returns `Vsevolod Stakhov`
  445. * - `addr` - address part of the address
  446. * - `user` - user part (if present) of the address, e.g. `blah`
  447. * - `domain` - domain part (if present), e.g. `foo.com`
  448. * @param {integer|string} type if specified has the following meaning: `0` or `any` means try SMTP recipients and fallback to MIME if failed, `1` or `smtp` means checking merely SMTP recipients and `2` or `mime` means MIME recipients only
  449. * @param {list of tables} recipients recipients to set
  450. * @return {boolean} result of the operation
  451. */
  452. LUA_FUNCTION_DEF (task, set_recipients);
  453. /***
  454. * @method task:has_from([type])
  455. * Return true if there is SMTP or MIME sender for a task.
  456. * @param {integer|string} type if specified has the following meaning: `0` or `any` means try SMTP recipients and fallback to MIME if failed, `1` or `smtp` means checking merely SMTP recipients and `2` or `mime` means MIME recipients only
  457. * @return {bool} `true` if there is sender of the following type
  458. */
  459. LUA_FUNCTION_DEF (task, has_from);
  460. /***
  461. * @method task:get_from([type])
  462. * Return SMTP or MIME sender for a task. This function returns an internet address which one is a table with the following structure:
  463. *
  464. * - `name` - name of internet address in UTF8, e.g. for `Vsevolod Stakhov <blah@foo.com>` it returns `Vsevolod Stakhov`
  465. * - `addr` - address part of the address
  466. * - `user` - user part (if present) of the address, e.g. `blah`
  467. * - `domain` - domain part (if present), e.g. `foo.com`
  468. * @param {integer|string} type if specified has the following meaning: `0` or `any` means try SMTP sender and fallback to MIME if failed, `1` or `smtp` means checking merely SMTP sender and `2` or `mime` means MIME `From:` only
  469. * @return {address} sender or `nil`
  470. */
  471. LUA_FUNCTION_DEF (task, get_from);
  472. /***
  473. * @method task:set_from(type, addr)
  474. * Sets sender for a task. This function accepts table that will be converted to the address.
  475. * If some fields are missing they are subsequently reconstructed by this function. E.g. if you
  476. * specify 'user' and 'domain', then address and raw string will be reconstructed
  477. *
  478. * - `name` - name of internet address in UTF8, e.g. for `Vsevolod Stakhov <blah@foo.com>` it returns `Vsevolod Stakhov`
  479. * - `addr` - address part of the address
  480. * - `user` - user part (if present) of the address, e.g. `blah`
  481. * - `domain` - domain part (if present), e.g. `foo.com`
  482. * @param {integer|string} type if specified has the following meaning: `0` or `any` means try SMTP sender and fallback to MIME if failed, `1` or `smtp` means checking merely SMTP sender and `2` or `mime` means MIME `From:` only
  483. * @param {table
  484. * @return {boolean} success or not
  485. */
  486. LUA_FUNCTION_DEF (task, set_from);
  487. /***
  488. * @method task:get_user()
  489. * Returns authenticated user name for this task if specified by an MTA.
  490. * @return {string} username or nil
  491. */
  492. LUA_FUNCTION_DEF (task, get_user);
  493. /***
  494. * @method task:set_user([username])
  495. * Sets or resets (if username is not specified) authenticated user name for this task.
  496. * @return {string} the previously set username or nil
  497. */
  498. LUA_FUNCTION_DEF (task, set_user);
  499. /***
  500. * @method task:get_from_ip()
  501. * Returns [ip_addr](ip.md) object of a sender that is provided by MTA
  502. * @return {rspamd_ip} ip address object
  503. */
  504. LUA_FUNCTION_DEF (task, get_from_ip);
  505. /***
  506. * @method task:set_from_ip(str)
  507. * Set tasks's IP address based on the passed string
  508. * @param {string} str string representation of ip
  509. */
  510. LUA_FUNCTION_DEF (task, set_from_ip);
  511. LUA_FUNCTION_DEF (task, get_from_ip_num);
  512. /***
  513. * @method task:get_client_ip()
  514. * Returns [ip_addr](ip.md) object of a client connected to rspamd (normally, it is an IP address of MTA)
  515. * @return {rspamd_ip} ip address object
  516. */
  517. LUA_FUNCTION_DEF (task, get_client_ip);
  518. /***
  519. * @method task:get_helo()
  520. * Returns the value of SMTP helo provided by MTA.
  521. * @return {string} HELO value
  522. */
  523. LUA_FUNCTION_DEF (task, get_helo);
  524. LUA_FUNCTION_DEF (task, set_helo);
  525. /***
  526. * @method task:get_hostname()
  527. * Returns the value of sender's hostname provided by MTA
  528. * @return {string} hostname value
  529. */
  530. LUA_FUNCTION_DEF (task, get_hostname);
  531. LUA_FUNCTION_DEF (task, set_hostname);
  532. /***
  533. * @method task:get_images()
  534. * Returns list of all images found in a task as a table of `rspamd_image`.
  535. * Each image has the following methods:
  536. *
  537. * * `get_width` - return width of an image in pixels
  538. * * `get_height` - return height of an image in pixels
  539. * * `get_type` - return string representation of image's type (e.g. 'jpeg')
  540. * * `get_filename` - return string with image's file name
  541. * * `get_size` - return size in bytes
  542. * @return {list of rspamd_image} images found in a message
  543. */
  544. LUA_FUNCTION_DEF (task, get_images);
  545. /***
  546. * @method task:get_archives()
  547. * Returns list of all archives found in a task as a table of `rspamd_archive`.
  548. * Each archive has the following methods available:
  549. *
  550. * * `get_files` - return list of strings with filenames inside archive
  551. * * `get_files_full` - return list of tables with all information about files
  552. * * `is_encrypted` - return true if an archive is encrypted
  553. * * `get_type` - return string representation of image's type (e.g. 'zip')
  554. * * `get_filename` - return string with archive's file name
  555. * * `get_size` - return size in bytes
  556. * @return {list of rspamd_archive} archives found in a message
  557. */
  558. LUA_FUNCTION_DEF (task, get_archives);
  559. /***
  560. * @method task:get_dkim_results()
  561. * Returns list of all dkim check results as table of maps. Callee must ensure that
  562. * dkim checks have been completed by adding dependency on `DKIM_TRACE` symbol.
  563. * Fields in map:
  564. *
  565. * * `result` - string result of check:
  566. * - `reject`
  567. * - `allow`
  568. * - `tempfail`
  569. * - `permfail`
  570. * - `not found`
  571. * - `bad record`
  572. * * `domain` - dkim domain
  573. * * `selector` - dkim selector
  574. * * `bhash` - short version of b tag (8 base64 symbols)
  575. * * `fail_reason` - reason of failure (if applicable)
  576. * @return {list of maps} dkim check results
  577. */
  578. LUA_FUNCTION_DEF (task, get_dkim_results);
  579. /***
  580. * @method task:get_symbol(name)
  581. * Searches for a symbol `name` in all metrics results and returns a list of tables
  582. * one per metric that describes the symbol inserted. Please note that this function
  583. * is intended to return values for **inserted** symbols, so if this symbol was not
  584. * inserted it won't be in the function's output. This method is useful for post-filters mainly.
  585. * The symbols are returned as the list of the following tables:
  586. *
  587. * - `metric` - name of metric
  588. * - `score` - score of a symbol in that metric
  589. * - `options` - a table of strings representing options of a symbol
  590. * - `group` - a group of symbol (or 'ungrouped')
  591. * @param {string} name symbol's name
  592. * @return {list of tables} list of tables or nil if symbol was not found in any metric
  593. */
  594. LUA_FUNCTION_DEF (task, get_symbol);
  595. /***
  596. * @method task:get_symbols_all()
  597. * Returns array of symbols matched in default metric with all metadata
  598. * @return {table} table of tables formatted as in `task:get_symbol()` except that `metric` is absent and `name` is added
  599. */
  600. LUA_FUNCTION_DEF (task, get_symbols_all);
  601. /***
  602. * @method task:get_symbols()
  603. * Returns array of all symbols matched for this task
  604. * @return {table, table} table of strings with symbols names + table of theirs scores
  605. */
  606. LUA_FUNCTION_DEF (task, get_symbols);
  607. /***
  608. * @method task:get_symbols_numeric()
  609. * Returns array of all symbols matched for this task
  610. * @return {table|number, table|number} table of numbers with symbols ids + table of theirs scores
  611. */
  612. LUA_FUNCTION_DEF (task, get_symbols_numeric);
  613. /***
  614. * @method task:get_symbols_tokens()
  615. * Returns array of all symbols as statistical tokens
  616. * @return {table|number} table of numbers
  617. */
  618. LUA_FUNCTION_DEF (task, get_symbols_tokens);
  619. /***
  620. * @method task:has_symbol(name)
  621. * Fast path to check if a specified symbol is in the task's results
  622. * @param {string} name symbol's name
  623. * @return {boolean} `true` if symbol has been found
  624. */
  625. LUA_FUNCTION_DEF (task, has_symbol);
  626. /***
  627. * @method task:enable_symbol(name)
  628. * Enable specified symbol for this particular task
  629. * @param {string} name symbol's name
  630. * @return {boolean} `true` if symbol has been found
  631. */
  632. LUA_FUNCTION_DEF (task, enable_symbol);
  633. /***
  634. * @method task:disable_symbol(name)
  635. * Disable specified symbol for this particular task
  636. * @param {string} name symbol's name
  637. * @return {boolean} `true` if symbol has been found
  638. */
  639. LUA_FUNCTION_DEF (task, disable_symbol);
  640. /***
  641. * @method task:get_date(type[, gmt])
  642. * Returns timestamp for a connection or for a MIME message. This function can be called with a
  643. * single table arguments with the following fields:
  644. *
  645. * * `format` - a format of date returned:
  646. * - `message` - returns a mime date as integer (unix timestamp)
  647. * - `message_str` - returns a mime date as string (UTC format)
  648. * - `connect` - returns a unix timestamp of a connection to rspamd
  649. * - `connect_str` - returns connection time in UTC format
  650. * * `gmt` - returns date in `GMT` timezone (normal for unix timestamps)
  651. *
  652. * By default this function returns connection time in numeric format.
  653. * @param {string} type date format as described above
  654. * @param {boolean} gmt gmt flag as described above
  655. * @return {string/number} date representation according to format
  656. * @example
  657. rspamd_config.DATE_IN_PAST = function(task)
  658. local dm = task:get_date{format = 'message', gmt = true}
  659. local dt = task:get_date{format = 'connect', gmt = true}
  660. -- A day
  661. if dt - dm > 86400 then
  662. return true
  663. end
  664. return false
  665. end
  666. */
  667. LUA_FUNCTION_DEF (task, get_date);
  668. /***
  669. * @method task:get_message_id()
  670. * Returns message id of the specified task
  671. * @return {string} if of a message
  672. */
  673. LUA_FUNCTION_DEF (task, get_message_id);
  674. LUA_FUNCTION_DEF (task, get_timeval);
  675. /***
  676. * @method task:get_metric_result()
  677. * Get full result of a metric as a table:
  678. * - `score`: current score
  679. * - `action`: current action as a string
  680. * - `nnegative`: number of negative rules matched
  681. * - `npositive`: number of positive rules matched
  682. * - `positive_score`: total score for positive rules
  683. * - `negative_score`: total score for negative rules
  684. * - `passthrough`: set to true if message has a passthrough result
  685. * @return {table} metric result
  686. */
  687. LUA_FUNCTION_DEF (task, get_metric_result);
  688. /***
  689. * @method task:get_metric_score(name)
  690. * Get the current score of metric `name` (must be nil or 'default') . Should be used in idempotent filters only.
  691. * @param {string} name name of a metric
  692. * @return {number,number} 2 numbers containing the current score and required score of the metric
  693. */
  694. LUA_FUNCTION_DEF (task, get_metric_score);
  695. /***
  696. * @method task:get_metric_action(name)
  697. * Get the current action of metric `name` (must be nil or 'default'). Should be used in idempotent filters only.
  698. * @param {string} name name of a metric
  699. * @return {string} the current action of the metric as a string
  700. */
  701. LUA_FUNCTION_DEF (task, get_metric_action);
  702. /***
  703. * @method task:set_metric_score(name, score)
  704. * Set the current score of metric `name`. Should be used in post-filters only.
  705. * @param {string} name name of a metric
  706. * @param {number} score the current score of the metric
  707. */
  708. LUA_FUNCTION_DEF (task, set_metric_score);
  709. /***
  710. * @method task:set_metric_subject(subject)
  711. * Set the subject in the default metric
  712. * @param {string} subject subject to set
  713. */
  714. LUA_FUNCTION_DEF (task, set_metric_subject);
  715. /***
  716. * @method task:learn(is_spam[, classifier)
  717. * Learn classifier `classifier` with the task. If `is_spam` is true then message
  718. * is learnt as spam. Otherwise HAM is learnt. By default, this function learns
  719. * `bayes` classifier.
  720. * @param {boolean} is_spam learn spam or ham
  721. * @param {string} classifier classifier's name
  722. * @return {boolean} `true` if classifier has been learnt successfully
  723. */
  724. LUA_FUNCTION_DEF (task, learn);
  725. /***
  726. * @method task:set_settings(obj)
  727. * Set users settings object for a task. The format of this object is described
  728. * [here](https://rspamd.com/doc/configuration/settings.html).
  729. * @param {any} obj any lua object that corresponds to the settings format
  730. */
  731. LUA_FUNCTION_DEF (task, set_settings);
  732. /***
  733. * @method task:get_settings()
  734. * Gets users settings object for a task. The format of this object is described
  735. * [here](https://rspamd.com/doc/configuration/settings.html).
  736. * @return {lua object} lua object generated from UCL
  737. */
  738. LUA_FUNCTION_DEF (task, get_settings);
  739. /***
  740. * @method task:lookup_settings(key)
  741. * Gets users settings object with the specified key for a task.
  742. * @param {string} key key to lookup
  743. * @return {lua object} lua object generated from UCL
  744. */
  745. LUA_FUNCTION_DEF (task, lookup_settings);
  746. /***
  747. * @method task:get_settings_id()
  748. * Get numeric hash of settings id if specified for this task. 0 is returned otherwise.
  749. * @return {number} settings-id hash
  750. */
  751. LUA_FUNCTION_DEF (task, get_settings_id);
  752. /***
  753. * @method task:set_milter_reply(obj)
  754. * Set special reply for milter
  755. * @param {any} obj any lua object that corresponds to the settings format
  756. * @example
  757. task:set_milter_reply({
  758. add_headers = {['X-Lua'] = 'test'},
  759. -- 1 is the position of header to remove
  760. remove_headers = {['DKIM-Signature'] = 1},
  761. })
  762. */
  763. LUA_FUNCTION_DEF (task, set_milter_reply);
  764. /***
  765. * @method task:process_re(params)
  766. * Processes the specified regexp and returns number of captures (cached or new)
  767. * Params is the table with the following fields (mandatory fields are marked with `*`):
  768. * - `re`* : regular expression object
  769. * - `type`*: type of regular expression:
  770. * + `mime`: mime regexp
  771. * + `header`: header regexp
  772. * + `rawheader`: raw header expression
  773. * + `rawmime`: raw mime regexp
  774. * + `body`: raw body regexp
  775. * + `url`: url regexp
  776. * - `header`: for header and rawheader regexp means the name of header
  777. * - `strong`: case sensitive match for headers
  778. * @return {number} number of regexp occurrences in the task (limited by 255 so far)
  779. */
  780. LUA_FUNCTION_DEF (task, process_regexp);
  781. /***
  782. * @method task:cache_set(key, value)
  783. * Store some value to the task cache
  784. * @param {string} key key to use
  785. * @param {any} value any value (including functions and tables)
  786. */
  787. LUA_FUNCTION_DEF (task, cache_set);
  788. /***
  789. * @method task:cache_get(key)
  790. * Returns cached value or nil if nothing is cached
  791. * @param {string} key key to use
  792. * @return {any} cached value
  793. */
  794. LUA_FUNCTION_DEF (task, cache_get);
  795. /***
  796. * @method task:get_size()
  797. * Returns size of the task in bytes (that includes headers + parts size)
  798. * @return {number} size in bytes
  799. */
  800. LUA_FUNCTION_DEF (task, get_size);
  801. /***
  802. * @method task:set_flag(flag_name[, set])
  803. * Set specific flag for task:
  804. *
  805. * - `no_log`: do not log task summary
  806. * - `no_stat`: do not include task into scanned stats
  807. * - `pass_all`: check all filters for task
  808. * - `extended_urls`: output extended info about urls
  809. * - `skip`: skip task processing
  810. * - `learn_spam`: learn message as spam
  811. * - `learn_ham`: learn message as ham
  812. * - `broken_headers`: header data is broken for a message
  813. * @param {string} flag to set
  814. * @param {boolean} set set or clear flag (default is set)
  815. @example
  816. --[[
  817. For messages with undefined queue ID (scanned with rspamc or WebUI)
  818. do not include results into statistics and do not log task summary
  819. (it will not appear in the WebUI history as well).
  820. ]]--
  821. -- Callback function to set flags
  822. local function no_log_stat_cb(task)
  823. if not task:get_queue_id() then
  824. task:set_flag('no_log')
  825. task:set_flag('no_stat')
  826. end
  827. end
  828. rspamd_config:register_symbol({
  829. name = 'LOCAL_NO_LOG_STAT',
  830. type = 'postfilter',
  831. callback = no_log_stat_cb
  832. })
  833. */
  834. LUA_FUNCTION_DEF (task, set_flag);
  835. /***
  836. * @method task:has_flag(flag_name)
  837. * Checks for a specific flag in task:
  838. *
  839. * - `no_log`: do not log task summary
  840. * - `no_stat`: do not include task into scanned stats
  841. * - `pass_all`: check all filters for task
  842. * - `extended_urls`: output extended info about urls
  843. * - `skip`: skip task processing
  844. * - `learn_spam`: learn message as spam
  845. * - `learn_ham`: learn message as ham
  846. * - `broken_headers`: header data is broken for a message
  847. * @param {string} flag to check
  848. * @return {boolean} true if flags is set
  849. */
  850. LUA_FUNCTION_DEF (task, has_flag);
  851. /***
  852. * @method task:get_flags()
  853. * Get list of flags for task:
  854. *
  855. * - `no_log`: do not log task summary
  856. * - `no_stat`: do not include task into scanned stats
  857. * - `pass_all`: check all filters for task
  858. * - `extended_urls`: output extended info about urls
  859. * - `skip`: skip task processing
  860. * - `learn_spam`: learn message as spam
  861. * - `learn_ham`: learn message as ham
  862. * - `broken_headers`: header data is broken for a message
  863. * - `milter`: task is initiated by milter connection
  864. * @return {array of strings} table with all flags as strings
  865. */
  866. LUA_FUNCTION_DEF (task, get_flags);
  867. /***
  868. * @method task:get_digest()
  869. * Returns message's unique digest (32 hex symbols)
  870. * @return {string} hex digest
  871. */
  872. LUA_FUNCTION_DEF (task, get_digest);
  873. /***
  874. * @method task:store_in_file([mode|table])
  875. * If task was loaded using file scan, then this method just returns its name,
  876. * otherwise, a fresh temporary file is created and its name is returned. Default
  877. * mode is 0600. To convert lua number to the octal mode you can use the following
  878. * trick: `tonumber("0644", 8)`. The file is automatically removed when task is
  879. * destroyed.
  880. *
  881. * If table argument is specified, the following extra fields are allowed:
  882. *
  883. * - `mode`: same as mode argument
  884. * - `force_new`: always create a new file
  885. * - `filename`: use specific filename instead of a temporary one
  886. * - `tmpmask`: use specific tempmask, e.g. '/tmp/file-XXXXX', where XXXX will be replaced by some random letters
  887. * - `keep`: do not remove file after task is processed
  888. *
  889. * @param {number} mode mode for new file
  890. * @return {string} file name with task content
  891. */
  892. LUA_FUNCTION_DEF (task, store_in_file);
  893. /***
  894. * @method task:get_protocol_reply([flags])
  895. * This method being called from a **postfilter** will return reply for a message
  896. * as it is returned to a client. This method returns the Lua table corresponding
  897. * to the UCL object. Flags is a table that specify which information should be
  898. * there in a reply:
  899. *
  900. * - `basic`: basic info, such as message-id
  901. * - `metrics`: metrics and symbols
  902. * - `messages`: messages
  903. * - `dkim`: dkim signature
  904. * - `milter`: milter control block
  905. * - `extra`: extra data, such as profiling
  906. * - `urls`: list of all urls in a message
  907. *
  908. * @param {table} flags table of flags (default is all flags but `urls`)
  909. * @return {table} ucl object corresponding to the reply
  910. */
  911. LUA_FUNCTION_DEF (task, get_protocol_reply);
  912. /***
  913. * @method task:headers_foreach(callback, [params])
  914. * This method calls `callback` for each header that satisfies some condition.
  915. * By default, all headers are iterated unless `callback` returns `true`. Nil or
  916. * false means continue of iterations.
  917. * Params could be as following:
  918. *
  919. * - `full`: header value is full table of all attributes @see task:get_header_full for details
  920. * - `regexp`: return headers that satisfies the specified regexp
  921. * @param {function} callback function from header name and header value
  922. * @param {table} params optional parameters
  923. */
  924. LUA_FUNCTION_DEF (task, headers_foreach);
  925. /***
  926. * @method task:disable_action(action)
  927. * Disables some action for this task (e.g. 'greylist')
  928. *
  929. * @param {string} action action to disable
  930. * @return {boolean} true if an action was enabled and is disabled after the method call
  931. */
  932. LUA_FUNCTION_DEF (task, disable_action);
  933. /***
  934. * @method task:get_newlines_type()
  935. * Returns the most frequent newlines type met in a task
  936. *
  937. * @return {string} "cr" for \r, "lf" for \n, "crlf" for \r\n
  938. */
  939. LUA_FUNCTION_DEF (task, get_newlines_type);
  940. /***
  941. * @method task:get_stat_tokens()
  942. * Returns list of tables the statistical tokens:
  943. * - `data`: 64 bit number encoded as a string
  944. * - `t1`: the first token (if any)
  945. * - `t2`: the second token (if any)
  946. * - `win`: window index
  947. * - `flag`: table of strings:
  948. * - `text`: text token
  949. * - `meta`: meta token
  950. * - `lua`: lua meta token
  951. * - `exception`: exception
  952. * - `subject`: subject token
  953. * - `unigram`: unigram token
  954. *
  955. * @return {table of tables}
  956. */
  957. LUA_FUNCTION_DEF (task, get_stat_tokens);
  958. /***
  959. * @method task:lookup_words(map, function({o, n, s, f}) ... end)
  960. * Matches words in a task (including meta words) against some map (set, regexp and so on)
  961. * and call the specified function with a table containing 4 values:
  962. * - [1] - stemmed word
  963. * - [2] - normalised word
  964. * - [3] - raw word
  965. * - [4] - flags (table of strings)
  966. */
  967. LUA_FUNCTION_DEF (task, lookup_words);
  968. /**
  969. * @method task:topointer()
  970. *
  971. * Returns raw C pointer (lightuserdata) associated with task
  972. */
  973. LUA_FUNCTION_DEF (task, topointer);
  974. static const struct luaL_reg tasklib_f[] = {
  975. LUA_INTERFACE_DEF (task, create),
  976. LUA_INTERFACE_DEF (task, load_from_file),
  977. LUA_INTERFACE_DEF (task, load_from_string),
  978. {NULL, NULL}
  979. };
  980. static const struct luaL_reg tasklib_m[] = {
  981. LUA_INTERFACE_DEF (task, get_message),
  982. LUA_INTERFACE_DEF (task, destroy),
  983. LUA_INTERFACE_DEF (task, process_message),
  984. LUA_INTERFACE_DEF (task, set_cfg),
  985. LUA_INTERFACE_DEF (task, get_cfg),
  986. LUA_INTERFACE_DEF (task, get_mempool),
  987. LUA_INTERFACE_DEF (task, get_session),
  988. LUA_INTERFACE_DEF (task, set_session),
  989. LUA_INTERFACE_DEF (task, get_ev_base),
  990. LUA_INTERFACE_DEF (task, get_worker),
  991. LUA_INTERFACE_DEF (task, insert_result),
  992. LUA_INTERFACE_DEF (task, adjust_result),
  993. LUA_INTERFACE_DEF (task, set_pre_result),
  994. LUA_INTERFACE_DEF (task, has_pre_result),
  995. LUA_INTERFACE_DEF (task, append_message),
  996. LUA_INTERFACE_DEF (task, has_urls),
  997. LUA_INTERFACE_DEF (task, get_urls),
  998. LUA_INTERFACE_DEF (task, get_content),
  999. LUA_INTERFACE_DEF (task, get_filename),
  1000. LUA_INTERFACE_DEF (task, get_rawbody),
  1001. LUA_INTERFACE_DEF (task, get_emails),
  1002. LUA_INTERFACE_DEF (task, get_text_parts),
  1003. LUA_INTERFACE_DEF (task, get_parts),
  1004. LUA_INTERFACE_DEF (task, get_request_header),
  1005. LUA_INTERFACE_DEF (task, set_request_header),
  1006. LUA_INTERFACE_DEF (task, get_header),
  1007. LUA_INTERFACE_DEF (task, get_header_raw),
  1008. LUA_INTERFACE_DEF (task, get_header_full),
  1009. LUA_INTERFACE_DEF (task, get_header_count),
  1010. LUA_INTERFACE_DEF (task, get_raw_headers),
  1011. LUA_INTERFACE_DEF (task, get_received_headers),
  1012. LUA_INTERFACE_DEF (task, get_queue_id),
  1013. LUA_INTERFACE_DEF (task, get_uid),
  1014. LUA_INTERFACE_DEF (task, get_resolver),
  1015. LUA_INTERFACE_DEF (task, set_resolver),
  1016. LUA_INTERFACE_DEF (task, inc_dns_req),
  1017. LUA_INTERFACE_DEF (task, get_dns_req),
  1018. LUA_INTERFACE_DEF (task, has_recipients),
  1019. LUA_INTERFACE_DEF (task, get_recipients),
  1020. LUA_INTERFACE_DEF (task, set_recipients),
  1021. LUA_INTERFACE_DEF (task, get_principal_recipient),
  1022. LUA_INTERFACE_DEF (task, get_reply_sender),
  1023. LUA_INTERFACE_DEF (task, has_from),
  1024. LUA_INTERFACE_DEF (task, get_from),
  1025. LUA_INTERFACE_DEF (task, set_from),
  1026. LUA_INTERFACE_DEF (task, get_user),
  1027. LUA_INTERFACE_DEF (task, set_user),
  1028. {"get_addr", lua_task_get_from_ip},
  1029. {"get_ip", lua_task_get_from_ip},
  1030. {"get_from_addr", lua_task_get_from_ip},
  1031. LUA_INTERFACE_DEF (task, get_from_ip),
  1032. LUA_INTERFACE_DEF (task, set_from_ip),
  1033. LUA_INTERFACE_DEF (task, get_from_ip_num),
  1034. LUA_INTERFACE_DEF (task, get_client_ip),
  1035. LUA_INTERFACE_DEF (task, get_subject),
  1036. LUA_INTERFACE_DEF (task, get_helo),
  1037. LUA_INTERFACE_DEF (task, set_helo),
  1038. LUA_INTERFACE_DEF (task, get_hostname),
  1039. LUA_INTERFACE_DEF (task, set_hostname),
  1040. LUA_INTERFACE_DEF (task, get_images),
  1041. LUA_INTERFACE_DEF (task, get_archives),
  1042. LUA_INTERFACE_DEF (task, get_dkim_results),
  1043. LUA_INTERFACE_DEF (task, get_symbol),
  1044. LUA_INTERFACE_DEF (task, get_symbols),
  1045. LUA_INTERFACE_DEF (task, get_symbols_all),
  1046. LUA_INTERFACE_DEF (task, get_symbols_numeric),
  1047. LUA_INTERFACE_DEF (task, get_symbols_tokens),
  1048. LUA_INTERFACE_DEF (task, has_symbol),
  1049. LUA_INTERFACE_DEF (task, enable_symbol),
  1050. LUA_INTERFACE_DEF (task, disable_symbol),
  1051. LUA_INTERFACE_DEF (task, get_date),
  1052. LUA_INTERFACE_DEF (task, get_message_id),
  1053. LUA_INTERFACE_DEF (task, get_timeval),
  1054. LUA_INTERFACE_DEF (task, get_metric_result),
  1055. LUA_INTERFACE_DEF (task, get_metric_score),
  1056. LUA_INTERFACE_DEF (task, get_metric_action),
  1057. LUA_INTERFACE_DEF (task, set_metric_score),
  1058. LUA_INTERFACE_DEF (task, set_metric_subject),
  1059. LUA_INTERFACE_DEF (task, learn),
  1060. LUA_INTERFACE_DEF (task, set_settings),
  1061. LUA_INTERFACE_DEF (task, get_settings),
  1062. LUA_INTERFACE_DEF (task, lookup_settings),
  1063. LUA_INTERFACE_DEF (task, get_settings_id),
  1064. LUA_INTERFACE_DEF (task, cache_get),
  1065. LUA_INTERFACE_DEF (task, cache_set),
  1066. LUA_INTERFACE_DEF (task, process_regexp),
  1067. LUA_INTERFACE_DEF (task, get_size),
  1068. LUA_INTERFACE_DEF (task, set_flag),
  1069. LUA_INTERFACE_DEF (task, get_flags),
  1070. LUA_INTERFACE_DEF (task, has_flag),
  1071. {"set_rmilter_reply", lua_task_set_milter_reply},
  1072. LUA_INTERFACE_DEF (task, set_milter_reply),
  1073. LUA_INTERFACE_DEF (task, get_digest),
  1074. LUA_INTERFACE_DEF (task, store_in_file),
  1075. LUA_INTERFACE_DEF (task, get_protocol_reply),
  1076. LUA_INTERFACE_DEF (task, headers_foreach),
  1077. LUA_INTERFACE_DEF (task, disable_action),
  1078. LUA_INTERFACE_DEF (task, get_newlines_type),
  1079. LUA_INTERFACE_DEF (task, get_stat_tokens),
  1080. LUA_INTERFACE_DEF (task, get_meta_words),
  1081. LUA_INTERFACE_DEF (task, lookup_words),
  1082. LUA_INTERFACE_DEF (task, topointer),
  1083. {"__tostring", rspamd_lua_class_tostring},
  1084. {NULL, NULL}
  1085. };
  1086. /* Image methods */
  1087. LUA_FUNCTION_DEF (image, get_width);
  1088. LUA_FUNCTION_DEF (image, get_height);
  1089. LUA_FUNCTION_DEF (image, get_type);
  1090. LUA_FUNCTION_DEF (image, get_filename);
  1091. LUA_FUNCTION_DEF (image, get_size);
  1092. static const struct luaL_reg imagelib_m[] = {
  1093. LUA_INTERFACE_DEF (image, get_width),
  1094. LUA_INTERFACE_DEF (image, get_height),
  1095. LUA_INTERFACE_DEF (image, get_type),
  1096. LUA_INTERFACE_DEF (image, get_filename),
  1097. LUA_INTERFACE_DEF (image, get_size),
  1098. {"__tostring", rspamd_lua_class_tostring},
  1099. {NULL, NULL}
  1100. };
  1101. /* Archive methods */
  1102. LUA_FUNCTION_DEF (archive, get_type);
  1103. LUA_FUNCTION_DEF (archive, get_files);
  1104. LUA_FUNCTION_DEF (archive, get_files_full);
  1105. LUA_FUNCTION_DEF (archive, is_encrypted);
  1106. LUA_FUNCTION_DEF (archive, get_filename);
  1107. LUA_FUNCTION_DEF (archive, get_size);
  1108. static const struct luaL_reg archivelib_m[] = {
  1109. LUA_INTERFACE_DEF (archive, get_type),
  1110. LUA_INTERFACE_DEF (archive, get_files),
  1111. LUA_INTERFACE_DEF (archive, get_files_full),
  1112. LUA_INTERFACE_DEF (archive, is_encrypted),
  1113. LUA_INTERFACE_DEF (archive, get_filename),
  1114. LUA_INTERFACE_DEF (archive, get_size),
  1115. {"__tostring", rspamd_lua_class_tostring},
  1116. {NULL, NULL}
  1117. };
  1118. /* Blob methods */
  1119. LUA_FUNCTION_DEF (text, fromstring);
  1120. LUA_FUNCTION_DEF (text, fromtable);
  1121. LUA_FUNCTION_DEF (text, len);
  1122. LUA_FUNCTION_DEF (text, str);
  1123. LUA_FUNCTION_DEF (text, ptr);
  1124. LUA_FUNCTION_DEF (text, save_in_file);
  1125. LUA_FUNCTION_DEF (text, take_ownership);
  1126. LUA_FUNCTION_DEF (text, gc);
  1127. static const struct luaL_reg textlib_f[] = {
  1128. LUA_INTERFACE_DEF (text, fromstring),
  1129. LUA_INTERFACE_DEF (text, fromtable),
  1130. {NULL, NULL}
  1131. };
  1132. static const struct luaL_reg textlib_m[] = {
  1133. LUA_INTERFACE_DEF (text, len),
  1134. LUA_INTERFACE_DEF (text, str),
  1135. LUA_INTERFACE_DEF (text, ptr),
  1136. LUA_INTERFACE_DEF (text, take_ownership),
  1137. LUA_INTERFACE_DEF (text, save_in_file),
  1138. {"write", lua_text_save_in_file},
  1139. {"__len", lua_text_len},
  1140. {"__tostring", lua_text_str},
  1141. {"__gc", lua_text_gc},
  1142. {NULL, NULL}
  1143. };
  1144. /* Utility functions */
  1145. struct rspamd_task *
  1146. lua_check_task (lua_State * L, gint pos)
  1147. {
  1148. void *ud = rspamd_lua_check_udata (L, pos, "rspamd{task}");
  1149. luaL_argcheck (L, ud != NULL, pos, "'task' expected");
  1150. return ud ? *((struct rspamd_task **)ud) : NULL;
  1151. }
  1152. struct rspamd_task *
  1153. lua_check_task_maybe (lua_State * L, gint pos)
  1154. {
  1155. void *ud = rspamd_lua_check_udata_maybe (L, pos, "rspamd{task}");
  1156. return ud ? *((struct rspamd_task **)ud) : NULL;
  1157. }
  1158. static struct rspamd_image *
  1159. lua_check_image (lua_State * L)
  1160. {
  1161. void *ud = rspamd_lua_check_udata (L, 1, "rspamd{image}");
  1162. luaL_argcheck (L, ud != NULL, 1, "'image' expected");
  1163. return ud ? *((struct rspamd_image **)ud) : NULL;
  1164. }
  1165. static struct rspamd_archive *
  1166. lua_check_archive (lua_State * L)
  1167. {
  1168. void *ud = rspamd_lua_check_udata (L, 1, "rspamd{archive}");
  1169. luaL_argcheck (L, ud != NULL, 1, "'archive' expected");
  1170. return ud ? *((struct rspamd_archive **)ud) : NULL;
  1171. }
  1172. struct rspamd_lua_text *
  1173. lua_check_text (lua_State * L, gint pos)
  1174. {
  1175. void *ud = rspamd_lua_check_udata (L, pos, "rspamd{text}");
  1176. luaL_argcheck (L, ud != NULL, pos, "'text' expected");
  1177. return ud ? (struct rspamd_lua_text *)ud : NULL;
  1178. }
  1179. static void
  1180. lua_task_set_cached (lua_State *L, struct rspamd_task *task, const gchar *key,
  1181. gint pos, guint id)
  1182. {
  1183. LUA_TRACE_POINT;
  1184. struct rspamd_lua_cached_entry *entry;
  1185. lua_pushvalue (L, pos);
  1186. entry = g_hash_table_lookup (task->lua_cache, key);
  1187. if (G_UNLIKELY (entry != NULL)) {
  1188. /* Unref previous value */
  1189. luaL_unref (L, LUA_REGISTRYINDEX, entry->ref);
  1190. }
  1191. else {
  1192. entry = rspamd_mempool_alloc (task->task_pool, sizeof (*entry));
  1193. g_hash_table_insert (task->lua_cache,
  1194. rspamd_mempool_strdup (task->task_pool, key), entry);
  1195. }
  1196. entry->ref = luaL_ref (L, LUA_REGISTRYINDEX);
  1197. entry->id = id;
  1198. }
  1199. static gboolean
  1200. lua_task_get_cached (lua_State *L, struct rspamd_task *task, const gchar *key,
  1201. guint id)
  1202. {
  1203. LUA_TRACE_POINT;
  1204. struct rspamd_lua_cached_entry *entry;
  1205. entry = g_hash_table_lookup (task->lua_cache, key);
  1206. if (entry != NULL && entry->id == id) {
  1207. lua_rawgeti (L, LUA_REGISTRYINDEX, entry->ref);
  1208. return TRUE;
  1209. }
  1210. return FALSE;
  1211. }
  1212. /* Task methods */
  1213. static int
  1214. lua_task_process_message (lua_State *L)
  1215. {
  1216. LUA_TRACE_POINT;
  1217. struct rspamd_task *task = lua_check_task (L, 1);
  1218. if (task != NULL) {
  1219. if (task->msg.len > 0) {
  1220. if (rspamd_message_parse (task)) {
  1221. lua_pushboolean (L, TRUE);
  1222. rspamd_message_process (task);
  1223. }
  1224. else {
  1225. lua_pushboolean (L, FALSE);
  1226. }
  1227. }
  1228. else {
  1229. lua_pushnil (L);
  1230. }
  1231. }
  1232. else {
  1233. return luaL_error (L, "invalid arguments");
  1234. }
  1235. return 1;
  1236. }
  1237. static int
  1238. lua_task_get_cfg (lua_State *L)
  1239. {
  1240. LUA_TRACE_POINT;
  1241. struct rspamd_task *task = lua_check_task (L, 1);
  1242. struct rspamd_config **pcfg;
  1243. if (task) {
  1244. pcfg = lua_newuserdata (L, sizeof (gpointer));
  1245. rspamd_lua_setclass (L, "rspamd{config}", -1);
  1246. *pcfg = task->cfg;
  1247. }
  1248. else {
  1249. return luaL_error (L, "invalid arguments");
  1250. }
  1251. return 1;
  1252. }
  1253. static int
  1254. lua_task_set_cfg (lua_State *L)
  1255. {
  1256. LUA_TRACE_POINT;
  1257. struct rspamd_task *task = lua_check_task (L, 1);
  1258. void *ud = rspamd_lua_check_udata (L, 2, "rspamd{config}");
  1259. if (task) {
  1260. luaL_argcheck (L, ud != NULL, 1, "'config' expected");
  1261. task->cfg = ud ? *((struct rspamd_config **)ud) : NULL;
  1262. }
  1263. else {
  1264. return luaL_error (L, "invalid arguments");
  1265. }
  1266. return 0;
  1267. }
  1268. static int
  1269. lua_task_destroy (lua_State *L)
  1270. {
  1271. LUA_TRACE_POINT;
  1272. struct rspamd_task *task = lua_check_task (L, 1);
  1273. if (task != NULL) {
  1274. rspamd_task_free (task);
  1275. }
  1276. return 0;
  1277. }
  1278. static int
  1279. lua_task_get_message (lua_State * L)
  1280. {
  1281. LUA_TRACE_POINT;
  1282. return luaL_error (L, "task:get_message is no longer supported");
  1283. }
  1284. static void
  1285. lua_task_unmap_dtor (gpointer p)
  1286. {
  1287. struct rspamd_task *task = (struct rspamd_task *)p;
  1288. if (task->msg.begin) {
  1289. munmap ((gpointer)task->msg.begin, task->msg.len);
  1290. }
  1291. }
  1292. static void
  1293. lua_task_free_dtor (gpointer p)
  1294. {
  1295. struct rspamd_task *task = (struct rspamd_task *)p;
  1296. if (task->msg.begin) {
  1297. g_free ((gpointer)task->msg.begin);
  1298. }
  1299. }
  1300. static gint
  1301. lua_task_load_from_file (lua_State * L)
  1302. {
  1303. LUA_TRACE_POINT;
  1304. struct rspamd_task *task = NULL, **ptask;
  1305. const gchar *fname = luaL_checkstring (L, 1), *err = NULL;
  1306. struct rspamd_config *cfg = NULL;
  1307. gboolean res = FALSE;
  1308. gpointer map;
  1309. gsize sz;
  1310. if (fname) {
  1311. if (lua_type (L, 2) == LUA_TUSERDATA) {
  1312. gpointer p;
  1313. p = rspamd_lua_check_udata_maybe (L, 2, "rspamd{config}");
  1314. if (p) {
  1315. cfg = *(struct rspamd_config **)p;
  1316. }
  1317. }
  1318. if (strcmp (fname, "-") == 0) {
  1319. /* Read from stdin */
  1320. gint fd = STDIN_FILENO;
  1321. GString *data = g_string_sized_new (BUFSIZ);
  1322. gchar buf[BUFSIZ];
  1323. gssize r;
  1324. for (;;) {
  1325. r = read (fd, buf, sizeof (buf));
  1326. if (r == -1) {
  1327. err = strerror (errno);
  1328. break;
  1329. }
  1330. else if (r == 0) {
  1331. break;
  1332. }
  1333. else {
  1334. g_string_append_len (data, buf, r);
  1335. }
  1336. }
  1337. task = rspamd_task_new (NULL, cfg, NULL, NULL, NULL);
  1338. task->msg.begin = data->str;
  1339. task->msg.len = data->len;
  1340. rspamd_mempool_add_destructor (task->task_pool,
  1341. lua_task_free_dtor, task);
  1342. res = TRUE;
  1343. g_string_free (data, FALSE); /* Buffer is still valid */
  1344. }
  1345. else {
  1346. map = rspamd_file_xmap (fname, PROT_READ, &sz, TRUE);
  1347. if (!map) {
  1348. err = strerror (errno);
  1349. } else {
  1350. task = rspamd_task_new (NULL, cfg, NULL, NULL, NULL);
  1351. task->msg.begin = map;
  1352. task->msg.len = sz;
  1353. rspamd_mempool_add_destructor (task->task_pool,
  1354. lua_task_unmap_dtor, task);
  1355. res = TRUE;
  1356. }
  1357. }
  1358. }
  1359. else {
  1360. return luaL_error (L, "invalid arguments");
  1361. }
  1362. lua_pushboolean (L, res);
  1363. if (res) {
  1364. ptask = lua_newuserdata (L, sizeof (*ptask));
  1365. *ptask = task;
  1366. rspamd_lua_setclass (L, "rspamd{task}", -1);
  1367. }
  1368. else {
  1369. if (err) {
  1370. lua_pushstring (L, err);
  1371. }
  1372. else {
  1373. lua_pushnil (L);
  1374. }
  1375. }
  1376. return 2;
  1377. }
  1378. static gint
  1379. lua_task_load_from_string (lua_State * L)
  1380. {
  1381. LUA_TRACE_POINT;
  1382. struct rspamd_task *task = NULL, **ptask;
  1383. const gchar *str_message;
  1384. gsize message_len;
  1385. struct rspamd_config *cfg = NULL;
  1386. str_message = luaL_checklstring (L, 1, &message_len);
  1387. if (str_message) {
  1388. if (lua_type (L, 2) == LUA_TUSERDATA) {
  1389. gpointer p;
  1390. p = rspamd_lua_check_udata_maybe (L, 2, "rspamd{config}");
  1391. if (p) {
  1392. cfg = *(struct rspamd_config **)p;
  1393. }
  1394. }
  1395. task = rspamd_task_new (NULL, cfg, NULL, NULL, NULL);
  1396. task->msg.begin = g_strdup (str_message);
  1397. task->msg.len = message_len;
  1398. rspamd_mempool_add_destructor (task->task_pool, lua_task_free_dtor, task);
  1399. }
  1400. else {
  1401. return luaL_error (L, "invalid arguments");
  1402. }
  1403. lua_pushboolean (L, true);
  1404. ptask = lua_newuserdata (L, sizeof (*ptask));
  1405. *ptask = task;
  1406. rspamd_lua_setclass (L, "rspamd{task}", -1);
  1407. return 2;
  1408. }
  1409. static gint
  1410. lua_task_create (lua_State * L)
  1411. {
  1412. LUA_TRACE_POINT;
  1413. struct rspamd_task *task = NULL, **ptask;
  1414. struct rspamd_config *cfg = NULL;
  1415. struct event_base *ev_base = NULL;
  1416. if (lua_type (L, 1) == LUA_TUSERDATA) {
  1417. gpointer p;
  1418. p = rspamd_lua_check_udata_maybe (L, 2, "rspamd{config}");
  1419. if (p) {
  1420. cfg = *(struct rspamd_config **)p;
  1421. }
  1422. }
  1423. if (lua_type (L, 2) == LUA_TUSERDATA) {
  1424. gpointer p;
  1425. p = rspamd_lua_check_udata_maybe (L, 2, "rspamd{ev_base}");
  1426. if (p) {
  1427. ev_base = *(struct event_base **)p;
  1428. }
  1429. }
  1430. task = rspamd_task_new (NULL, cfg, NULL, NULL, ev_base);
  1431. task->flags |= RSPAMD_TASK_FLAG_EMPTY;
  1432. ptask = lua_newuserdata (L, sizeof (*ptask));
  1433. *ptask = task;
  1434. rspamd_lua_setclass (L, "rspamd{task}", -1);
  1435. return 1;
  1436. }
  1437. static int
  1438. lua_task_get_mempool (lua_State * L)
  1439. {
  1440. LUA_TRACE_POINT;
  1441. rspamd_mempool_t **ppool;
  1442. struct rspamd_task *task = lua_check_task (L, 1);
  1443. if (task != NULL) {
  1444. ppool = lua_newuserdata (L, sizeof (rspamd_mempool_t *));
  1445. rspamd_lua_setclass (L, "rspamd{mempool}", -1);
  1446. *ppool = task->task_pool;
  1447. }
  1448. else {
  1449. return luaL_error (L, "invalid arguments");
  1450. }
  1451. return 1;
  1452. }
  1453. static int
  1454. lua_task_get_session (lua_State * L)
  1455. {
  1456. LUA_TRACE_POINT;
  1457. struct rspamd_async_session **psession;
  1458. struct rspamd_task *task = lua_check_task (L, 1);
  1459. if (task != NULL) {
  1460. psession = lua_newuserdata (L, sizeof (void *));
  1461. rspamd_lua_setclass (L, "rspamd{session}", -1);
  1462. *psession = task->s;
  1463. }
  1464. else {
  1465. return luaL_error (L, "invalid arguments");
  1466. }
  1467. return 1;
  1468. }
  1469. static int
  1470. lua_task_set_session (lua_State * L)
  1471. {
  1472. LUA_TRACE_POINT;
  1473. struct rspamd_async_session *session = lua_check_session (L, 2);
  1474. struct rspamd_task *task = lua_check_task (L, 1);
  1475. if (task != NULL && session != NULL) {
  1476. task->s = session;
  1477. }
  1478. else {
  1479. return luaL_error (L, "invalid arguments");
  1480. }
  1481. return 1;
  1482. }
  1483. static int
  1484. lua_task_get_ev_base (lua_State * L)
  1485. {
  1486. LUA_TRACE_POINT;
  1487. struct event_base **pbase;
  1488. struct rspamd_task *task = lua_check_task (L, 1);
  1489. if (task != NULL) {
  1490. pbase = lua_newuserdata (L, sizeof (struct event_base *));
  1491. rspamd_lua_setclass (L, "rspamd{ev_base}", -1);
  1492. *pbase = task->ev_base;
  1493. }
  1494. else {
  1495. return luaL_error (L, "invalid arguments");
  1496. }
  1497. return 1;
  1498. }
  1499. static int
  1500. lua_task_get_worker (lua_State * L)
  1501. {
  1502. LUA_TRACE_POINT;
  1503. struct rspamd_worker **pworker;
  1504. struct rspamd_task *task = lua_check_task (L, 1);
  1505. if (task != NULL) {
  1506. if (task->worker) {
  1507. pworker = lua_newuserdata (L, sizeof (struct rspamd_worker *));
  1508. rspamd_lua_setclass (L, "rspamd{worker}", -1);
  1509. *pworker = task->worker;
  1510. }
  1511. else {
  1512. lua_pushnil (L);
  1513. }
  1514. }
  1515. else {
  1516. return luaL_error (L, "invalid arguments");
  1517. }
  1518. return 1;
  1519. }
  1520. static gint
  1521. lua_task_insert_result (lua_State * L)
  1522. {
  1523. LUA_TRACE_POINT;
  1524. struct rspamd_task *task = lua_check_task (L, 1);
  1525. const gchar *symbol_name, *param;
  1526. double weight;
  1527. struct rspamd_symbol_result *s;
  1528. enum rspamd_symbol_insert_flags flags = RSPAMD_SYMBOL_INSERT_DEFAULT;
  1529. gint i, top, args_start;
  1530. if (task != NULL) {
  1531. if (lua_isboolean (L, 2)) {
  1532. args_start = 3;
  1533. if (lua_toboolean (L, 2)) {
  1534. flags |= RSPAMD_SYMBOL_INSERT_ENFORCE;
  1535. }
  1536. }
  1537. else {
  1538. args_start = 2;
  1539. }
  1540. symbol_name = rspamd_mempool_strdup (task->task_pool,
  1541. luaL_checkstring (L, args_start));
  1542. weight = luaL_checknumber (L, args_start + 1);
  1543. top = lua_gettop (L);
  1544. s = rspamd_task_insert_result_full (task, symbol_name, weight, NULL, flags);
  1545. /* Get additional options */
  1546. if (s) {
  1547. for (i = args_start + 2; i <= top; i++) {
  1548. if (lua_type (L, i) == LUA_TSTRING) {
  1549. param = luaL_checkstring (L, i);
  1550. rspamd_task_add_result_option (task, s, param);
  1551. }
  1552. else if (lua_type (L, i) == LUA_TTABLE) {
  1553. lua_pushvalue (L, i);
  1554. lua_pushnil (L);
  1555. while (lua_next (L, -2)) {
  1556. param = lua_tostring (L, -1);
  1557. rspamd_task_add_result_option (task, s, param);
  1558. lua_pop (L, 1);
  1559. }
  1560. lua_pop (L, 1);
  1561. }
  1562. }
  1563. }
  1564. }
  1565. else {
  1566. return luaL_error (L, "invalid arguments");
  1567. }
  1568. return 0;
  1569. }
  1570. static gint
  1571. lua_task_adjust_result (lua_State * L)
  1572. {
  1573. LUA_TRACE_POINT;
  1574. struct rspamd_task *task = lua_check_task (L, 1);
  1575. const gchar *symbol_name, *param;
  1576. struct rspamd_metric_result *metric_res;
  1577. struct rspamd_symbol_result *s = NULL;
  1578. double weight;
  1579. gint i, top;
  1580. if (task != NULL) {
  1581. symbol_name = luaL_checkstring (L, 2);
  1582. weight = luaL_checknumber (L, 3);
  1583. top = lua_gettop (L);
  1584. metric_res = task->result;
  1585. if (metric_res) {
  1586. s = rspamd_task_find_symbol_result (task, symbol_name);
  1587. }
  1588. else {
  1589. return luaL_error (L, "no metric result");
  1590. }
  1591. if (s) {
  1592. metric_res->score -= s->score;
  1593. s->score = weight;
  1594. metric_res->score += s->score;
  1595. }
  1596. else {
  1597. return luaL_error (L, "symbol not found: %s", symbol_name);
  1598. }
  1599. /* Get additional options */
  1600. if (s) {
  1601. for (i = 4; i <= top; i++) {
  1602. if (lua_type (L, i) == LUA_TSTRING) {
  1603. param = luaL_checkstring (L, i);
  1604. rspamd_task_add_result_option (task, s, param);
  1605. }
  1606. else if (lua_type (L, i) == LUA_TTABLE) {
  1607. lua_pushvalue (L, i);
  1608. lua_pushnil (L);
  1609. while (lua_next (L, -2)) {
  1610. param = lua_tostring (L, -1);
  1611. rspamd_task_add_result_option (task, s, param);
  1612. lua_pop (L, 1);
  1613. }
  1614. lua_pop (L, 1);
  1615. }
  1616. }
  1617. }
  1618. }
  1619. else {
  1620. return luaL_error (L, "invalid arguments");
  1621. }
  1622. return 0;
  1623. }
  1624. static gint
  1625. lua_task_set_pre_result (lua_State * L)
  1626. {
  1627. LUA_TRACE_POINT;
  1628. struct rspamd_task *task = lua_check_task (L, 1);
  1629. const gchar *message = NULL, *module = NULL;
  1630. gdouble score = NAN;
  1631. struct rspamd_action *action;
  1632. guint priority = RSPAMD_PASSTHROUGH_NORMAL;
  1633. if (task != NULL) {
  1634. if (RSPAMD_TASK_IS_SKIPPED (task)) {
  1635. /* Do not set pre-result for a skipped task */
  1636. return 0;
  1637. }
  1638. if (lua_type (L, 2) == LUA_TSTRING) {
  1639. const gchar *act_name = lua_tostring (L, 2);
  1640. gint internal_type;
  1641. if (strcmp (act_name, "accept") == 0) {
  1642. /* Compatibility! */
  1643. act_name = "no action";
  1644. }
  1645. else if (rspamd_action_from_str (act_name, &internal_type)) {
  1646. /* Compatibility! */
  1647. act_name = rspamd_action_to_str (internal_type);
  1648. }
  1649. action = rspamd_config_get_action (task->cfg, act_name);
  1650. }
  1651. else {
  1652. return luaL_error (L, "invalid arguments");
  1653. }
  1654. if (action == NULL) {
  1655. struct rspamd_action *tmp;
  1656. HASH_ITER (hh, task->cfg->actions, action, tmp) {
  1657. msg_err_task ("known defined action: %s = %f",
  1658. action->name, action->threshold);
  1659. }
  1660. return luaL_error (L, "unknown action %s", lua_tostring (L, 2));
  1661. }
  1662. if (lua_type (L, 3) == LUA_TSTRING) {
  1663. message = lua_tostring (L, 3);
  1664. /* Keep compatibility here :( */
  1665. ucl_object_replace_key (task->messages,
  1666. ucl_object_fromstring_common (message, 0, UCL_STRING_RAW),
  1667. "smtp_message", 0,
  1668. false);
  1669. }
  1670. else {
  1671. message = "unknown reason";
  1672. }
  1673. if (lua_type (L, 4) == LUA_TSTRING) {
  1674. module = lua_tostring (L, 4);
  1675. }
  1676. else {
  1677. module = "Unknown lua";
  1678. }
  1679. if (lua_type (L, 5) == LUA_TNUMBER) {
  1680. score = lua_tonumber (L, 5);
  1681. }
  1682. if (lua_type (L, 6) == LUA_TNUMBER) {
  1683. priority = lua_tonumber (L, 6);
  1684. }
  1685. rspamd_add_passthrough_result (task, action, priority,
  1686. score, rspamd_mempool_strdup (task->task_pool, message),
  1687. rspamd_mempool_strdup (task->task_pool, module));
  1688. /* Don't classify or filter message if pre-filter sets results */
  1689. task->processed_stages |= (RSPAMD_TASK_STAGE_CLASSIFIERS |
  1690. RSPAMD_TASK_STAGE_CLASSIFIERS_PRE |
  1691. RSPAMD_TASK_STAGE_CLASSIFIERS_POST);
  1692. rspamd_symcache_disable_all_symbols (task, task->cfg->cache,
  1693. SYMBOL_TYPE_IDEMPOTENT|SYMBOL_TYPE_IGNORE_PASSTHROUGH|
  1694. SYMBOL_TYPE_POSTFILTER);
  1695. }
  1696. else {
  1697. return luaL_error (L, "invalid arguments");
  1698. }
  1699. return 0;
  1700. }
  1701. static gint
  1702. lua_task_has_pre_result (lua_State * L)
  1703. {
  1704. LUA_TRACE_POINT;
  1705. struct rspamd_task *task = lua_check_task (L, 1);
  1706. if (task) {
  1707. lua_pushboolean (L, task->result->passthrough_result != NULL);
  1708. }
  1709. else {
  1710. return luaL_error (L, "invalid arguments");
  1711. }
  1712. return 1;
  1713. }
  1714. static gint
  1715. lua_task_append_message (lua_State * L)
  1716. {
  1717. LUA_TRACE_POINT;
  1718. struct rspamd_task *task = lua_check_task (L, 1);
  1719. const gchar *message = luaL_checkstring (L, 2), *category;
  1720. if (task != NULL) {
  1721. if (lua_type (L, 3) == LUA_TSTRING) {
  1722. category = luaL_checkstring (L, 3);
  1723. }
  1724. else {
  1725. category = "unknown";
  1726. }
  1727. ucl_object_insert_key (task->messages,
  1728. ucl_object_fromstring_common (message, 0, UCL_STRING_RAW),
  1729. category, 0,
  1730. true);
  1731. }
  1732. else {
  1733. return luaL_error (L, "invalid arguments");
  1734. }
  1735. return 0;
  1736. }
  1737. struct lua_tree_cb_data {
  1738. lua_State *L;
  1739. int i;
  1740. gint mask;
  1741. };
  1742. static void
  1743. lua_tree_url_callback (gpointer key, gpointer value, gpointer ud)
  1744. {
  1745. struct rspamd_lua_url *lua_url;
  1746. struct rspamd_url *url = (struct rspamd_url *)value;
  1747. struct lua_tree_cb_data *cb = ud;
  1748. if (url->protocol & cb->mask) {
  1749. lua_url = lua_newuserdata (cb->L, sizeof (struct rspamd_lua_url));
  1750. rspamd_lua_setclass (cb->L, "rspamd{url}", -1);
  1751. lua_url->url = url;
  1752. lua_rawseti (cb->L, -2, cb->i++);
  1753. }
  1754. }
  1755. static gint
  1756. lua_task_get_urls (lua_State * L)
  1757. {
  1758. LUA_TRACE_POINT;
  1759. struct rspamd_task *task = lua_check_task (L, 1);
  1760. struct lua_tree_cb_data cb;
  1761. gint protocols_mask = 0;
  1762. static const gint default_mask = PROTOCOL_HTTP|PROTOCOL_HTTPS|
  1763. PROTOCOL_FILE|PROTOCOL_FTP;
  1764. gsize sz;
  1765. if (task) {
  1766. if (lua_gettop (L) >= 2) {
  1767. if (lua_type (L, 2) == LUA_TBOOLEAN) {
  1768. protocols_mask = default_mask;
  1769. if (lua_toboolean (L, 2)) {
  1770. protocols_mask |= PROTOCOL_MAILTO;
  1771. }
  1772. }
  1773. else if (lua_type (L, 2) == LUA_TTABLE) {
  1774. for (lua_pushnil (L); lua_next (L, 2); lua_pop (L, 1)) {
  1775. int nmask;
  1776. const gchar *pname = lua_tostring (L, -1);
  1777. nmask = rspamd_url_protocol_from_string (pname);
  1778. if (nmask != PROTOCOL_UNKNOWN) {
  1779. protocols_mask |= nmask;
  1780. }
  1781. else {
  1782. msg_info ("bad url protocol: %s", pname);
  1783. }
  1784. }
  1785. }
  1786. else if (lua_type (L, 2) == LUA_TSTRING) {
  1787. const gchar *plist = lua_tostring (L, 2);
  1788. gchar **strvec;
  1789. gchar * const *cvec;
  1790. strvec = g_strsplit_set (plist, ",;", -1);
  1791. cvec = strvec;
  1792. while (*cvec) {
  1793. int nmask;
  1794. nmask = rspamd_url_protocol_from_string (*cvec);
  1795. if (nmask != PROTOCOL_UNKNOWN) {
  1796. protocols_mask |= nmask;
  1797. }
  1798. else {
  1799. msg_info ("bad url protocol: %s", *cvec);
  1800. }
  1801. cvec ++;
  1802. }
  1803. g_strfreev (strvec);
  1804. }
  1805. else {
  1806. protocols_mask = default_mask;
  1807. }
  1808. }
  1809. else {
  1810. protocols_mask = default_mask;
  1811. }
  1812. cb.i = 1;
  1813. cb.L = L;
  1814. cb.mask = protocols_mask;
  1815. if (protocols_mask & PROTOCOL_MAILTO) {
  1816. sz = g_hash_table_size (task->urls) + g_hash_table_size (task->emails);
  1817. if (protocols_mask == (default_mask|PROTOCOL_MAILTO)) {
  1818. /* Can use cached version */
  1819. if (!lua_task_get_cached (L, task, "emails+urls", sz)) {
  1820. lua_createtable (L, sz, 0);
  1821. g_hash_table_foreach (task->urls, lua_tree_url_callback, &cb);
  1822. g_hash_table_foreach (task->emails, lua_tree_url_callback, &cb);
  1823. lua_task_set_cached (L, task, "emails+urls", -1, sz);
  1824. }
  1825. }
  1826. else {
  1827. lua_createtable (L, sz, 0);
  1828. g_hash_table_foreach (task->urls, lua_tree_url_callback, &cb);
  1829. g_hash_table_foreach (task->emails, lua_tree_url_callback, &cb);
  1830. }
  1831. }
  1832. else {
  1833. sz = g_hash_table_size (task->urls);
  1834. if (protocols_mask == (default_mask)) {
  1835. if (!lua_task_get_cached (L, task, "urls", sz)) {
  1836. lua_createtable (L, sz, 0);
  1837. g_hash_table_foreach (task->urls, lua_tree_url_callback, &cb);
  1838. lua_task_set_cached (L, task, "urls", -1, sz);
  1839. }
  1840. }
  1841. else {
  1842. lua_createtable (L, sz, 0);
  1843. g_hash_table_foreach (task->urls, lua_tree_url_callback, &cb);
  1844. }
  1845. }
  1846. }
  1847. else {
  1848. return luaL_error (L, "invalid arguments");
  1849. }
  1850. return 1;
  1851. }
  1852. static gint
  1853. lua_task_has_urls (lua_State * L)
  1854. {
  1855. LUA_TRACE_POINT;
  1856. struct rspamd_task *task = lua_check_task (L, 1);
  1857. gboolean need_emails = FALSE, ret = FALSE;
  1858. if (task) {
  1859. if (lua_gettop (L) >= 2) {
  1860. need_emails = lua_toboolean (L, 2);
  1861. }
  1862. if (g_hash_table_size (task->urls) > 0) {
  1863. ret = TRUE;
  1864. }
  1865. if (need_emails && g_hash_table_size (task->emails) > 0) {
  1866. ret = TRUE;
  1867. }
  1868. }
  1869. else {
  1870. return luaL_error (L, "invalid arguments");
  1871. }
  1872. lua_pushboolean (L, ret);
  1873. return 1;
  1874. }
  1875. static gint
  1876. lua_task_get_content (lua_State * L)
  1877. {
  1878. LUA_TRACE_POINT;
  1879. struct rspamd_task *task = lua_check_task (L, 1);
  1880. struct rspamd_lua_text *t;
  1881. if (task) {
  1882. t = lua_newuserdata (L, sizeof (*t));
  1883. rspamd_lua_setclass (L, "rspamd{text}", -1);
  1884. t->len = task->msg.len;
  1885. t->start = task->msg.begin;
  1886. t->flags = 0;
  1887. }
  1888. else {
  1889. return luaL_error (L, "invalid arguments");
  1890. }
  1891. return 1;
  1892. }
  1893. static gint
  1894. lua_task_get_filename (lua_State * L)
  1895. {
  1896. LUA_TRACE_POINT;
  1897. struct rspamd_task *task = lua_check_task (L, 1);
  1898. if (task) {
  1899. if (task->msg.fpath) {
  1900. lua_pushstring (L, task->msg.fpath);
  1901. }
  1902. else {
  1903. lua_pushnil (L);
  1904. }
  1905. }
  1906. else {
  1907. return luaL_error (L, "invalid arguments");
  1908. }
  1909. return 1;
  1910. }
  1911. static gint
  1912. lua_task_get_rawbody (lua_State * L)
  1913. {
  1914. LUA_TRACE_POINT;
  1915. struct rspamd_task *task = lua_check_task (L, 1);
  1916. struct rspamd_lua_text *t;
  1917. if (task) {
  1918. t = lua_newuserdata (L, sizeof (*t));
  1919. rspamd_lua_setclass (L, "rspamd{text}", -1);
  1920. if (task->raw_headers_content.len > 0) {
  1921. g_assert (task->raw_headers_content.len <= task->msg.len);
  1922. t->start = task->msg.begin + task->raw_headers_content.len;
  1923. t->len = task->msg.len - task->raw_headers_content.len;
  1924. }
  1925. else {
  1926. t->len = task->msg.len;
  1927. t->start = task->msg.begin;
  1928. }
  1929. t->flags = 0;
  1930. }
  1931. else {
  1932. return luaL_error (L, "invalid arguments");
  1933. }
  1934. return 1;
  1935. }
  1936. static gint
  1937. lua_task_get_emails (lua_State * L)
  1938. {
  1939. LUA_TRACE_POINT;
  1940. struct rspamd_task *task = lua_check_task (L, 1);
  1941. struct lua_tree_cb_data cb;
  1942. if (task) {
  1943. lua_createtable (L, g_hash_table_size (task->emails), 0);
  1944. cb.i = 1;
  1945. cb.L = L;
  1946. cb.mask = PROTOCOL_MAILTO;
  1947. g_hash_table_foreach (task->emails, lua_tree_url_callback, &cb);
  1948. }
  1949. else {
  1950. return luaL_error (L, "invalid arguments");
  1951. }
  1952. return 1;
  1953. }
  1954. static gint
  1955. lua_task_get_text_parts (lua_State * L)
  1956. {
  1957. LUA_TRACE_POINT;
  1958. guint i;
  1959. struct rspamd_task *task = lua_check_task (L, 1);
  1960. struct rspamd_mime_text_part *part, **ppart;
  1961. if (task != NULL) {
  1962. if (!lua_task_get_cached (L, task, "text_parts", task->text_parts->len)) {
  1963. lua_createtable (L, task->text_parts->len, 0);
  1964. for (i = 0; i < task->text_parts->len; i ++) {
  1965. part = g_ptr_array_index (task->text_parts, i);
  1966. ppart = lua_newuserdata (L, sizeof (struct rspamd_mime_text_part *));
  1967. *ppart = part;
  1968. rspamd_lua_setclass (L, "rspamd{textpart}", -1);
  1969. /* Make it array */
  1970. lua_rawseti (L, -2, i + 1);
  1971. }
  1972. lua_task_set_cached (L, task, "text_parts", -1, task->text_parts->len);
  1973. }
  1974. }
  1975. else {
  1976. return luaL_error (L, "invalid arguments");
  1977. }
  1978. return 1;
  1979. }
  1980. static gint
  1981. lua_task_get_parts (lua_State * L)
  1982. {
  1983. LUA_TRACE_POINT;
  1984. guint i;
  1985. struct rspamd_task *task = lua_check_task (L, 1);
  1986. struct rspamd_mime_part *part, **ppart;
  1987. if (task != NULL) {
  1988. if (!lua_task_get_cached (L, task, "mime_parts", task->parts->len)) {
  1989. lua_createtable (L, task->parts->len, 0);
  1990. for (i = 0; i < task->parts->len; i ++) {
  1991. part = g_ptr_array_index (task->parts, i);
  1992. ppart = lua_newuserdata (L, sizeof (struct rspamd_mime_part *));
  1993. *ppart = part;
  1994. rspamd_lua_setclass (L, "rspamd{mimepart}", -1);
  1995. /* Make it array */
  1996. lua_rawseti (L, -2, i + 1);
  1997. }
  1998. lua_task_set_cached (L, task, "mime_parts", -1, task->parts->len);
  1999. }
  2000. }
  2001. else {
  2002. return luaL_error (L, "invalid arguments");
  2003. }
  2004. return 1;
  2005. }
  2006. static gint
  2007. lua_task_get_request_header (lua_State *L)
  2008. {
  2009. LUA_TRACE_POINT;
  2010. rspamd_ftok_t *hdr;
  2011. struct rspamd_task *task = lua_check_task (L, 1);
  2012. const gchar *s;
  2013. struct rspamd_lua_text *t;
  2014. s = luaL_checkstring (L, 2);
  2015. if (s && task) {
  2016. hdr = rspamd_task_get_request_header (task, s);
  2017. if (hdr) {
  2018. t = lua_newuserdata (L, sizeof (*t));
  2019. rspamd_lua_setclass (L, "rspamd{text}", -1);
  2020. t->start = hdr->begin;
  2021. t->len = hdr->len;
  2022. t->flags = 0;
  2023. return 1;
  2024. }
  2025. else {
  2026. lua_pushnil (L);
  2027. }
  2028. }
  2029. else {
  2030. return luaL_error (L, "invalid arguments");
  2031. }
  2032. return 1;
  2033. }
  2034. static gint
  2035. lua_task_set_request_header (lua_State *L)
  2036. {
  2037. LUA_TRACE_POINT;
  2038. struct rspamd_task *task = lua_check_task (L, 1);
  2039. const gchar *s, *v = NULL;
  2040. rspamd_fstring_t *buf;
  2041. struct rspamd_lua_text *t;
  2042. rspamd_ftok_t *hdr, *new_name;
  2043. gsize len, vlen;
  2044. s = luaL_checklstring (L, 2, &len);
  2045. if (s && task) {
  2046. if (lua_type (L, 3) == LUA_TSTRING) {
  2047. v = luaL_checklstring (L, 3, &vlen);
  2048. }
  2049. else if (lua_type (L, 3) == LUA_TUSERDATA) {
  2050. t = lua_check_text (L, 3);
  2051. if (t != NULL) {
  2052. v = t->start;
  2053. vlen = t->len;
  2054. }
  2055. }
  2056. if (v != NULL) {
  2057. buf = rspamd_fstring_new_init (v, vlen);
  2058. hdr = rspamd_ftok_map (buf);
  2059. buf = rspamd_fstring_new_init (s, len);
  2060. new_name = rspamd_ftok_map (buf);
  2061. rspamd_task_add_request_header (task, new_name, hdr);
  2062. }
  2063. }
  2064. else {
  2065. return luaL_error (L, "invalid arguments");
  2066. }
  2067. return 0;
  2068. }
  2069. gint
  2070. rspamd_lua_push_header (lua_State *L, struct rspamd_mime_header *rh,
  2071. enum rspamd_lua_task_header_type how)
  2072. {
  2073. LUA_TRACE_POINT;
  2074. switch (how) {
  2075. case RSPAMD_TASK_HEADER_PUSH_FULL:
  2076. /* Create new associated table for a header */
  2077. lua_createtable (L, 0, 7);
  2078. rspamd_lua_table_set (L, "name", rh->name);
  2079. if (rh->value) {
  2080. rspamd_lua_table_set (L, "value", rh->value);
  2081. }
  2082. if (rh->raw_len > 0) {
  2083. lua_pushstring (L, "raw");
  2084. lua_pushlstring (L, rh->raw_value, rh->raw_len);
  2085. lua_settable (L, -3);
  2086. }
  2087. if (rh->decoded) {
  2088. rspamd_lua_table_set (L, "decoded", rh->decoded);
  2089. }
  2090. lua_pushstring (L, "tab_separated");
  2091. lua_pushboolean (L, rh->tab_separated);
  2092. lua_settable (L, -3);
  2093. lua_pushstring (L, "empty_separator");
  2094. lua_pushboolean (L, rh->empty_separator);
  2095. lua_settable (L, -3);
  2096. rspamd_lua_table_set (L, "separator", rh->separator);
  2097. lua_pushstring (L, "order");
  2098. lua_pushinteger (L, rh->order);
  2099. lua_settable (L, -3);
  2100. break;
  2101. case RSPAMD_TASK_HEADER_PUSH_RAW:
  2102. if (rh->value) {
  2103. lua_pushstring (L, rh->value);
  2104. }
  2105. else {
  2106. lua_pushnil (L);
  2107. }
  2108. break;
  2109. case RSPAMD_TASK_HEADER_PUSH_SIMPLE:
  2110. if (rh->decoded) {
  2111. lua_pushstring (L, rh->decoded);
  2112. }
  2113. else {
  2114. lua_pushnil (L);
  2115. }
  2116. break;
  2117. case RSPAMD_TASK_HEADER_PUSH_COUNT:
  2118. default:
  2119. g_assert_not_reached ();
  2120. break;
  2121. }
  2122. return 1;
  2123. }
  2124. gint
  2125. rspamd_lua_push_header_array (lua_State * L,
  2126. GPtrArray *ar,
  2127. enum rspamd_lua_task_header_type how)
  2128. {
  2129. LUA_TRACE_POINT;
  2130. struct rspamd_mime_header *rh;
  2131. guint i;
  2132. if (ar == NULL || ar->len == 0) {
  2133. if (how == RSPAMD_TASK_HEADER_PUSH_COUNT) {
  2134. lua_pushnumber (L, 0);
  2135. }
  2136. else {
  2137. lua_pushnil (L);
  2138. }
  2139. return 1;
  2140. }
  2141. if (how == RSPAMD_TASK_HEADER_PUSH_FULL) {
  2142. lua_createtable (L, ar->len, 0);
  2143. PTR_ARRAY_FOREACH (ar, i, rh) {
  2144. rspamd_lua_push_header (L, rh, how);
  2145. lua_rawseti (L, -2, i + 1);
  2146. }
  2147. }
  2148. else if (how == RSPAMD_TASK_HEADER_PUSH_COUNT) {
  2149. lua_pushinteger (L, ar->len);
  2150. }
  2151. else {
  2152. rh = g_ptr_array_index (ar, 0);
  2153. return rspamd_lua_push_header (L, rh, how);
  2154. }
  2155. return 1;
  2156. }
  2157. static gint
  2158. lua_task_get_header_common (lua_State *L, enum rspamd_lua_task_header_type how)
  2159. {
  2160. LUA_TRACE_POINT;
  2161. gboolean strong = FALSE;
  2162. struct rspamd_task *task = lua_check_task (L, 1);
  2163. const gchar *name;
  2164. GPtrArray *ar;
  2165. name = luaL_checkstring (L, 2);
  2166. if (name && task) {
  2167. if (lua_gettop (L) == 3) {
  2168. strong = lua_toboolean (L, 3);
  2169. }
  2170. ar = rspamd_message_get_header_array (task, name, strong);
  2171. return rspamd_lua_push_header_array (L, ar, how);
  2172. }
  2173. else {
  2174. return luaL_error (L, "invalid arguments");
  2175. }
  2176. }
  2177. static gint
  2178. lua_task_get_header_full (lua_State * L)
  2179. {
  2180. return lua_task_get_header_common (L, RSPAMD_TASK_HEADER_PUSH_FULL);
  2181. }
  2182. static gint
  2183. lua_task_get_header (lua_State * L)
  2184. {
  2185. return lua_task_get_header_common (L, RSPAMD_TASK_HEADER_PUSH_SIMPLE);
  2186. }
  2187. static gint
  2188. lua_task_get_header_raw (lua_State * L)
  2189. {
  2190. return lua_task_get_header_common (L, RSPAMD_TASK_HEADER_PUSH_RAW);
  2191. }
  2192. static gint
  2193. lua_task_get_header_count (lua_State * L)
  2194. {
  2195. return lua_task_get_header_common (L, RSPAMD_TASK_HEADER_PUSH_COUNT);
  2196. }
  2197. static gint
  2198. lua_task_get_raw_headers (lua_State *L)
  2199. {
  2200. LUA_TRACE_POINT;
  2201. struct rspamd_task *task = lua_check_task (L, 1);
  2202. struct rspamd_lua_text *t;
  2203. if (task) {
  2204. t = lua_newuserdata (L, sizeof (*t));
  2205. rspamd_lua_setclass (L, "rspamd{text}", -1);
  2206. t->start = task->raw_headers_content.begin;
  2207. t->len = task->raw_headers_content.len;
  2208. t->flags = 0;
  2209. }
  2210. else {
  2211. return luaL_error (L, "invalid arguments");
  2212. }
  2213. return 1;
  2214. }
  2215. static gint
  2216. lua_task_get_received_headers (lua_State * L)
  2217. {
  2218. LUA_TRACE_POINT;
  2219. struct rspamd_task *task = lua_check_task (L, 1);
  2220. struct received_header *rh;
  2221. const gchar *proto;
  2222. guint i, k = 1;
  2223. if (task) {
  2224. if (!lua_task_get_cached (L, task, "received", task->received->len)) {
  2225. lua_createtable (L, task->received->len, 0);
  2226. for (i = 0; i < task->received->len; i ++) {
  2227. rh = g_ptr_array_index (task->received, i);
  2228. lua_createtable (L, 0, 10);
  2229. if (rh->hdr && rh->hdr->decoded) {
  2230. rspamd_lua_table_set (L, "raw", rh->hdr->decoded);
  2231. }
  2232. lua_pushstring (L, "flags");
  2233. lua_createtable (L, 0, 3);
  2234. lua_pushstring (L, "artificial");
  2235. if (rh->flags & RSPAMD_RECEIVED_FLAG_ARTIFICIAL) {
  2236. lua_pushboolean (L, true);
  2237. }
  2238. else {
  2239. lua_pushboolean (L, false);
  2240. }
  2241. lua_settable (L, -3);
  2242. lua_pushstring (L, "authenticated");
  2243. if (rh->flags & RSPAMD_RECEIVED_FLAG_AUTHENTICATED) {
  2244. lua_pushboolean (L, true);
  2245. }
  2246. else {
  2247. lua_pushboolean (L, false);
  2248. }
  2249. lua_settable (L, -3);
  2250. lua_pushstring (L, "ssl");
  2251. if (rh->flags & RSPAMD_RECEIVED_FLAG_SSL) {
  2252. lua_pushboolean (L, true);
  2253. }
  2254. else {
  2255. lua_pushboolean (L, false);
  2256. }
  2257. lua_settable (L, -3);
  2258. lua_settable (L, -3);
  2259. if (G_UNLIKELY (rh->from_ip == NULL &&
  2260. rh->real_ip == NULL &&
  2261. rh->real_hostname == NULL &&
  2262. rh->by_hostname == NULL && rh->timestamp == 0 &&
  2263. rh->for_mbox == NULL)) {
  2264. lua_rawseti (L, -2, k ++);
  2265. continue;
  2266. }
  2267. rspamd_lua_table_set (L, "from_hostname", rh->from_hostname);
  2268. rspamd_lua_table_set (L, "from_ip", rh->from_ip);
  2269. rspamd_lua_table_set (L, "real_hostname", rh->real_hostname);
  2270. lua_pushstring (L, "real_ip");
  2271. rspamd_lua_ip_push (L, rh->addr);
  2272. lua_settable (L, -3);
  2273. lua_pushstring (L, "proto");
  2274. switch (rh->type) {
  2275. case RSPAMD_RECEIVED_SMTP:
  2276. proto = "smtp";
  2277. break;
  2278. case RSPAMD_RECEIVED_ESMTP:
  2279. proto = "esmtp";
  2280. break;
  2281. case RSPAMD_RECEIVED_ESMTPS:
  2282. proto = "esmtps";
  2283. break;
  2284. case RSPAMD_RECEIVED_ESMTPA:
  2285. proto = "esmtpa";
  2286. break;
  2287. case RSPAMD_RECEIVED_ESMTPSA:
  2288. proto = "esmtpsa";
  2289. break;
  2290. case RSPAMD_RECEIVED_LMTP:
  2291. proto = "lmtp";
  2292. break;
  2293. case RSPAMD_RECEIVED_IMAP:
  2294. proto = "imap";
  2295. break;
  2296. case RSPAMD_RECEIVED_HTTP:
  2297. proto = "http";
  2298. break;
  2299. case RSPAMD_RECEIVED_LOCAL:
  2300. proto = "local";
  2301. break;
  2302. case RSPAMD_RECEIVED_MAPI:
  2303. proto = "mapi";
  2304. break;
  2305. case RSPAMD_RECEIVED_UNKNOWN:
  2306. default:
  2307. proto = "unknown";
  2308. break;
  2309. }
  2310. lua_pushstring (L, proto);
  2311. lua_settable (L, -3);
  2312. lua_pushstring (L, "timestamp");
  2313. lua_pushinteger (L, rh->timestamp);
  2314. lua_settable (L, -3);
  2315. rspamd_lua_table_set (L, "by_hostname", rh->by_hostname);
  2316. rspamd_lua_table_set (L, "for", rh->for_mbox);
  2317. lua_rawseti (L, -2, k ++);
  2318. }
  2319. lua_task_set_cached (L, task, "received", -1, task->received->len);
  2320. }
  2321. }
  2322. else {
  2323. return luaL_error (L, "invalid arguments");
  2324. }
  2325. return 1;
  2326. }
  2327. static gint
  2328. lua_task_get_queue_id (lua_State *L)
  2329. {
  2330. LUA_TRACE_POINT;
  2331. struct rspamd_task *task = lua_check_task (L, 1);
  2332. if (task) {
  2333. if (task->queue_id != NULL && strcmp (task->queue_id, "undef") != 0) {
  2334. lua_pushstring (L, task->queue_id);
  2335. }
  2336. else {
  2337. lua_pushnil (L);
  2338. }
  2339. }
  2340. else {
  2341. return luaL_error (L, "invalid arguments");
  2342. }
  2343. return 1;
  2344. }
  2345. static gint
  2346. lua_task_get_uid (lua_State *L)
  2347. {
  2348. LUA_TRACE_POINT;
  2349. struct rspamd_task *task = lua_check_task (L, 1);
  2350. if (task) {
  2351. lua_pushstring (L, task->task_pool->tag.uid);
  2352. }
  2353. else {
  2354. return luaL_error (L, "invalid arguments");
  2355. }
  2356. return 1;
  2357. }
  2358. static gint
  2359. lua_task_get_resolver (lua_State *L)
  2360. {
  2361. LUA_TRACE_POINT;
  2362. struct rspamd_task *task = lua_check_task (L, 1);
  2363. struct rspamd_dns_resolver **presolver;
  2364. if (task != NULL && task->resolver != NULL) {
  2365. presolver = lua_newuserdata (L, sizeof (void *));
  2366. rspamd_lua_setclass (L, "rspamd{resolver}", -1);
  2367. *presolver = task->resolver;
  2368. }
  2369. else {
  2370. return luaL_error (L, "invalid arguments");
  2371. }
  2372. return 1;
  2373. }
  2374. static gint
  2375. lua_task_set_resolver (lua_State *L)
  2376. {
  2377. LUA_TRACE_POINT;
  2378. struct rspamd_task *task = lua_check_task (L, 1);
  2379. struct rspamd_dns_resolver *resolver = lua_check_dns_resolver (L, 2);
  2380. if (task != NULL && resolver != NULL) {
  2381. task->resolver = resolver;
  2382. }
  2383. else {
  2384. return luaL_error (L, "invalid arguments");
  2385. }
  2386. return 0;
  2387. }
  2388. static gint
  2389. lua_task_inc_dns_req (lua_State *L)
  2390. {
  2391. LUA_TRACE_POINT;
  2392. struct rspamd_task *task = lua_check_task (L, 1);
  2393. static guint warning_shown = 0;
  2394. if (warning_shown < 100) {
  2395. warning_shown ++;
  2396. msg_warn_task_check ("task:inc_dns_req is deprecated and should not be used");
  2397. }
  2398. if (task != NULL) {
  2399. /* Deprecation: already done in rspamd_dns_resolver_request */
  2400. }
  2401. else {
  2402. return luaL_error (L, "invalid arguments");
  2403. }
  2404. return 0;
  2405. }
  2406. static gint
  2407. lua_task_get_dns_req (lua_State *L)
  2408. {
  2409. LUA_TRACE_POINT;
  2410. struct rspamd_task *task = lua_check_task (L, 1);
  2411. if (task != NULL) {
  2412. lua_pushinteger (L, task->dns_requests);
  2413. }
  2414. else {
  2415. return luaL_error (L, "invalid arguments");
  2416. }
  2417. return 1;
  2418. }
  2419. enum rspamd_address_type {
  2420. RSPAMD_ADDRESS_ANY = 0,
  2421. RSPAMD_ADDRESS_SMTP = 1,
  2422. RSPAMD_ADDRESS_MIME = 2,
  2423. RSPAMD_ADDRESS_MASK = 0x3FF,
  2424. RSPAMD_ADDRESS_RAW = (1u << 10),
  2425. RSPAMD_ADDRESS_ORIGINAL = (1u << 11),
  2426. RSPAMD_ADDRESS_MAX = RSPAMD_ADDRESS_MASK,
  2427. };
  2428. /*
  2429. * Convert element at the specified position to the type
  2430. * for get_from/get_recipients
  2431. */
  2432. static enum rspamd_address_type
  2433. lua_task_str_to_get_type (lua_State *L, struct rspamd_task *task, gint pos)
  2434. {
  2435. const gchar *type = NULL;
  2436. gint ret = RSPAMD_ADDRESS_ANY;
  2437. guint64 h;
  2438. gsize sz;
  2439. /* Get what value */
  2440. if (lua_type (L, pos) == LUA_TNUMBER) {
  2441. ret = lua_tonumber (L, pos);
  2442. if (ret >= RSPAMD_ADDRESS_ANY && ret < RSPAMD_ADDRESS_MAX) {
  2443. return ret;
  2444. }
  2445. return RSPAMD_ADDRESS_ANY;
  2446. }
  2447. else if (lua_type (L, pos) == LUA_TSTRING) {
  2448. type = lua_tolstring (L, pos, &sz);
  2449. if (type && sz > 0) {
  2450. h = rspamd_cryptobox_fast_hash_specific (RSPAMD_CRYPTOBOX_XXHASH64,
  2451. type, sz, 0xdeadbabe);
  2452. switch (h) {
  2453. case 0xDA081341FB600389ULL: /* mime */
  2454. ret = RSPAMD_ADDRESS_MIME;
  2455. break;
  2456. case 0xEEC8A7832F8C43ACULL: /* any */
  2457. ret = RSPAMD_ADDRESS_ANY;
  2458. break;
  2459. case 0x472274D5193B2A80ULL: /* smtp */
  2460. case 0xEFE0F586CC9F14A9ULL: /* envelope */
  2461. ret = RSPAMD_ADDRESS_SMTP;
  2462. break;
  2463. default:
  2464. msg_err_task ("invalid email type: %*s", (gint)sz, type);
  2465. break;
  2466. }
  2467. }
  2468. }
  2469. else if (lua_type (L, pos) == LUA_TTABLE) {
  2470. for (lua_pushnil (L); lua_next (L, pos); lua_pop (L, 1)) {
  2471. type = lua_tolstring (L, pos, &sz);
  2472. if (type && sz > 0) {
  2473. h = rspamd_cryptobox_fast_hash_specific (RSPAMD_CRYPTOBOX_XXHASH64,
  2474. type, sz, 0xdeadbabe);
  2475. switch (h) {
  2476. case 0xDA081341FB600389ULL: /* mime */
  2477. ret |= RSPAMD_ADDRESS_MIME;
  2478. break;
  2479. case 0xEEC8A7832F8C43ACULL: /* any */
  2480. ret |= RSPAMD_ADDRESS_ANY;
  2481. break;
  2482. case 0x472274D5193B2A80ULL: /* smtp */
  2483. case 0xEFE0F586CC9F14A9ULL: /* envelope */
  2484. ret |= RSPAMD_ADDRESS_SMTP;
  2485. break;
  2486. case 0xAF4DE083D9AD0132: /* raw */
  2487. ret |= RSPAMD_ADDRESS_RAW;
  2488. break;
  2489. case 0xC7AB6C7B7B0F5A8A: /* orig */
  2490. case 0x1778AE905589E431: /* original */
  2491. ret |= RSPAMD_ADDRESS_ORIGINAL;
  2492. break;
  2493. default:
  2494. msg_err_task ("invalid email type: %*s", (gint)sz, type);
  2495. break;
  2496. }
  2497. }
  2498. }
  2499. }
  2500. return ret;
  2501. }
  2502. #define EMAIL_CHECK_FLAG(fl, str) do { \
  2503. if (addr->flags & (fl)) { \
  2504. lua_pushstring (L, (str)); \
  2505. lua_pushboolean (L, true); \
  2506. lua_settable (L, -3); \
  2507. } \
  2508. } while(0)
  2509. static void
  2510. lua_push_email_address (lua_State *L, struct rspamd_email_address *addr)
  2511. {
  2512. if (addr) {
  2513. lua_createtable (L, 0, 4);
  2514. if (addr->addr_len > 0) {
  2515. lua_pushstring (L, "addr");
  2516. lua_pushlstring (L, addr->addr, addr->addr_len);
  2517. lua_settable (L, -3);
  2518. }
  2519. else {
  2520. lua_pushstring (L, "addr");
  2521. lua_pushstring (L, "");
  2522. lua_settable (L, -3);
  2523. }
  2524. if (addr->domain_len > 0) {
  2525. lua_pushstring (L, "domain");
  2526. lua_pushlstring (L, addr->domain, addr->domain_len);
  2527. lua_settable (L, -3);
  2528. }
  2529. else {
  2530. lua_pushstring (L, "domain");
  2531. lua_pushstring (L, "");
  2532. lua_settable (L, -3);
  2533. }
  2534. if (addr->user_len > 0) {
  2535. lua_pushstring (L, "user");
  2536. lua_pushlstring (L, addr->user, addr->user_len);
  2537. lua_settable (L, -3);
  2538. }
  2539. else {
  2540. lua_pushstring (L, "user");
  2541. lua_pushstring (L, "");
  2542. lua_settable (L, -3);
  2543. }
  2544. if (addr->name) {
  2545. lua_pushstring (L, "name");
  2546. lua_pushstring (L, addr->name);
  2547. lua_settable (L, -3);
  2548. }
  2549. else {
  2550. lua_pushstring (L, "name");
  2551. lua_pushstring (L, "");
  2552. lua_settable (L, -3);
  2553. }
  2554. lua_pushstring (L, "flags");
  2555. lua_createtable (L, 0, 7);
  2556. EMAIL_CHECK_FLAG (RSPAMD_EMAIL_ADDR_VALID, "valid");
  2557. EMAIL_CHECK_FLAG (RSPAMD_EMAIL_ADDR_IP, "ip");
  2558. EMAIL_CHECK_FLAG (RSPAMD_EMAIL_ADDR_BRACED, "braced");
  2559. EMAIL_CHECK_FLAG (RSPAMD_EMAIL_ADDR_QUOTED, "quoted");
  2560. EMAIL_CHECK_FLAG (RSPAMD_EMAIL_ADDR_EMPTY, "empty");
  2561. EMAIL_CHECK_FLAG (RSPAMD_EMAIL_ADDR_HAS_BACKSLASH, "backslash");
  2562. EMAIL_CHECK_FLAG (RSPAMD_EMAIL_ADDR_HAS_8BIT, "8bit");
  2563. lua_settable (L, -3);
  2564. }
  2565. }
  2566. void
  2567. lua_push_emails_address_list (lua_State *L, GPtrArray *addrs, int flags)
  2568. {
  2569. struct rspamd_email_address *addr;
  2570. guint i, pos = 1;
  2571. lua_createtable (L, addrs->len, 0);
  2572. for (i = 0; i < addrs->len; i ++) {
  2573. addr = g_ptr_array_index (addrs, i);
  2574. if (addr->flags & RSPAMD_EMAIL_ADDR_ORIGINAL) {
  2575. if (flags & RSPAMD_ADDRESS_ORIGINAL) {
  2576. lua_push_email_address (L, addr);
  2577. lua_rawseti (L, -2, pos);
  2578. pos++;
  2579. }
  2580. }
  2581. else {
  2582. lua_push_email_address (L, addr);
  2583. lua_rawseti (L, -2, pos);
  2584. pos++;
  2585. }
  2586. }
  2587. }
  2588. static gboolean
  2589. lua_import_email_address (lua_State *L, struct rspamd_task *task,
  2590. gint pos,
  2591. struct rspamd_email_address **paddr)
  2592. {
  2593. struct rspamd_email_address *addr;
  2594. const gchar *p;
  2595. gchar *dst;
  2596. gsize len;
  2597. g_assert (paddr != NULL);
  2598. if (!lua_istable (L, pos)) {
  2599. return FALSE;
  2600. }
  2601. addr = g_malloc0 (sizeof (*addr));
  2602. lua_pushstring (L, "name");
  2603. lua_gettable (L, pos);
  2604. if (lua_type (L, -1) == LUA_TSTRING) {
  2605. p = lua_tolstring (L, -1, &len);
  2606. dst = rspamd_mempool_alloc (task->task_pool, len + 1);
  2607. rspamd_strlcpy (dst, p, len + 1);
  2608. addr->name = dst;
  2609. }
  2610. lua_pop (L, 1);
  2611. lua_pushstring (L, "user");
  2612. lua_gettable (L, pos);
  2613. if (lua_type (L, -1) == LUA_TSTRING) {
  2614. p = lua_tolstring (L, -1, &len);
  2615. addr->user = (const gchar *)rspamd_mempool_alloc (task->task_pool, len);
  2616. memcpy ((gchar *)addr->user, p, len);
  2617. addr->user_len = len;
  2618. }
  2619. lua_pop (L, 1);
  2620. lua_pushstring (L, "domain");
  2621. lua_gettable (L, pos);
  2622. if (lua_type (L, -1) == LUA_TSTRING) {
  2623. p = lua_tolstring (L, -1, &len);
  2624. addr->domain = (const gchar *)rspamd_mempool_alloc (task->task_pool, len);
  2625. memcpy ((gchar *)addr->domain, p, len);
  2626. addr->domain_len = len;
  2627. }
  2628. lua_pop (L, 1);
  2629. lua_pushstring (L, "addr");
  2630. lua_gettable (L, pos);
  2631. if (lua_type (L, -1) == LUA_TSTRING) {
  2632. p = lua_tolstring (L, -1, &len);
  2633. addr->addr = (const gchar *)rspamd_mempool_alloc (task->task_pool, len);
  2634. memcpy ((gchar *)addr->addr, p, len);
  2635. addr->addr_len = len;
  2636. }
  2637. else {
  2638. /* Construct addr */
  2639. len = addr->domain_len + addr->user_len + 1;
  2640. addr->addr = (const gchar *)rspamd_mempool_alloc (task->task_pool, len);
  2641. addr->addr_len = rspamd_snprintf ((gchar *)addr->addr, len, "%*s@%*s",
  2642. (int)addr->user_len, addr->user,
  2643. (int)addr->domain_len, addr->domain);
  2644. }
  2645. lua_pop (L, 1);
  2646. lua_pushstring (L, "raw");
  2647. lua_gettable (L, pos);
  2648. if (lua_type (L, -1) == LUA_TSTRING) {
  2649. gchar *cpy;
  2650. p = lua_tolstring (L, -1, &len);
  2651. cpy = rspamd_mempool_alloc (task->task_pool, len + 1);
  2652. memcpy (cpy, p, len);
  2653. cpy[len] = '\0';
  2654. addr->raw_len = len;
  2655. addr->raw = cpy;
  2656. }
  2657. else {
  2658. /* Construct raw addr */
  2659. len = addr->addr_len + 3;
  2660. if (addr->name) {
  2661. len += strlen (addr->name) + 1;
  2662. dst = rspamd_mempool_alloc (task->task_pool, len + 1);
  2663. addr->raw_len = rspamd_snprintf (dst, len, "%s <%*s>",
  2664. addr->name,
  2665. (int)addr->addr_len, addr->addr);
  2666. }
  2667. else {
  2668. dst = rspamd_mempool_alloc (task->task_pool, len + 1);
  2669. addr->raw_len = rspamd_snprintf (dst, len, "<%*s@%*s>",
  2670. (int)addr->user_len, addr->user,
  2671. (int)addr->domain_len, addr->domain);
  2672. }
  2673. addr->raw = dst;
  2674. }
  2675. lua_pop (L, 1);
  2676. addr->flags = RSPAMD_EMAIL_ADDR_VALID;
  2677. *paddr = addr;
  2678. return TRUE;
  2679. }
  2680. static gint
  2681. lua_task_get_recipients (lua_State *L)
  2682. {
  2683. LUA_TRACE_POINT;
  2684. struct rspamd_task *task = lua_check_task (L, 1);
  2685. GPtrArray *ptrs = NULL;
  2686. gint what = 0;
  2687. if (task) {
  2688. if (lua_gettop (L) == 2) {
  2689. /* Get what value */
  2690. what = lua_task_str_to_get_type (L, task, 2);
  2691. }
  2692. switch (what & RSPAMD_ADDRESS_MASK) {
  2693. case RSPAMD_ADDRESS_SMTP:
  2694. /* Here we check merely envelope rcpt */
  2695. ptrs = task->rcpt_envelope;
  2696. break;
  2697. case RSPAMD_ADDRESS_MIME:
  2698. /* Here we check merely mime rcpt */
  2699. ptrs = task->rcpt_mime;
  2700. break;
  2701. case RSPAMD_ADDRESS_ANY:
  2702. default:
  2703. if (task->rcpt_envelope) {
  2704. ptrs = task->rcpt_envelope;
  2705. }
  2706. else {
  2707. ptrs = task->rcpt_mime;
  2708. }
  2709. break;
  2710. }
  2711. if (ptrs) {
  2712. lua_push_emails_address_list (L, ptrs, what & ~RSPAMD_ADDRESS_MASK);
  2713. }
  2714. else {
  2715. lua_pushnil (L);
  2716. }
  2717. }
  2718. else {
  2719. return luaL_error (L, "invalid arguments");
  2720. }
  2721. return 1;
  2722. }
  2723. static gint
  2724. lua_task_set_recipients (lua_State *L)
  2725. {
  2726. LUA_TRACE_POINT;
  2727. struct rspamd_task *task = lua_check_task (L, 1);
  2728. GPtrArray *ptrs = NULL;
  2729. struct rspamd_email_address *addr = NULL;
  2730. gint what = 0, pos = 3;
  2731. const gchar *how = "rewrite";
  2732. if (task && lua_gettop (L) >= 3) {
  2733. /* Get what value */
  2734. what = lua_task_str_to_get_type (L, task, 2);
  2735. if (lua_isstring (L, 4)) {
  2736. how = lua_tostring (L, 4);
  2737. }
  2738. switch (what) {
  2739. case RSPAMD_ADDRESS_SMTP:
  2740. /* Here we check merely envelope rcpt */
  2741. ptrs = task->rcpt_envelope;
  2742. break;
  2743. case RSPAMD_ADDRESS_MIME:
  2744. /* Here we check merely mime rcpt */
  2745. ptrs = task->rcpt_mime;
  2746. break;
  2747. case RSPAMD_ADDRESS_ANY:
  2748. default:
  2749. if (task->rcpt_envelope) {
  2750. ptrs = task->rcpt_envelope;
  2751. }
  2752. else {
  2753. ptrs = task->rcpt_mime;
  2754. }
  2755. break;
  2756. }
  2757. if (ptrs) {
  2758. guint i, flags_add = RSPAMD_EMAIL_ADDR_ORIGINAL;
  2759. struct rspamd_email_address *tmp;
  2760. if (strcmp (how, "alias") == 0) {
  2761. flags_add |= RSPAMD_EMAIL_ADDR_ALIASED;
  2762. }
  2763. PTR_ARRAY_FOREACH (ptrs, i, tmp) {
  2764. tmp->flags |= flags_add;
  2765. }
  2766. lua_pushvalue (L, pos);
  2767. for (lua_pushnil (L); lua_next (L, -2); lua_pop (L, 1)) {
  2768. if (lua_import_email_address (L, task, lua_gettop (L), &addr)) {
  2769. g_ptr_array_add (ptrs, addr);
  2770. }
  2771. }
  2772. lua_pop (L, 1);
  2773. lua_pushboolean (L, true);
  2774. }
  2775. else {
  2776. lua_pushboolean (L, false);
  2777. }
  2778. }
  2779. else {
  2780. return luaL_error (L, "invalid arguments");
  2781. }
  2782. return 1;
  2783. }
  2784. #define CHECK_EMAIL_ADDR(addr) do { \
  2785. if (addr == NULL) { \
  2786. ret = 0; \
  2787. } \
  2788. else { \
  2789. ret = addr->flags & RSPAMD_EMAIL_ADDR_VALID; \
  2790. } \
  2791. } while (0)
  2792. #define CHECK_EMAIL_ADDR_LIST(addr) do { \
  2793. if (addr == NULL) { \
  2794. ret = 0; \
  2795. } \
  2796. else { \
  2797. ret = addr->len > 0; \
  2798. } \
  2799. } while (0)
  2800. static gint
  2801. lua_task_has_from (lua_State *L)
  2802. {
  2803. LUA_TRACE_POINT;
  2804. struct rspamd_task *task = lua_check_task (L, 1);
  2805. gint what = 0;
  2806. gboolean ret = FALSE;
  2807. if (task) {
  2808. if (lua_gettop (L) == 2) {
  2809. /* Get what value */
  2810. what = lua_task_str_to_get_type (L, task, 2);
  2811. }
  2812. switch (what & RSPAMD_ADDRESS_MASK) {
  2813. case RSPAMD_ADDRESS_SMTP:
  2814. /* Here we check merely envelope rcpt */
  2815. CHECK_EMAIL_ADDR (task->from_envelope);
  2816. break;
  2817. case RSPAMD_ADDRESS_MIME:
  2818. /* Here we check merely mime rcpt */
  2819. CHECK_EMAIL_ADDR_LIST (task->from_mime);
  2820. break;
  2821. case RSPAMD_ADDRESS_ANY:
  2822. default:
  2823. CHECK_EMAIL_ADDR (task->from_envelope);
  2824. if (!ret) {
  2825. CHECK_EMAIL_ADDR_LIST (task->from_mime);
  2826. }
  2827. break;
  2828. }
  2829. }
  2830. else {
  2831. return luaL_error (L, "invalid arguments");
  2832. }
  2833. lua_pushboolean (L, ret);
  2834. return 1;
  2835. }
  2836. static gint
  2837. lua_task_has_recipients (lua_State *L)
  2838. {
  2839. LUA_TRACE_POINT;
  2840. struct rspamd_task *task = lua_check_task (L, 1);
  2841. gint what = 0;
  2842. gboolean ret = FALSE;
  2843. if (task) {
  2844. if (lua_gettop (L) == 2) {
  2845. /* Get what value */
  2846. what = lua_task_str_to_get_type (L, task, 2);
  2847. }
  2848. switch (what & RSPAMD_ADDRESS_MASK) {
  2849. case RSPAMD_ADDRESS_SMTP:
  2850. /* Here we check merely envelope rcpt */
  2851. CHECK_EMAIL_ADDR_LIST (task->rcpt_envelope);
  2852. break;
  2853. case RSPAMD_ADDRESS_MIME:
  2854. /* Here we check merely mime rcpt */
  2855. CHECK_EMAIL_ADDR_LIST (task->rcpt_mime);
  2856. break;
  2857. case RSPAMD_ADDRESS_ANY:
  2858. default:
  2859. CHECK_EMAIL_ADDR_LIST (task->rcpt_envelope);
  2860. if (!ret) {
  2861. CHECK_EMAIL_ADDR_LIST (task->rcpt_mime);
  2862. }
  2863. break;
  2864. }
  2865. }
  2866. else {
  2867. return luaL_error (L, "invalid arguments");
  2868. }
  2869. lua_pushboolean (L, ret);
  2870. return 1;
  2871. }
  2872. static gint
  2873. lua_task_get_from (lua_State *L)
  2874. {
  2875. LUA_TRACE_POINT;
  2876. struct rspamd_task *task = lua_check_task (L, 1);
  2877. GPtrArray *addrs = NULL;
  2878. struct rspamd_email_address *addr = NULL;
  2879. gint what = 0;
  2880. if (task) {
  2881. if (lua_gettop (L) == 2) {
  2882. /* Get what value */
  2883. what = lua_task_str_to_get_type (L, task, 2);
  2884. }
  2885. switch (what & RSPAMD_ADDRESS_MASK) {
  2886. case RSPAMD_ADDRESS_SMTP:
  2887. /* Here we check merely envelope rcpt */
  2888. addr = task->from_envelope;
  2889. break;
  2890. case RSPAMD_ADDRESS_MIME:
  2891. /* Here we check merely mime rcpt */
  2892. addrs = task->from_mime;
  2893. break;
  2894. case RSPAMD_ADDRESS_ANY:
  2895. default:
  2896. if (task->from_envelope) {
  2897. addr = task->from_envelope;
  2898. }
  2899. else {
  2900. addrs = task->from_mime;
  2901. }
  2902. break;
  2903. }
  2904. if (addrs) {
  2905. lua_push_emails_address_list (L, addrs, what & ~RSPAMD_ADDRESS_MASK);
  2906. }
  2907. else if (addr) {
  2908. /* Create table to preserve compatibility */
  2909. if (addr->addr) {
  2910. lua_createtable (L, 1, 0);
  2911. lua_push_email_address (L, addr);
  2912. lua_rawseti (L, -2, 1);
  2913. }
  2914. else {
  2915. lua_pushnil (L);
  2916. }
  2917. }
  2918. else {
  2919. lua_pushnil (L);
  2920. }
  2921. }
  2922. else {
  2923. return luaL_error (L, "invalid arguments");
  2924. }
  2925. return 1;
  2926. }
  2927. static gint
  2928. lua_task_set_from (lua_State *L)
  2929. {
  2930. LUA_TRACE_POINT;
  2931. struct rspamd_task *task = lua_check_task (L, 1);
  2932. const gchar *how = "rewrite";
  2933. GPtrArray *addrs = NULL;
  2934. struct rspamd_email_address **paddr = NULL, *addr;
  2935. gint what = 0;
  2936. if (task && lua_gettop (L) >= 3) {
  2937. what = lua_task_str_to_get_type (L, task, 2);
  2938. if (lua_isstring (L, 4)) {
  2939. how = lua_tostring (L, 4);
  2940. }
  2941. switch (what & RSPAMD_ADDRESS_MASK) {
  2942. case RSPAMD_ADDRESS_SMTP:
  2943. /* Here we check merely envelope rcpt */
  2944. paddr = &task->from_envelope;
  2945. break;
  2946. case RSPAMD_ADDRESS_MIME:
  2947. /* Here we check merely mime rcpt */
  2948. addrs = task->from_mime;
  2949. break;
  2950. case RSPAMD_ADDRESS_ANY:
  2951. default:
  2952. if (task->from_envelope) {
  2953. paddr = &task->from_envelope;
  2954. }
  2955. else {
  2956. addrs = task->from_mime;
  2957. }
  2958. break;
  2959. }
  2960. if (addrs) {
  2961. if (lua_import_email_address (L, task, 3, &addr)) {
  2962. guint i, flags_add = RSPAMD_EMAIL_ADDR_ORIGINAL;
  2963. struct rspamd_email_address *tmp;
  2964. if (strcmp (how, "alias") == 0) {
  2965. flags_add |= RSPAMD_EMAIL_ADDR_ALIASED;
  2966. }
  2967. PTR_ARRAY_FOREACH (addrs, i, tmp) {
  2968. tmp->flags |= flags_add;
  2969. }
  2970. g_ptr_array_add (addrs, addr);
  2971. lua_pushboolean (L, true);
  2972. }
  2973. else {
  2974. lua_pushboolean (L, false);
  2975. }
  2976. }
  2977. else if (paddr) {
  2978. if (lua_import_email_address (L, task, 3, &addr)) {
  2979. if (paddr) {
  2980. rspamd_email_address_free (*paddr);
  2981. }
  2982. *paddr = addr;
  2983. lua_pushboolean (L, true);
  2984. }
  2985. else {
  2986. lua_pushboolean (L, false);
  2987. }
  2988. }
  2989. else {
  2990. lua_pushboolean (L, false);
  2991. }
  2992. }
  2993. else {
  2994. return luaL_error (L, "invalid arguments");
  2995. }
  2996. return 1;
  2997. }
  2998. static gint
  2999. lua_task_get_principal_recipient (lua_State *L)
  3000. {
  3001. LUA_TRACE_POINT;
  3002. struct rspamd_task *task = lua_check_task (L, 1);
  3003. const gchar *r;
  3004. if (task) {
  3005. r = rspamd_task_get_principal_recipient (task);
  3006. if (r != NULL) {
  3007. lua_pushstring (L, r);
  3008. }
  3009. else {
  3010. lua_pushnil (L);
  3011. }
  3012. }
  3013. else {
  3014. return luaL_error (L, "invalid arguments");
  3015. }
  3016. return 1;
  3017. }
  3018. static gint
  3019. lua_task_get_reply_sender (lua_State *L)
  3020. {
  3021. LUA_TRACE_POINT;
  3022. struct rspamd_task *task = lua_check_task (L, 1);
  3023. struct rspamd_mime_header *rh;
  3024. if (task) {
  3025. GPtrArray *ar;
  3026. ar = rspamd_message_get_header_array (task, "Reply-To", false);
  3027. if (ar && ar->len == 1) {
  3028. rh = (struct rspamd_mime_header *)g_ptr_array_index (ar, 0);
  3029. lua_pushstring (L, rh->decoded);
  3030. }
  3031. else if (task->from_mime && task->from_mime->len == 1) {
  3032. struct rspamd_email_address *addr;
  3033. addr = (struct rspamd_email_address *)g_ptr_array_index (task->from_mime, 0);
  3034. lua_pushlstring (L, addr->addr, addr->addr_len);
  3035. }
  3036. else if (task->from_envelope) {
  3037. lua_pushlstring (L, task->from_envelope->addr,
  3038. task->from_envelope->addr_len);
  3039. }
  3040. else {
  3041. lua_pushnil (L);
  3042. }
  3043. }
  3044. else {
  3045. return luaL_error (L, "invalid arguments");
  3046. }
  3047. return 1;
  3048. }
  3049. static gint
  3050. lua_task_get_user (lua_State *L)
  3051. {
  3052. LUA_TRACE_POINT;
  3053. struct rspamd_task *task = lua_check_task (L, 1);
  3054. if (task) {
  3055. if (task->user != NULL) {
  3056. lua_pushstring (L, task->user);
  3057. }
  3058. else {
  3059. lua_pushnil (L);
  3060. }
  3061. }
  3062. else {
  3063. return luaL_error (L, "invalid arguments");
  3064. }
  3065. return 1;
  3066. }
  3067. static gint
  3068. lua_task_set_user (lua_State *L)
  3069. {
  3070. LUA_TRACE_POINT;
  3071. struct rspamd_task *task = lua_check_task (L, 1);
  3072. const gchar *new_user;
  3073. if (task) {
  3074. if (lua_type (L, 2) == LUA_TSTRING) {
  3075. new_user = lua_tostring (L, 2);
  3076. if (task->user) {
  3077. /* Push old user */
  3078. lua_pushstring (L, task->user);
  3079. }
  3080. else {
  3081. lua_pushnil (L);
  3082. }
  3083. task->user = rspamd_mempool_strdup (task->task_pool, new_user);
  3084. }
  3085. else {
  3086. /* Reset user */
  3087. if (task->user) {
  3088. /* Push old user */
  3089. lua_pushstring (L, task->user);
  3090. }
  3091. else {
  3092. lua_pushnil (L);
  3093. }
  3094. task->user = NULL;
  3095. }
  3096. }
  3097. else {
  3098. return luaL_error (L, "invalid arguments");
  3099. }
  3100. return 1;
  3101. }
  3102. static gint
  3103. lua_task_get_from_ip (lua_State *L)
  3104. {
  3105. LUA_TRACE_POINT;
  3106. struct rspamd_task *task = lua_check_task (L, 1);
  3107. if (task) {
  3108. rspamd_lua_ip_push (L, task->from_addr);
  3109. }
  3110. else {
  3111. return luaL_error (L, "invalid arguments");
  3112. }
  3113. return 1;
  3114. }
  3115. static gint
  3116. lua_task_set_from_ip (lua_State *L)
  3117. {
  3118. LUA_TRACE_POINT;
  3119. struct rspamd_task *task = lua_check_task (L, 1);
  3120. const gchar *ip_str = luaL_checkstring (L, 2);
  3121. rspamd_inet_addr_t *addr = NULL;
  3122. if (!task || !ip_str) {
  3123. lua_pushstring (L, "invalid parameters");
  3124. return lua_error (L);
  3125. }
  3126. else {
  3127. if (!rspamd_parse_inet_address (&addr,
  3128. ip_str,
  3129. 0)) {
  3130. msg_warn_task ("cannot get IP from received header: '%s'",
  3131. ip_str);
  3132. }
  3133. else {
  3134. if (task->from_addr) {
  3135. rspamd_inet_address_free (task->from_addr);
  3136. }
  3137. task->from_addr = addr;
  3138. }
  3139. }
  3140. return 0;
  3141. }
  3142. static gint
  3143. lua_task_get_from_ip_num (lua_State *L)
  3144. {
  3145. LUA_TRACE_POINT;
  3146. msg_err ("this function is deprecated and should no longer be used");
  3147. lua_pushnil (L);
  3148. return 1;
  3149. }
  3150. static gint
  3151. lua_task_get_client_ip (lua_State *L)
  3152. {
  3153. LUA_TRACE_POINT;
  3154. struct rspamd_task *task = lua_check_task (L, 1);
  3155. if (task) {
  3156. rspamd_lua_ip_push (L, task->client_addr);
  3157. }
  3158. else {
  3159. return luaL_error (L, "invalid arguments");
  3160. }
  3161. return 1;
  3162. }
  3163. static gint
  3164. lua_task_get_helo (lua_State *L)
  3165. {
  3166. LUA_TRACE_POINT;
  3167. struct rspamd_task *task = lua_check_task (L, 1);
  3168. if (task) {
  3169. if (task->helo != NULL) {
  3170. lua_pushstring (L, task->helo);
  3171. return 1;
  3172. }
  3173. else {
  3174. lua_pushnil (L);
  3175. }
  3176. }
  3177. else {
  3178. return luaL_error (L, "invalid arguments");
  3179. }
  3180. return 1;
  3181. }
  3182. static gint
  3183. lua_task_get_subject (lua_State *L)
  3184. {
  3185. LUA_TRACE_POINT;
  3186. struct rspamd_task *task = lua_check_task (L, 1);
  3187. if (task) {
  3188. if (task->subject != NULL) {
  3189. lua_pushstring (L, task->subject);
  3190. return 1;
  3191. }
  3192. else {
  3193. lua_pushnil (L);
  3194. }
  3195. }
  3196. else {
  3197. return luaL_error (L, "invalid arguments");
  3198. }
  3199. return 1;
  3200. }
  3201. static gint
  3202. lua_task_set_helo (lua_State *L)
  3203. {
  3204. LUA_TRACE_POINT;
  3205. struct rspamd_task *task = lua_check_task (L, 1);
  3206. const gchar *new_helo;
  3207. if (task) {
  3208. new_helo = luaL_checkstring (L, 2);
  3209. if (new_helo) {
  3210. task->helo = rspamd_mempool_strdup (task->task_pool, new_helo);
  3211. }
  3212. }
  3213. else {
  3214. return luaL_error (L, "invalid arguments");
  3215. }
  3216. return 0;
  3217. }
  3218. static gint
  3219. lua_task_get_hostname (lua_State *L)
  3220. {
  3221. LUA_TRACE_POINT;
  3222. struct rspamd_task *task = lua_check_task (L, 1);
  3223. if (task) {
  3224. if (task->hostname != NULL) {
  3225. /* Check whether it looks like an IP address */
  3226. if (*task->hostname == '[') {
  3227. /*
  3228. * From the milter documentation:
  3229. * If the reverse lookup fails or if none of the IP
  3230. * addresses of the resolved host name matches the
  3231. * original IP address, hostname will contain the
  3232. * message sender's IP address enclosed in square
  3233. * brackets (e.g. `[a.b.c.d]')
  3234. */
  3235. lua_pushnil (L);
  3236. }
  3237. else {
  3238. lua_pushstring (L, task->hostname);
  3239. }
  3240. }
  3241. else {
  3242. lua_pushnil (L);
  3243. }
  3244. }
  3245. else {
  3246. return luaL_error (L, "invalid arguments");
  3247. }
  3248. return 1;
  3249. }
  3250. static gint
  3251. lua_task_set_hostname (lua_State *L)
  3252. {
  3253. LUA_TRACE_POINT;
  3254. struct rspamd_task *task = lua_check_task (L, 1);
  3255. const gchar *new_hostname;
  3256. if (task) {
  3257. new_hostname = luaL_checkstring (L, 2);
  3258. if (new_hostname) {
  3259. task->hostname = rspamd_mempool_strdup (task->task_pool,
  3260. new_hostname);
  3261. }
  3262. }
  3263. else {
  3264. return luaL_error (L, "invalid arguments");
  3265. }
  3266. return 0;
  3267. }
  3268. static gint
  3269. lua_task_get_images (lua_State *L)
  3270. {
  3271. LUA_TRACE_POINT;
  3272. struct rspamd_task *task = lua_check_task (L, 1);
  3273. guint nelt = 0, i;
  3274. struct rspamd_mime_part *part;
  3275. struct rspamd_image **pimg;
  3276. if (task) {
  3277. if (!lua_task_get_cached (L, task, "images", task->parts->len)) {
  3278. lua_createtable (L, task->parts->len, 0);
  3279. for (i = 0; i < task->parts->len; i ++) {
  3280. part = g_ptr_array_index (task->parts, i);
  3281. if (part->flags & RSPAMD_MIME_PART_IMAGE) {
  3282. pimg = lua_newuserdata (L, sizeof (struct rspamd_image *));
  3283. rspamd_lua_setclass (L, "rspamd{image}", -1);
  3284. *pimg = part->specific.img;
  3285. lua_rawseti (L, -2, ++nelt);
  3286. }
  3287. }
  3288. lua_task_set_cached (L, task, "images", -1, task->parts->len);
  3289. }
  3290. }
  3291. else {
  3292. return luaL_error (L, "invalid arguments");
  3293. }
  3294. return 1;
  3295. }
  3296. static gint
  3297. lua_task_get_archives (lua_State *L)
  3298. {
  3299. LUA_TRACE_POINT;
  3300. struct rspamd_task *task = lua_check_task (L, 1);
  3301. guint nelt = 0, i;
  3302. struct rspamd_mime_part *part;
  3303. struct rspamd_archive **parch;
  3304. if (task) {
  3305. if (!lua_task_get_cached (L, task, "archives", task->parts->len)) {
  3306. lua_createtable (L, task->parts->len, 0);
  3307. for (i = 0; i < task->parts->len; i ++) {
  3308. part = g_ptr_array_index (task->parts, i);
  3309. if (part->flags & RSPAMD_MIME_PART_ARCHIVE) {
  3310. parch = lua_newuserdata (L, sizeof (struct rspamd_archive *));
  3311. rspamd_lua_setclass (L, "rspamd{archive}", -1);
  3312. *parch = part->specific.arch;
  3313. lua_rawseti (L, -2, ++nelt);
  3314. }
  3315. }
  3316. lua_task_set_cached (L, task, "archives", -1, task->parts->len);
  3317. }
  3318. }
  3319. else {
  3320. return luaL_error (L, "invalid arguments");
  3321. }
  3322. return 1;
  3323. }
  3324. static gint
  3325. lua_task_get_dkim_results (lua_State *L)
  3326. {
  3327. LUA_TRACE_POINT;
  3328. struct rspamd_task *task = lua_check_task (L, 1);
  3329. guint nelt = 0, i;
  3330. struct rspamd_dkim_check_result **pres, **cur;
  3331. if (task) {
  3332. if (!lua_task_get_cached (L, task, "dkim_results", 0)) {
  3333. pres = rspamd_mempool_get_variable (task->task_pool,
  3334. RSPAMD_MEMPOOL_DKIM_CHECK_RESULTS);
  3335. if (pres == NULL) {
  3336. lua_newtable (L);
  3337. }
  3338. else {
  3339. for (cur = pres; *cur != NULL; cur ++) {
  3340. nelt ++;
  3341. }
  3342. lua_createtable (L, nelt, 0);
  3343. for (i = 0; i < nelt; i ++) {
  3344. struct rspamd_dkim_check_result *res = pres[i];
  3345. const gchar *result_str = "unknown";
  3346. lua_createtable (L, 0, 4);
  3347. switch (res->rcode) {
  3348. case DKIM_CONTINUE:
  3349. result_str = "allow";
  3350. break;
  3351. case DKIM_REJECT:
  3352. result_str = "reject";
  3353. break;
  3354. case DKIM_TRYAGAIN:
  3355. result_str = "tempfail";
  3356. break;
  3357. case DKIM_NOTFOUND:
  3358. result_str = "not found";
  3359. break;
  3360. case DKIM_RECORD_ERROR:
  3361. result_str = "bad record";
  3362. break;
  3363. case DKIM_PERM_ERROR:
  3364. result_str = "permanent error";
  3365. break;
  3366. default:
  3367. break;
  3368. }
  3369. rspamd_lua_table_set (L, "result", result_str);
  3370. if (res->domain) {
  3371. rspamd_lua_table_set (L, "domain", res->domain);
  3372. }
  3373. if (res->selector) {
  3374. rspamd_lua_table_set (L, "selector", res->selector);
  3375. }
  3376. if (res->short_b) {
  3377. rspamd_lua_table_set (L, "bhash", res->short_b);
  3378. }
  3379. if (res->fail_reason) {
  3380. rspamd_lua_table_set (L, "fail_reason", res->fail_reason);
  3381. }
  3382. lua_rawseti (L, -2, i + 1);
  3383. }
  3384. }
  3385. lua_task_set_cached (L, task, "dkim_results", -1, 0);
  3386. }
  3387. }
  3388. else {
  3389. return luaL_error (L, "invalid arguments");
  3390. }
  3391. return 1;
  3392. }
  3393. static inline gboolean
  3394. lua_push_symbol_result (lua_State *L,
  3395. struct rspamd_task *task,
  3396. const gchar *symbol,
  3397. struct rspamd_symbol_result *symbol_result,
  3398. gboolean add_metric,
  3399. gboolean add_name)
  3400. {
  3401. struct rspamd_metric_result *metric_res;
  3402. struct rspamd_symbol_result *s = NULL;
  3403. struct rspamd_symbol_option *opt;
  3404. struct rspamd_symbols_group *sym_group;
  3405. guint i;
  3406. gint j = 1, e = 4;
  3407. if (!symbol_result) {
  3408. metric_res = task->result;
  3409. if (metric_res) {
  3410. s = rspamd_task_find_symbol_result (task, symbol);
  3411. }
  3412. }
  3413. else {
  3414. s = symbol_result;
  3415. }
  3416. if (s) {
  3417. if (add_metric) {
  3418. e++;
  3419. }
  3420. if (add_name) {
  3421. e++;
  3422. }
  3423. lua_createtable (L, 0, e);
  3424. if (add_name) {
  3425. lua_pushstring (L, "name");
  3426. lua_pushstring (L, symbol);
  3427. lua_settable (L, -3);
  3428. }
  3429. lua_pushstring (L, "score");
  3430. lua_pushnumber (L, s->score);
  3431. lua_settable (L, -3);
  3432. if (s->sym && s->sym->gr) {
  3433. lua_pushstring (L, "group");
  3434. lua_pushstring (L, s->sym->gr->name);
  3435. lua_settable (L, -3);
  3436. lua_pushstring (L, "groups");
  3437. lua_createtable (L, s->sym->groups->len, 0);
  3438. PTR_ARRAY_FOREACH (s->sym->groups, i, sym_group) {
  3439. lua_pushstring (L, sym_group->name);
  3440. lua_rawseti (L, -2, i + 1);
  3441. }
  3442. lua_settable (L, -3);
  3443. }
  3444. else {
  3445. lua_pushstring (L, "group");
  3446. lua_pushstring (L, "ungrouped");
  3447. lua_settable (L, -3);
  3448. }
  3449. if (s->options) {
  3450. lua_pushstring (L, "options");
  3451. lua_createtable (L, kh_size (s->options), 0);
  3452. DL_FOREACH (s->opts_head, opt) {
  3453. lua_pushstring (L, (const char*)opt->option);
  3454. lua_rawseti (L, -2, j++);
  3455. }
  3456. lua_settable (L, -3);
  3457. }
  3458. return TRUE;
  3459. }
  3460. return FALSE;
  3461. }
  3462. static gint
  3463. lua_task_get_symbol (lua_State *L)
  3464. {
  3465. LUA_TRACE_POINT;
  3466. struct rspamd_task *task = lua_check_task (L, 1);
  3467. const gchar *symbol;
  3468. gboolean found = FALSE;
  3469. gint i = 1;
  3470. symbol = luaL_checkstring (L, 2);
  3471. if (task && symbol) {
  3472. lua_createtable (L, 1, 0);
  3473. if ((found = lua_push_symbol_result (L, task, symbol,
  3474. NULL, TRUE, FALSE))) {
  3475. lua_rawseti (L, -2, i++);
  3476. }
  3477. else {
  3478. /* Pop table */
  3479. lua_pop (L, 1);
  3480. }
  3481. }
  3482. else {
  3483. return luaL_error (L, "invalid arguments");
  3484. }
  3485. if (!found) {
  3486. lua_pushnil (L);
  3487. }
  3488. return 1;
  3489. }
  3490. static gint
  3491. lua_task_has_symbol (lua_State *L)
  3492. {
  3493. LUA_TRACE_POINT;
  3494. struct rspamd_task *task = lua_check_task (L, 1);
  3495. const gchar *symbol;
  3496. gboolean found = FALSE;
  3497. symbol = luaL_checkstring (L, 2);
  3498. if (task && symbol) {
  3499. found = (rspamd_task_find_symbol_result (task, symbol) != NULL);
  3500. lua_pushboolean (L, found);
  3501. }
  3502. else {
  3503. return luaL_error (L, "invalid arguments");
  3504. }
  3505. return 1;
  3506. }
  3507. static gint
  3508. lua_task_enable_symbol (lua_State *L)
  3509. {
  3510. LUA_TRACE_POINT;
  3511. struct rspamd_task *task = lua_check_task (L, 1);
  3512. const gchar *symbol;
  3513. gboolean found = FALSE;
  3514. symbol = luaL_checkstring (L, 2);
  3515. if (task && symbol) {
  3516. found = rspamd_symcache_enable_symbol (task, task->cfg->cache, symbol);
  3517. lua_pushboolean (L, found);
  3518. }
  3519. else {
  3520. return luaL_error (L, "invalid arguments");
  3521. }
  3522. return 1;
  3523. }
  3524. static gint
  3525. lua_task_disable_symbol (lua_State *L)
  3526. {
  3527. LUA_TRACE_POINT;
  3528. struct rspamd_task *task = lua_check_task (L, 1);
  3529. const gchar *symbol;
  3530. gboolean found = FALSE;
  3531. symbol = luaL_checkstring (L, 2);
  3532. if (task && symbol) {
  3533. found = rspamd_symcache_disable_symbol (task, task->cfg->cache, symbol);
  3534. lua_pushboolean (L, found);
  3535. }
  3536. else {
  3537. return luaL_error (L, "invalid arguments");
  3538. }
  3539. return 1;
  3540. }
  3541. static gint
  3542. lua_task_get_symbols (lua_State *L)
  3543. {
  3544. LUA_TRACE_POINT;
  3545. struct rspamd_task *task = lua_check_task (L, 1);
  3546. struct rspamd_metric_result *mres;
  3547. gint i = 1;
  3548. struct rspamd_symbol_result *s;
  3549. if (task) {
  3550. mres = task->result;
  3551. if (mres) {
  3552. lua_createtable (L, kh_size (mres->symbols), 0);
  3553. lua_createtable (L, kh_size (mres->symbols), 0);
  3554. kh_foreach_value_ptr (mres->symbols, s, {
  3555. if (!(s->flags & RSPAMD_SYMBOL_RESULT_IGNORED)) {
  3556. lua_pushstring (L, s->name);
  3557. lua_rawseti (L, -3, i);
  3558. lua_pushnumber (L, s->score);
  3559. lua_rawseti (L, -2, i);
  3560. i++;
  3561. }
  3562. });
  3563. }
  3564. else {
  3565. lua_createtable (L, 0, 0);
  3566. lua_createtable (L, 0, 0);
  3567. }
  3568. }
  3569. else {
  3570. return luaL_error (L, "invalid arguments");
  3571. }
  3572. return 2;
  3573. }
  3574. static gint
  3575. lua_task_get_symbols_all (lua_State *L)
  3576. {
  3577. LUA_TRACE_POINT;
  3578. struct rspamd_task *task = lua_check_task (L, 1);
  3579. struct rspamd_metric_result *mres;
  3580. struct rspamd_symbol_result *s;
  3581. gboolean found = FALSE;
  3582. gint i = 1;
  3583. if (task) {
  3584. mres = task->result;
  3585. if (mres) {
  3586. found = TRUE;
  3587. lua_createtable (L, kh_size (mres->symbols), 0);
  3588. kh_foreach_value_ptr (mres->symbols, s, {
  3589. lua_push_symbol_result (L, task, s->name, s, FALSE, TRUE);
  3590. lua_rawseti (L, -2, i++);
  3591. });
  3592. }
  3593. }
  3594. else {
  3595. return luaL_error (L, "invalid arguments");
  3596. }
  3597. if (!found) {
  3598. lua_pushnil (L);
  3599. }
  3600. return 1;
  3601. }
  3602. static gint
  3603. lua_task_get_symbols_numeric (lua_State *L)
  3604. {
  3605. LUA_TRACE_POINT;
  3606. struct rspamd_task *task = lua_check_task (L, 1);
  3607. struct rspamd_metric_result *mres;
  3608. gint i = 1, id;
  3609. struct rspamd_symbol_result *s;
  3610. if (task) {
  3611. mres = task->result;
  3612. if (mres) {
  3613. lua_createtable (L, kh_size (mres->symbols), 0);
  3614. lua_createtable (L, kh_size (mres->symbols), 0);
  3615. lua_createtable (L, kh_size (mres->symbols), 0);
  3616. kh_foreach_value_ptr (mres->symbols, s, {
  3617. if (!(s->flags & RSPAMD_SYMBOL_RESULT_IGNORED)) {
  3618. id = rspamd_symcache_find_symbol (task->cfg->cache,
  3619. s->name);
  3620. lua_pushinteger (L, id);
  3621. lua_rawseti (L, -3, i);
  3622. lua_pushnumber (L, s->score);
  3623. lua_rawseti (L, -2, i);
  3624. i++;
  3625. }
  3626. });
  3627. }
  3628. else {
  3629. lua_createtable (L, 0, 0);
  3630. lua_createtable (L, 0, 0);
  3631. }
  3632. }
  3633. else {
  3634. return luaL_error (L, "invalid arguments");
  3635. }
  3636. return 2;
  3637. }
  3638. struct tokens_foreach_cbdata {
  3639. struct rspamd_task *task;
  3640. lua_State *L;
  3641. gint idx;
  3642. gboolean normalize;
  3643. };
  3644. static void
  3645. tokens_foreach_cb (gint id, const gchar *sym, gint flags, gpointer ud)
  3646. {
  3647. struct tokens_foreach_cbdata *cbd = ud;
  3648. struct rspamd_symbol_result *s;
  3649. if (flags & SYMBOL_TYPE_NOSTAT) {
  3650. return;
  3651. }
  3652. if ((s = rspamd_task_find_symbol_result (cbd->task, sym)) != NULL) {
  3653. if (cbd->normalize) {
  3654. lua_pushnumber (cbd->L, tanh (s->score));
  3655. }
  3656. else {
  3657. lua_pushnumber (cbd->L, s->score);
  3658. }
  3659. }
  3660. else {
  3661. lua_pushnumber (cbd->L, 0.0);
  3662. }
  3663. lua_rawseti (cbd->L, -2, cbd->idx++);
  3664. }
  3665. static gint
  3666. lua_task_get_symbols_tokens (lua_State *L)
  3667. {
  3668. LUA_TRACE_POINT;
  3669. struct rspamd_task *task = lua_check_task (L, 1);
  3670. struct tokens_foreach_cbdata cbd;
  3671. cbd.task = task;
  3672. cbd.L = L;
  3673. cbd.idx = 1;
  3674. cbd.normalize = TRUE;
  3675. if (lua_type (L, 2) == LUA_TBOOLEAN) {
  3676. cbd.normalize = lua_toboolean (L, 2);
  3677. }
  3678. else {
  3679. cbd.normalize = TRUE;
  3680. }
  3681. lua_createtable (L,
  3682. rspamd_symcache_stats_symbols_count (task->cfg->cache), 0);
  3683. rspamd_symcache_foreach (task->cfg->cache, tokens_foreach_cb, &cbd);
  3684. return 1;
  3685. }
  3686. enum lua_date_type {
  3687. DATE_CONNECT = 0,
  3688. DATE_MESSAGE,
  3689. DATE_CONNECT_STRING,
  3690. DATE_MESSAGE_STRING
  3691. };
  3692. static enum lua_date_type
  3693. lua_task_detect_date_type (struct rspamd_task *task,
  3694. lua_State *L, gint idx, gboolean *gmt)
  3695. {
  3696. enum lua_date_type type = DATE_CONNECT;
  3697. if (lua_type (L, idx) == LUA_TNUMBER) {
  3698. gint num = lua_tonumber (L, idx);
  3699. if (num >= DATE_CONNECT && num <= DATE_MESSAGE_STRING) {
  3700. return num;
  3701. }
  3702. }
  3703. else if (lua_type (L, idx) == LUA_TTABLE) {
  3704. const gchar *str;
  3705. lua_pushvalue (L, idx);
  3706. lua_pushstring (L, "format");
  3707. lua_gettable (L, -2);
  3708. str = lua_tostring (L, -1);
  3709. if (str) {
  3710. if (g_ascii_strcasecmp (str, "message") == 0) {
  3711. type = DATE_MESSAGE;
  3712. } else if (g_ascii_strcasecmp (str, "connect_str") == 0) {
  3713. type = DATE_CONNECT_STRING;
  3714. } else if (g_ascii_strcasecmp (str, "message_str") == 0) {
  3715. type = DATE_MESSAGE_STRING;
  3716. }
  3717. }
  3718. else {
  3719. msg_warn_task ("date format has not been specified");
  3720. }
  3721. lua_pop (L, 1);
  3722. lua_pushstring (L, "gmt");
  3723. lua_gettable (L, -2);
  3724. if (lua_type (L, -1) == LUA_TBOOLEAN) {
  3725. *gmt = lua_toboolean (L, -1);
  3726. }
  3727. /* Value and table */
  3728. lua_pop (L, 2);
  3729. }
  3730. return type;
  3731. }
  3732. static gint
  3733. lua_task_get_date (lua_State *L)
  3734. {
  3735. LUA_TRACE_POINT;
  3736. struct rspamd_task *task = lua_check_task (L, 1);
  3737. GPtrArray *hdrs;
  3738. gdouble tim;
  3739. enum lua_date_type type = DATE_CONNECT;
  3740. gboolean gmt = TRUE;
  3741. if (task != NULL) {
  3742. if (lua_gettop (L) > 1) {
  3743. type = lua_task_detect_date_type (task, L, 2, &gmt);
  3744. }
  3745. /* Get GMT date and store it to time_t */
  3746. if (type == DATE_CONNECT || type == DATE_CONNECT_STRING) {
  3747. tim = (tv_to_msec (&task->tv)) / 1000.;
  3748. if (!gmt) {
  3749. struct tm t;
  3750. time_t tt;
  3751. tt = tim;
  3752. rspamd_localtime (tt, &t);
  3753. #if !defined(__sun)
  3754. t.tm_gmtoff = 0;
  3755. #endif
  3756. t.tm_isdst = 0;
  3757. tim = mktime (&t);
  3758. }
  3759. }
  3760. else {
  3761. hdrs = rspamd_message_get_header_array (task, "Date",
  3762. FALSE);
  3763. if (hdrs && hdrs->len > 0) {
  3764. time_t tt;
  3765. struct tm t;
  3766. struct rspamd_mime_header *h;
  3767. h = g_ptr_array_index (hdrs, 0);
  3768. tt = rspamd_parse_smtp_date (h->decoded, strlen (h->decoded));
  3769. if (!gmt) {
  3770. rspamd_localtime (tt, &t);
  3771. #if !defined(__sun)
  3772. t.tm_gmtoff = 0;
  3773. #endif
  3774. t.tm_isdst = 0;
  3775. tim = mktime (&t);
  3776. }
  3777. else {
  3778. tim = tt;
  3779. }
  3780. }
  3781. else {
  3782. tim = 0.0;
  3783. }
  3784. }
  3785. if (type == DATE_CONNECT || type == DATE_MESSAGE) {
  3786. lua_pushnumber (L, tim);
  3787. }
  3788. else {
  3789. GTimeVal tv;
  3790. gchar *out;
  3791. double_to_tv (tim, &tv);
  3792. out = g_time_val_to_iso8601 (&tv);
  3793. lua_pushstring (L, out);
  3794. g_free (out);
  3795. }
  3796. }
  3797. else {
  3798. return luaL_error (L, "invalid arguments");
  3799. }
  3800. return 1;
  3801. }
  3802. static gint
  3803. lua_task_get_message_id (lua_State *L)
  3804. {
  3805. LUA_TRACE_POINT;
  3806. struct rspamd_task *task = lua_check_task (L, 1);
  3807. if (task != NULL) {
  3808. if (task->message_id != NULL) {
  3809. lua_pushstring (L, task->message_id);
  3810. }
  3811. else {
  3812. lua_pushnil (L);
  3813. }
  3814. }
  3815. else {
  3816. return luaL_error (L, "invalid arguments");
  3817. }
  3818. return 1;
  3819. }
  3820. static gint
  3821. lua_task_get_timeval (lua_State *L)
  3822. {
  3823. LUA_TRACE_POINT;
  3824. struct rspamd_task *task = lua_check_task (L, 1);
  3825. if (task != NULL) {
  3826. lua_createtable (L, 0, 2);
  3827. lua_pushstring (L, "tv_sec");
  3828. lua_pushinteger (L, (lua_Integer)task->tv.tv_sec);
  3829. lua_settable (L, -3);
  3830. lua_pushstring (L, "tv_usec");
  3831. lua_pushinteger (L, (lua_Integer)task->tv.tv_usec);
  3832. lua_settable (L, -3);
  3833. }
  3834. else {
  3835. return luaL_error (L, "invalid arguments");
  3836. }
  3837. return 1;
  3838. }
  3839. static gint
  3840. lua_task_get_size (lua_State *L)
  3841. {
  3842. LUA_TRACE_POINT;
  3843. struct rspamd_task *task = lua_check_task (L, 1);
  3844. if (task != NULL) {
  3845. lua_pushinteger (L, task->msg.len);
  3846. }
  3847. else {
  3848. return luaL_error (L, "invalid arguments");
  3849. }
  3850. return 1;
  3851. }
  3852. /**
  3853. * - `no_log`: do not log task summary
  3854. * - `no_stat`: do not include task into scanned stats
  3855. * - `pass_all`: check all filters for task
  3856. * - `extended_urls`: output extended info about urls
  3857. * - `skip`: skip task processing
  3858. */
  3859. #define LUA_TASK_FLAG_WRITE(flag, set) do { \
  3860. task->flags = (set) ? (task->flags | (flag)) : (task->flags & ~(flag)); \
  3861. } while(0)
  3862. #define LUA_TASK_SET_FLAG(flag, strname, macro, set) do { \
  3863. if (!found && strcmp ((flag), strname) == 0) { \
  3864. LUA_TASK_FLAG_WRITE((macro), set); \
  3865. found = TRUE; \
  3866. } \
  3867. } while(0)
  3868. #define LUA_TASK_FLAG_READ(flag) do { \
  3869. lua_pushboolean(L, !!(task->flags & (flag))); \
  3870. } while(0)
  3871. #define LUA_TASK_GET_FLAG(flag, strname, macro) do { \
  3872. if (!found && strcmp ((flag), strname) == 0) { \
  3873. LUA_TASK_FLAG_READ((macro)); \
  3874. found = TRUE; \
  3875. } \
  3876. } while(0)
  3877. static gint
  3878. lua_task_set_flag (lua_State *L)
  3879. {
  3880. LUA_TRACE_POINT;
  3881. struct rspamd_task *task = lua_check_task (L, 1);
  3882. const gchar *flag = luaL_checkstring (L, 2);
  3883. gboolean set = TRUE, found = FALSE;
  3884. if (lua_gettop (L) >= 3) {
  3885. set = lua_toboolean (L, 3);
  3886. }
  3887. if (task != NULL && flag != NULL) {
  3888. LUA_TASK_SET_FLAG (flag, "pass_all", RSPAMD_TASK_FLAG_PASS_ALL, set);
  3889. LUA_TASK_SET_FLAG (flag, "no_log", RSPAMD_TASK_FLAG_NO_LOG, set);
  3890. LUA_TASK_SET_FLAG (flag, "no_stat", RSPAMD_TASK_FLAG_NO_STAT, set);
  3891. LUA_TASK_SET_FLAG (flag, "skip", RSPAMD_TASK_FLAG_SKIP, set);
  3892. LUA_TASK_SET_FLAG (flag, "extended_urls", RSPAMD_TASK_FLAG_EXT_URLS, set);
  3893. LUA_TASK_SET_FLAG (flag, "learn_spam", RSPAMD_TASK_FLAG_LEARN_SPAM, set);
  3894. LUA_TASK_SET_FLAG (flag, "learn_ham", RSPAMD_TASK_FLAG_LEARN_HAM, set);
  3895. LUA_TASK_SET_FLAG (flag, "broken_headers",
  3896. RSPAMD_TASK_FLAG_BROKEN_HEADERS, set);
  3897. LUA_TASK_SET_FLAG (flag, "greylisted", RSPAMD_TASK_FLAG_GREYLISTED, set);
  3898. LUA_TASK_SET_FLAG (flag, "skip_process", RSPAMD_TASK_FLAG_SKIP_PROCESS, set);
  3899. if (!found) {
  3900. msg_warn_task ("unknown flag requested: %s", flag);
  3901. }
  3902. }
  3903. else {
  3904. return luaL_error (L, "invalid arguments");
  3905. }
  3906. return 0;
  3907. }
  3908. static gint
  3909. lua_task_has_flag (lua_State *L)
  3910. {
  3911. LUA_TRACE_POINT;
  3912. struct rspamd_task *task = lua_check_task (L, 1);
  3913. const gchar *flag = luaL_checkstring (L, 2);
  3914. gboolean found = FALSE;
  3915. if (task != NULL && flag != NULL) {
  3916. LUA_TASK_GET_FLAG (flag, "pass_all", RSPAMD_TASK_FLAG_PASS_ALL);
  3917. LUA_TASK_GET_FLAG (flag, "no_log", RSPAMD_TASK_FLAG_NO_LOG);
  3918. LUA_TASK_GET_FLAG (flag, "no_stat", RSPAMD_TASK_FLAG_NO_STAT);
  3919. LUA_TASK_GET_FLAG (flag, "skip", RSPAMD_TASK_FLAG_SKIP);
  3920. LUA_TASK_GET_FLAG (flag, "extended_urls", RSPAMD_TASK_FLAG_EXT_URLS);
  3921. LUA_TASK_GET_FLAG (flag, "learn_spam", RSPAMD_TASK_FLAG_LEARN_SPAM);
  3922. LUA_TASK_GET_FLAG (flag, "learn_ham", RSPAMD_TASK_FLAG_LEARN_HAM);
  3923. LUA_TASK_GET_FLAG (flag, "greylisted", RSPAMD_TASK_FLAG_GREYLISTED);
  3924. LUA_TASK_GET_FLAG (flag, "broken_headers",
  3925. RSPAMD_TASK_FLAG_BROKEN_HEADERS);
  3926. LUA_TASK_GET_FLAG (flag, "skip_process",
  3927. RSPAMD_TASK_FLAG_SKIP_PROCESS);
  3928. LUA_TASK_GET_FLAG (flag, "milter",
  3929. RSPAMD_TASK_FLAG_MILTER);
  3930. LUA_TASK_GET_FLAG (flag, "bad_unicode",
  3931. RSPAMD_TASK_FLAG_BAD_UNICODE);
  3932. LUA_TASK_GET_FLAG (flag, "mime",
  3933. RSPAMD_TASK_FLAG_MIME);
  3934. if (!found) {
  3935. msg_warn_task ("unknown flag requested: %s", flag);
  3936. lua_pushboolean (L, 0);
  3937. }
  3938. }
  3939. else {
  3940. return luaL_error (L, "invalid arguments");
  3941. }
  3942. return 1;
  3943. }
  3944. static gint
  3945. lua_task_get_flags (lua_State *L)
  3946. {
  3947. LUA_TRACE_POINT;
  3948. struct rspamd_task *task = lua_check_task (L, 1);
  3949. gint idx = 1;
  3950. guint flags, bit, i;
  3951. if (task) {
  3952. lua_createtable (L, 8, 0);
  3953. flags = task->flags;
  3954. for (i = 0; i < sizeof (task->flags) * NBBY; i ++) {
  3955. bit = (1U << i);
  3956. if (flags & bit) {
  3957. switch (bit) {
  3958. case RSPAMD_TASK_FLAG_PASS_ALL:
  3959. lua_pushstring (L, "pass_all");
  3960. lua_rawseti (L, -2, idx ++);
  3961. break;
  3962. case RSPAMD_TASK_FLAG_NO_LOG:
  3963. lua_pushstring (L, "no_log");
  3964. lua_rawseti (L, -2, idx++);
  3965. break;
  3966. case RSPAMD_TASK_FLAG_NO_STAT:
  3967. lua_pushstring (L, "no_stat");
  3968. lua_rawseti (L, -2, idx++);
  3969. break;
  3970. case RSPAMD_TASK_FLAG_SKIP:
  3971. lua_pushstring (L, "skip");
  3972. lua_rawseti (L, -2, idx++);
  3973. break;
  3974. case RSPAMD_TASK_FLAG_EXT_URLS:
  3975. lua_pushstring (L, "extended_urls");
  3976. lua_rawseti (L, -2, idx++);
  3977. break;
  3978. case RSPAMD_TASK_FLAG_BROKEN_HEADERS:
  3979. lua_pushstring (L, "broken_headers");
  3980. lua_rawseti (L, -2, idx++);
  3981. break;
  3982. case RSPAMD_TASK_FLAG_LEARN_SPAM:
  3983. lua_pushstring (L, "learn_spam");
  3984. lua_rawseti (L, -2, idx++);
  3985. break;
  3986. case RSPAMD_TASK_FLAG_LEARN_HAM:
  3987. lua_pushstring (L, "learn_ham");
  3988. lua_rawseti (L, -2, idx++);
  3989. break;
  3990. case RSPAMD_TASK_FLAG_GREYLISTED:
  3991. lua_pushstring (L, "greylisted");
  3992. lua_rawseti (L, -2, idx++);
  3993. break;
  3994. case RSPAMD_TASK_FLAG_SKIP_PROCESS:
  3995. lua_pushstring (L, "skip_process");
  3996. lua_rawseti (L, -2, idx++);
  3997. break;
  3998. case RSPAMD_TASK_FLAG_MILTER:
  3999. lua_pushstring (L, "milter");
  4000. lua_rawseti (L, -2, idx++);
  4001. break;
  4002. default:
  4003. break;
  4004. }
  4005. }
  4006. }
  4007. }
  4008. else {
  4009. return luaL_error (L, "invalid arguments");
  4010. }
  4011. return 1;
  4012. }
  4013. static gint
  4014. lua_task_get_digest (lua_State *L)
  4015. {
  4016. LUA_TRACE_POINT;
  4017. struct rspamd_task *task = lua_check_task (L, 1);
  4018. gchar hexbuf[33];
  4019. gint r;
  4020. if (task) {
  4021. r = rspamd_encode_hex_buf (task->digest, sizeof (task->digest),
  4022. hexbuf, sizeof (hexbuf) - 1);
  4023. if (r > 0) {
  4024. hexbuf[r] = '\0';
  4025. lua_pushstring (L, hexbuf);
  4026. }
  4027. else {
  4028. lua_pushnil (L);
  4029. }
  4030. }
  4031. else {
  4032. return luaL_error (L, "invalid arguments");
  4033. }
  4034. return 1;
  4035. }
  4036. static gint
  4037. lua_task_learn (lua_State *L)
  4038. {
  4039. LUA_TRACE_POINT;
  4040. struct rspamd_task *task = lua_check_task (L, 1);
  4041. gboolean is_spam = FALSE;
  4042. const gchar *clname = NULL;
  4043. GError *err = NULL;
  4044. int ret = 1;
  4045. if (task == NULL) {
  4046. return luaL_error (L, "invalid arguments");
  4047. }
  4048. is_spam = lua_toboolean(L, 2);
  4049. if (lua_gettop (L) > 2) {
  4050. clname = luaL_checkstring (L, 3);
  4051. }
  4052. if (!rspamd_learn_task_spam (task, is_spam, clname, &err)) {
  4053. lua_pushboolean (L, FALSE);
  4054. if (err != NULL) {
  4055. lua_pushstring (L, err->message);
  4056. ret = 2;
  4057. }
  4058. }
  4059. else {
  4060. lua_pushboolean (L, TRUE);
  4061. }
  4062. return ret;
  4063. }
  4064. static gint
  4065. lua_task_set_settings (lua_State *L)
  4066. {
  4067. LUA_TRACE_POINT;
  4068. struct rspamd_task *task = lua_check_task (L, 1);
  4069. ucl_object_t *settings;
  4070. const ucl_object_t *act, *elt, *metric_elt, *vars, *cur;
  4071. ucl_object_iter_t it = NULL;
  4072. struct rspamd_metric_result *mres;
  4073. guint i;
  4074. settings = ucl_object_lua_import (L, 2);
  4075. if (settings != NULL && task != NULL) {
  4076. metric_elt = ucl_object_lookup (settings, DEFAULT_METRIC);
  4077. if (metric_elt) {
  4078. task->settings = ucl_object_ref (metric_elt);
  4079. ucl_object_unref (settings);
  4080. }
  4081. else {
  4082. task->settings = settings;
  4083. }
  4084. act = ucl_object_lookup (task->settings, "actions");
  4085. if (act) {
  4086. /* Adjust desired actions */
  4087. mres = task->result;
  4088. for (i = 0; i < mres->nactions; i++) {
  4089. struct rspamd_action_result *act_res = &mres->actions_limits[i];
  4090. elt = ucl_object_lookup (act, act_res->action->name);
  4091. if (elt) {
  4092. if (ucl_object_type (elt) == UCL_FLOAT ||
  4093. ucl_object_type (elt) == UCL_INT) {
  4094. gdouble nscore = ucl_object_todouble (elt);
  4095. msg_debug_task ("adjusted action %s: %.2f -> %.2f",
  4096. ucl_object_key (elt),
  4097. act_res->cur_limit,
  4098. nscore);
  4099. act_res->cur_limit = nscore;
  4100. }
  4101. else if (ucl_object_type (elt) == UCL_NULL) {
  4102. act_res->cur_limit = NAN;
  4103. msg_info_task ("disabled action %s due to settings",
  4104. ucl_object_key (elt));
  4105. }
  4106. }
  4107. }
  4108. }
  4109. vars = ucl_object_lookup (task->settings, "variables");
  4110. if (vars && ucl_object_type (vars) == UCL_OBJECT) {
  4111. /* Set memory pool variables */
  4112. it = NULL;
  4113. while ((cur = ucl_object_iterate (vars, &it, true)) != NULL) {
  4114. if (ucl_object_type (cur) == UCL_STRING) {
  4115. rspamd_mempool_set_variable (task->task_pool,
  4116. ucl_object_key (cur), rspamd_mempool_strdup (
  4117. task->task_pool,
  4118. ucl_object_tostring (cur)
  4119. ), NULL);
  4120. }
  4121. }
  4122. }
  4123. rspamd_symcache_process_settings (task, task->cfg->cache);
  4124. }
  4125. else {
  4126. return luaL_error (L, "invalid arguments");
  4127. }
  4128. return 0;
  4129. }
  4130. static gint
  4131. lua_task_set_milter_reply (lua_State *L)
  4132. {
  4133. LUA_TRACE_POINT;
  4134. struct rspamd_task *task = lua_check_task (L, 1);
  4135. ucl_object_t *reply, *prev;
  4136. reply = ucl_object_lua_import (L, 2);
  4137. if (reply != NULL && task != NULL) {
  4138. prev = rspamd_mempool_get_variable (task->task_pool,
  4139. RSPAMD_MEMPOOL_MILTER_REPLY);
  4140. if (prev) {
  4141. ucl_object_merge (prev, reply, false);
  4142. ucl_object_unref (reply);
  4143. }
  4144. else {
  4145. rspamd_mempool_set_variable (task->task_pool,
  4146. RSPAMD_MEMPOOL_MILTER_REPLY,
  4147. reply, (rspamd_mempool_destruct_t) ucl_object_unref);
  4148. }
  4149. }
  4150. else {
  4151. return luaL_error (L, "invalid arguments");
  4152. }
  4153. return 0;
  4154. }
  4155. static gint
  4156. lua_task_get_settings (lua_State *L)
  4157. {
  4158. LUA_TRACE_POINT;
  4159. struct rspamd_task *task = lua_check_task (L, 1);
  4160. if (task != NULL) {
  4161. if (task->settings) {
  4162. return ucl_object_push_lua (L, task->settings, true);
  4163. }
  4164. else {
  4165. lua_pushnil (L);
  4166. }
  4167. }
  4168. else {
  4169. return luaL_error (L, "invalid arguments");
  4170. }
  4171. return 1;
  4172. }
  4173. static gint
  4174. lua_task_lookup_settings (lua_State *L)
  4175. {
  4176. LUA_TRACE_POINT;
  4177. struct rspamd_task *task = lua_check_task (L, 1);
  4178. const gchar *key = NULL;
  4179. const ucl_object_t *elt;
  4180. if (task != NULL) {
  4181. if (lua_isstring (L, 2)) {
  4182. key = lua_tostring (L, 2);
  4183. }
  4184. if (task->settings) {
  4185. if (key == NULL) {
  4186. return ucl_object_push_lua (L, task->settings, true);
  4187. }
  4188. else {
  4189. elt = ucl_object_lookup (task->settings, key);
  4190. if (elt) {
  4191. return ucl_object_push_lua (L, elt, true);
  4192. }
  4193. else {
  4194. lua_pushnil (L);
  4195. }
  4196. }
  4197. }
  4198. else {
  4199. lua_pushnil (L);
  4200. }
  4201. }
  4202. else {
  4203. return luaL_error (L, "invalid arguments");
  4204. }
  4205. return 1;
  4206. }
  4207. static gint
  4208. lua_task_get_settings_id (lua_State *L)
  4209. {
  4210. LUA_TRACE_POINT;
  4211. struct rspamd_task *task = lua_check_task (L, 1);
  4212. guint32 *hp;
  4213. if (task != NULL) {
  4214. hp = rspamd_mempool_get_variable (task->task_pool, "settings_hash");
  4215. if (hp) {
  4216. lua_pushnumber (L, *hp);
  4217. }
  4218. else {
  4219. lua_pushnil (L);
  4220. }
  4221. }
  4222. else {
  4223. return luaL_error (L, "invalid arguments");
  4224. }
  4225. return 1;
  4226. }
  4227. static gint
  4228. lua_task_cache_get (lua_State *L)
  4229. {
  4230. LUA_TRACE_POINT;
  4231. struct rspamd_task *task = lua_check_task (L, 1);
  4232. const gchar *key = luaL_checkstring (L, 2);
  4233. guint id = 0;
  4234. if (task && key) {
  4235. if (lua_type (L, 3) == LUA_TNUMBER) {
  4236. id = lua_tonumber (L, 3);
  4237. }
  4238. if (!lua_task_get_cached (L, task, key, id)) {
  4239. lua_pushnil (L);
  4240. }
  4241. }
  4242. else {
  4243. luaL_error (L, "invalid arguments");
  4244. }
  4245. return 1;
  4246. }
  4247. static gint
  4248. lua_task_cache_set (lua_State *L)
  4249. {
  4250. LUA_TRACE_POINT;
  4251. struct rspamd_task *task = lua_check_task (L, 1);
  4252. const gchar *key = luaL_checkstring (L, 2);
  4253. guint id = 0;
  4254. if (task && key && lua_gettop (L) >= 3) {
  4255. if (lua_type (L, 4) == LUA_TNUMBER) {
  4256. id = lua_tonumber (L, 4);
  4257. }
  4258. lua_task_set_cached (L, task, key, 3, id);
  4259. }
  4260. else {
  4261. luaL_error (L, "invalid arguments");
  4262. }
  4263. return 0;
  4264. }
  4265. struct lua_file_cbdata {
  4266. gchar *fname;
  4267. gint fd;
  4268. gboolean keep;
  4269. };
  4270. static void
  4271. lua_tmp_file_dtor (gpointer p)
  4272. {
  4273. struct lua_file_cbdata *cbdata = p;
  4274. if (!cbdata->keep) {
  4275. unlink (cbdata->fname);
  4276. }
  4277. close (cbdata->fd);
  4278. }
  4279. static gint
  4280. lua_task_store_in_file (lua_State *L)
  4281. {
  4282. LUA_TRACE_POINT;
  4283. struct rspamd_task *task = lua_check_task (L, 1);
  4284. gboolean force_new = FALSE, keep = FALSE;
  4285. gchar fpath[PATH_MAX];
  4286. const gchar *tmpmask = NULL, *fname = NULL;
  4287. guint64 mode = 00600;
  4288. gint fd;
  4289. struct lua_file_cbdata *cbdata;
  4290. GError *err = NULL;
  4291. if (task) {
  4292. if (lua_istable (L, 2)) {
  4293. if (!rspamd_lua_parse_table_arguments (L, 2, &err,
  4294. "filename=S;tmpmask=S;mode=I;force_new=B;keep=B",
  4295. &fname, &tmpmask, &mode, &force_new, &keep)) {
  4296. msg_err_task ("cannot get parameters list: %e", err);
  4297. if (err) {
  4298. g_error_free (err);
  4299. }
  4300. return luaL_error (L, "invalid arguments");
  4301. }
  4302. }
  4303. else if (lua_isnumber (L, 2)) {
  4304. mode = lua_tonumber (L, 2);
  4305. }
  4306. if (!force_new && (task->flags & RSPAMD_TASK_FLAG_FILE) &&
  4307. task->msg.fpath) {
  4308. lua_pushstring (L, task->msg.fpath);
  4309. }
  4310. else {
  4311. if (fname == NULL) {
  4312. if (tmpmask == NULL) {
  4313. rspamd_snprintf (fpath, sizeof (fpath), "%s%c%s",
  4314. task->cfg->temp_dir,
  4315. G_DIR_SEPARATOR, "rmsg-XXXXXXXXXX");
  4316. }
  4317. else {
  4318. rspamd_snprintf (fpath, sizeof (fpath), "%s", tmpmask);
  4319. }
  4320. fd = mkstemp (fpath);
  4321. fname = fpath;
  4322. if (fd != -1) {
  4323. fchmod (fd, mode);
  4324. }
  4325. }
  4326. else {
  4327. fd = rspamd_file_xopen (fname, O_WRONLY|O_CREAT|O_EXCL,
  4328. (guint)mode, FALSE);
  4329. }
  4330. if (fd == -1) {
  4331. msg_err_task ("cannot save file: %s", strerror (errno));
  4332. lua_pushnil (L);
  4333. }
  4334. else {
  4335. if (write (fd, task->msg.begin, task->msg.len) == -1) {
  4336. msg_err_task ("cannot write file %s: %s", fpath,
  4337. strerror (errno));
  4338. unlink (fname);
  4339. close (fd);
  4340. lua_pushnil (L);
  4341. return 1;
  4342. }
  4343. cbdata = rspamd_mempool_alloc (task->task_pool, sizeof (*cbdata));
  4344. cbdata->fd = fd;
  4345. cbdata->fname = rspamd_mempool_strdup (task->task_pool, fname);
  4346. cbdata->keep = keep;
  4347. lua_pushstring (L, cbdata->fname);
  4348. rspamd_mempool_add_destructor (task->task_pool,
  4349. lua_tmp_file_dtor, cbdata);
  4350. }
  4351. }
  4352. }
  4353. else {
  4354. luaL_error (L, "invalid arguments");
  4355. }
  4356. return 1;
  4357. }
  4358. static gint
  4359. lua_task_process_regexp (lua_State *L)
  4360. {
  4361. LUA_TRACE_POINT;
  4362. struct rspamd_task *task = lua_check_task (L, 1);
  4363. struct rspamd_lua_regexp *re = NULL;
  4364. gboolean strong = FALSE;
  4365. const gchar *type_str = NULL, *header_str = NULL;
  4366. gsize header_len = 0;
  4367. GError *err = NULL;
  4368. gint ret = 0;
  4369. enum rspamd_re_type type = RSPAMD_RE_BODY;
  4370. /*
  4371. * - `re`* : regular expression object
  4372. * - `type`*: type of regular expression:
  4373. * + `mime`: mime regexp
  4374. * + `rawmime`: raw mime regexp
  4375. * + `header`: header regexp
  4376. * + `rawheader`: raw header expression
  4377. * + `body`: raw body regexp
  4378. * + `url`: url regexp
  4379. * - `header`: for header and rawheader regexp means the name of header
  4380. * - `strong`: case sensitive match for headers
  4381. */
  4382. if (task != NULL) {
  4383. if (!rspamd_lua_parse_table_arguments (L, 2, &err,
  4384. "*re=U{regexp};*type=S;header=V;strong=B",
  4385. &re, &type_str, &header_len, &header_str,
  4386. &strong)) {
  4387. msg_err_task ("cannot get parameters list: %e", err);
  4388. if (err) {
  4389. g_error_free (err);
  4390. }
  4391. return luaL_error (L, "invalid arguments");
  4392. }
  4393. else {
  4394. type = rspamd_re_cache_type_from_string (type_str);
  4395. if ((type == RSPAMD_RE_HEADER || type == RSPAMD_RE_RAWHEADER)
  4396. && header_str == NULL) {
  4397. msg_err_task (
  4398. "header argument is mandatory for header/rawheader regexps");
  4399. }
  4400. else {
  4401. ret = rspamd_re_cache_process (task, re->re, type,
  4402. (gpointer) header_str, header_len, strong);
  4403. }
  4404. }
  4405. }
  4406. else {
  4407. return luaL_error (L, "invalid arguments");
  4408. }
  4409. lua_pushinteger (L, ret);
  4410. return 1;
  4411. }
  4412. static gint
  4413. lua_task_get_metric_result (lua_State *L)
  4414. {
  4415. LUA_TRACE_POINT;
  4416. struct rspamd_task *task = lua_check_task (L, 1);
  4417. struct rspamd_metric_result *metric_res;
  4418. struct rspamd_action *action;
  4419. if (task) {
  4420. metric_res = task->result;
  4421. /* Fields added:
  4422. * - `score`: current score
  4423. * - `action`: current action as a string
  4424. * - `nnegative`: number of negative rules matched
  4425. * - `npositive`: number of positive rules matched
  4426. * - `positive_score`: total score for positive rules
  4427. * - `negative_score`: total score for negative rules
  4428. * - `passthrough`: set to true if message has a passthrough result
  4429. */
  4430. lua_createtable (L, 0, 7);
  4431. lua_pushstring (L, "score");
  4432. lua_pushnumber (L, metric_res->score);
  4433. lua_settable (L, -3);
  4434. action = rspamd_check_action_metric (task);
  4435. if (action) {
  4436. lua_pushstring (L, "action");
  4437. lua_pushstring (L, action->name);
  4438. lua_settable (L, -3);
  4439. }
  4440. lua_pushstring (L, "nnegative");
  4441. lua_pushnumber (L, metric_res->nnegative);
  4442. lua_settable (L, -3);
  4443. lua_pushstring (L, "npositive");
  4444. lua_pushnumber (L, metric_res->npositive);
  4445. lua_settable (L, -3);
  4446. lua_pushstring (L, "positive_score");
  4447. lua_pushnumber (L, metric_res->positive_score);
  4448. lua_settable (L, -3);
  4449. lua_pushstring (L, "negative_score");
  4450. lua_pushnumber (L, metric_res->negative_score);
  4451. lua_settable (L, -3);
  4452. lua_pushstring (L, "passthrough");
  4453. lua_pushboolean (L, !!(metric_res->passthrough_result != NULL));
  4454. lua_settable (L, -3);
  4455. }
  4456. else {
  4457. return luaL_error (L, "invalid arguments");
  4458. }
  4459. return 1;
  4460. }
  4461. static gint
  4462. lua_task_get_metric_score (lua_State *L)
  4463. {
  4464. LUA_TRACE_POINT;
  4465. struct rspamd_task *task = lua_check_task (L, 1);
  4466. gdouble rs;
  4467. struct rspamd_metric_result *metric_res;
  4468. if (task) {
  4469. if ((metric_res = task->result) != NULL) {
  4470. lua_createtable (L, 2, 0);
  4471. lua_pushnumber (L, isnan (metric_res->score) ? 0.0 : metric_res->score);
  4472. rs = rspamd_task_get_required_score (task, metric_res);
  4473. lua_rawseti (L, -2, 1);
  4474. lua_pushnumber (L, rs);
  4475. lua_rawseti (L, -2, 2);
  4476. }
  4477. else {
  4478. lua_pushnil (L);
  4479. }
  4480. }
  4481. else {
  4482. return luaL_error (L, "invalid arguments");
  4483. }
  4484. return 1;
  4485. }
  4486. static gint
  4487. lua_task_get_metric_action (lua_State *L)
  4488. {
  4489. LUA_TRACE_POINT;
  4490. struct rspamd_task *task = lua_check_task (L, 1);
  4491. struct rspamd_metric_result *metric_res;
  4492. struct rspamd_action *action;
  4493. if (task) {
  4494. metric_res = task->result;
  4495. action = rspamd_check_action_metric (task);
  4496. lua_pushstring (L, action->name);
  4497. }
  4498. else {
  4499. return luaL_error (L, "invalid arguments");
  4500. }
  4501. return 1;
  4502. }
  4503. static gint
  4504. lua_task_set_metric_score (lua_State *L)
  4505. {
  4506. LUA_TRACE_POINT;
  4507. struct rspamd_task *task = lua_check_task (L, 1);
  4508. struct rspamd_metric_result *metric_res;
  4509. gdouble nscore;
  4510. if (lua_isnumber (L, 2)) {
  4511. nscore = luaL_checknumber (L, 2);
  4512. }
  4513. else {
  4514. nscore = luaL_checknumber (L, 3);
  4515. }
  4516. if (task) {
  4517. if ((metric_res = task->result) != NULL) {
  4518. msg_debug_task ("set metric score from %.2f to %.2f",
  4519. metric_res->score, nscore);
  4520. metric_res->score = nscore;
  4521. lua_pushboolean (L, true);
  4522. }
  4523. else {
  4524. lua_pushboolean (L, false);
  4525. }
  4526. }
  4527. else {
  4528. return luaL_error (L, "invalid arguments");
  4529. }
  4530. return 1;
  4531. }
  4532. static gint
  4533. lua_task_disable_action (lua_State *L)
  4534. {
  4535. LUA_TRACE_POINT;
  4536. struct rspamd_task *task = lua_check_task (L, 1);
  4537. const gchar *action_name;
  4538. struct rspamd_action_result *action_res;
  4539. action_name = luaL_checkstring (L, 2);
  4540. if (task && action_name) {
  4541. for (guint i = 0; i < task->result->nactions; i ++) {
  4542. action_res = &task->result->actions_limits[i];
  4543. if (strcmp (action_name, action_res->action->name) == 0) {
  4544. if (isnan (action_res->cur_limit)) {
  4545. lua_pushboolean (L, false);
  4546. }
  4547. else {
  4548. action_res->cur_limit = NAN;
  4549. lua_pushboolean (L, true);
  4550. }
  4551. break;
  4552. }
  4553. }
  4554. }
  4555. else {
  4556. return luaL_error (L, "invalid arguments");
  4557. }
  4558. return 1;
  4559. }
  4560. static gint
  4561. lua_task_get_newlines_type (lua_State *L)
  4562. {
  4563. LUA_TRACE_POINT;
  4564. struct rspamd_task *task = lua_check_task (L, 1);
  4565. if (task) {
  4566. switch (task->nlines_type) {
  4567. case RSPAMD_TASK_NEWLINES_CR:
  4568. lua_pushstring (L, "cr");
  4569. break;
  4570. case RSPAMD_TASK_NEWLINES_LF:
  4571. lua_pushstring (L, "lf");
  4572. break;
  4573. case RSPAMD_TASK_NEWLINES_CRLF:
  4574. default:
  4575. lua_pushstring (L, "crlf");
  4576. break;
  4577. }
  4578. }
  4579. else {
  4580. return luaL_error (L, "invalid arguments");
  4581. }
  4582. return 1;
  4583. }
  4584. static void
  4585. lua_push_stat_token (lua_State *L, rspamd_token_t *tok)
  4586. {
  4587. gchar numbuf[64];
  4588. /* Table values
  4589. * - `data`: 64 bit number encoded as a string
  4590. * - `t1`: the first token (if any)
  4591. * - `t2`: the second token (if any)
  4592. * - `win`: window index
  4593. * - `flag`: table of strings:
  4594. * - `text`: text token
  4595. * - `meta`: meta token
  4596. * - `lua`: lua meta token
  4597. * - `exception`: exception
  4598. * - `subject`: subject token
  4599. * - `unigram`: unigram token
  4600. */
  4601. lua_createtable (L, 0, 5);
  4602. rspamd_snprintf (numbuf, sizeof (numbuf), "%uL", tok->data);
  4603. lua_pushstring (L, "data");
  4604. lua_pushstring (L, numbuf);
  4605. lua_settable (L, -3);
  4606. if (tok->t1) {
  4607. lua_pushstring (L, "t1");
  4608. lua_pushlstring (L, tok->t1->stemmed.begin, tok->t1->stemmed.len);
  4609. lua_settable (L, -3);
  4610. }
  4611. if (tok->t2) {
  4612. lua_pushstring (L, "t2");
  4613. lua_pushlstring (L, tok->t2->stemmed.begin, tok->t2->stemmed.len);
  4614. lua_settable (L, -3);
  4615. }
  4616. lua_pushstring (L, "win");
  4617. lua_pushinteger (L, tok->window_idx);
  4618. lua_settable (L, -3);
  4619. lua_pushstring (L, "flags");
  4620. lua_createtable (L, 0, 5);
  4621. /* Flags */
  4622. {
  4623. if (tok->flags & RSPAMD_STAT_TOKEN_FLAG_TEXT) {
  4624. lua_pushstring (L, "text");
  4625. lua_pushboolean (L, true);
  4626. lua_settable (L, -3);
  4627. }
  4628. if (tok->flags & RSPAMD_STAT_TOKEN_FLAG_META) {
  4629. lua_pushstring (L, "meta");
  4630. lua_pushboolean (L, true);
  4631. lua_settable (L, -3);
  4632. }
  4633. if (tok->flags & RSPAMD_STAT_TOKEN_FLAG_LUA_META) {
  4634. lua_pushstring (L, "lua");
  4635. lua_pushboolean (L, true);
  4636. lua_settable (L, -3);
  4637. }
  4638. if (tok->flags & RSPAMD_STAT_TOKEN_FLAG_EXCEPTION) {
  4639. lua_pushstring (L, "exception");
  4640. lua_pushboolean (L, true);
  4641. lua_settable (L, -3);
  4642. }
  4643. if (tok->flags & RSPAMD_STAT_TOKEN_FLAG_HEADER) {
  4644. lua_pushstring (L, "header");
  4645. lua_pushboolean (L, true);
  4646. lua_settable (L, -3);
  4647. }
  4648. }
  4649. lua_settable (L, -3);
  4650. }
  4651. static gint
  4652. lua_task_get_stat_tokens (lua_State *L)
  4653. {
  4654. LUA_TRACE_POINT;
  4655. struct rspamd_task *task = lua_check_task (L, 1);
  4656. guint i;
  4657. rspamd_token_t *tok;
  4658. if (task) {
  4659. if (!task->tokens) {
  4660. rspamd_stat_process_tokenize (NULL, task);
  4661. }
  4662. if (!task->tokens) {
  4663. lua_pushnil (L);
  4664. }
  4665. else {
  4666. lua_createtable (L, task->tokens->len, 0);
  4667. PTR_ARRAY_FOREACH (task->tokens, i, tok) {
  4668. lua_push_stat_token (L, tok);
  4669. lua_rawseti (L, -2, i + 1);
  4670. }
  4671. }
  4672. }
  4673. else {
  4674. return luaL_error (L, "invalid arguments");
  4675. }
  4676. return 1;
  4677. }
  4678. static gint
  4679. lua_task_set_metric_subject (lua_State *L)
  4680. {
  4681. LUA_TRACE_POINT;
  4682. struct rspamd_task *task = lua_check_task (L, 1);
  4683. const gchar *subject;
  4684. subject = luaL_checkstring (L, 2);
  4685. if (task && subject) {
  4686. rspamd_mempool_set_variable (task->task_pool, "metric_subject",
  4687. rspamd_mempool_strdup(task->task_pool, subject), NULL);
  4688. lua_pushboolean (L, true);
  4689. }
  4690. else {
  4691. return luaL_error (L, "invalid arguments");
  4692. }
  4693. return 1;
  4694. }
  4695. static gint
  4696. lua_task_get_protocol_reply (lua_State *L)
  4697. {
  4698. LUA_TRACE_POINT;
  4699. struct rspamd_task *task = lua_check_task (L, 1);
  4700. guint flags = 0;
  4701. ucl_object_t *obj;
  4702. if (!task) {
  4703. return luaL_error (L, "invalid arguments");
  4704. }
  4705. if (!(task->processed_stages & (RSPAMD_TASK_STAGE_POST_FILTERS >> 1))) {
  4706. return luaL_error (L, "must not be called before post-filters");
  4707. }
  4708. if (lua_istable (L, 2)) {
  4709. for (lua_pushnil (L); lua_next (L, 2); lua_pop (L, 1)) {
  4710. if (lua_isstring (L, -1)) {
  4711. const gchar *str = lua_tostring (L, -1);
  4712. if (strcmp (str, "default") == 0) {
  4713. flags |= RSPAMD_PROTOCOL_DEFAULT;
  4714. }
  4715. else if (strcmp (str, "basic") == 0) {
  4716. flags |= RSPAMD_PROTOCOL_BASIC;
  4717. }
  4718. else if (strcmp (str, "metrics") == 0) {
  4719. flags |= RSPAMD_PROTOCOL_METRICS;
  4720. }
  4721. else if (strcmp (str, "messages") == 0) {
  4722. flags |= RSPAMD_PROTOCOL_MESSAGES;
  4723. }
  4724. else if (strcmp (str, "rmilter") == 0) {
  4725. flags |= RSPAMD_PROTOCOL_RMILTER;
  4726. }
  4727. else if (strcmp (str, "dkim") == 0) {
  4728. flags |= RSPAMD_PROTOCOL_DKIM;
  4729. }
  4730. else if (strcmp (str, "extra") == 0) {
  4731. flags |= RSPAMD_PROTOCOL_EXTRA;
  4732. }
  4733. else {
  4734. msg_err_task ("invalid protocol flag: %s", str);
  4735. }
  4736. }
  4737. }
  4738. }
  4739. else {
  4740. flags = RSPAMD_PROTOCOL_DEFAULT;
  4741. }
  4742. obj = rspamd_protocol_write_ucl (task, flags);
  4743. if (obj) {
  4744. ucl_object_push_lua (L, obj, true);
  4745. }
  4746. else {
  4747. lua_pushnil (L);
  4748. }
  4749. return 1;
  4750. }
  4751. static gint
  4752. lua_task_headers_foreach (lua_State *L)
  4753. {
  4754. LUA_TRACE_POINT;
  4755. struct rspamd_task *task = lua_check_task (L, 1);
  4756. enum rspamd_lua_task_header_type how = RSPAMD_TASK_HEADER_PUSH_SIMPLE;
  4757. struct rspamd_lua_regexp *re = NULL;
  4758. GList *cur;
  4759. struct rspamd_mime_header *hdr;
  4760. gint old_top;
  4761. if (task && lua_isfunction (L, 2)) {
  4762. if (lua_istable (L, 3)) {
  4763. lua_pushstring (L, "full");
  4764. lua_gettable (L, 3);
  4765. if (lua_isboolean (L, -1) && lua_toboolean (L, -1)) {
  4766. how = RSPAMD_TASK_HEADER_PUSH_FULL;
  4767. }
  4768. lua_pop (L, 1);
  4769. lua_pushstring (L, "raw");
  4770. lua_gettable (L, 3);
  4771. if (lua_isboolean (L, -1) && lua_toboolean (L, -1)) {
  4772. how = RSPAMD_TASK_HEADER_PUSH_RAW;
  4773. }
  4774. lua_pop (L, 1);
  4775. lua_pushstring (L, "regexp");
  4776. lua_gettable (L, 3);
  4777. if (lua_isuserdata (L, -1)) {
  4778. re = *(struct rspamd_lua_regexp **)
  4779. rspamd_lua_check_udata (L, -1, "rspamd{regexp}");
  4780. }
  4781. lua_pop (L, 1);
  4782. }
  4783. if (task->headers_order) {
  4784. cur = task->headers_order->head;
  4785. while (cur) {
  4786. hdr = cur->data;
  4787. if (re && re->re) {
  4788. if (!rspamd_regexp_match (re->re, hdr->name,
  4789. strlen (hdr->name),FALSE)) {
  4790. cur = g_list_next (cur);
  4791. continue;
  4792. }
  4793. }
  4794. old_top = lua_gettop (L);
  4795. lua_pushvalue (L, 2);
  4796. lua_pushstring (L, hdr->name);
  4797. rspamd_lua_push_header (L, hdr, how);
  4798. if (lua_pcall (L, 2, LUA_MULTRET, 0) != 0) {
  4799. msg_err ("call to header_foreach failed: %s",
  4800. lua_tostring (L, -1));
  4801. lua_settop (L, old_top);
  4802. break;
  4803. }
  4804. else {
  4805. if (lua_gettop (L) > old_top) {
  4806. if (lua_isboolean (L, old_top + 1)) {
  4807. if (lua_toboolean (L, old_top + 1)) {
  4808. lua_settop (L, old_top);
  4809. break;
  4810. }
  4811. }
  4812. }
  4813. }
  4814. lua_settop (L, old_top);
  4815. cur = g_list_next (cur);
  4816. }
  4817. }
  4818. }
  4819. return 0;
  4820. }
  4821. static gint
  4822. lua_task_get_meta_words (lua_State *L)
  4823. {
  4824. LUA_TRACE_POINT;
  4825. struct rspamd_task *task = lua_check_task (L, 1);
  4826. enum rspamd_lua_words_type how = RSPAMD_LUA_WORDS_STEM;
  4827. if (task == NULL) {
  4828. return luaL_error (L, "invalid arguments");
  4829. }
  4830. if (task->meta_words == NULL) {
  4831. lua_createtable (L, 0, 0);
  4832. }
  4833. else {
  4834. if (lua_type (L, 2) == LUA_TSTRING) {
  4835. const gchar *how_str = lua_tostring (L, 2);
  4836. if (strcmp (how_str, "stem") == 0) {
  4837. how = RSPAMD_LUA_WORDS_STEM;
  4838. }
  4839. else if (strcmp (how_str, "norm") == 0) {
  4840. how = RSPAMD_LUA_WORDS_NORM;
  4841. }
  4842. else if (strcmp (how_str, "raw") == 0) {
  4843. how = RSPAMD_LUA_WORDS_RAW;
  4844. }
  4845. else if (strcmp (how_str, "full") == 0) {
  4846. how = RSPAMD_LUA_WORDS_FULL;
  4847. }
  4848. else {
  4849. return luaL_error (L, "unknown words type: %s", how_str);
  4850. }
  4851. }
  4852. return rspamd_lua_push_words (L, task->meta_words, how);
  4853. }
  4854. return 1;
  4855. }
  4856. static guint
  4857. lua_lookup_words_array (lua_State *L,
  4858. gint cbpos,
  4859. struct rspamd_task *task,
  4860. struct rspamd_lua_map *map,
  4861. GArray *words)
  4862. {
  4863. rspamd_stat_token_t *tok;
  4864. guint i, nmatched = 0;
  4865. gint err_idx;
  4866. gboolean matched;
  4867. const gchar *key;
  4868. gsize keylen;
  4869. for (i = 0; i < words->len; i ++) {
  4870. tok = &g_array_index (words, rspamd_stat_token_t, i);
  4871. matched = FALSE;
  4872. if (tok->normalized.len == 0) {
  4873. continue;
  4874. }
  4875. key = tok->normalized.begin;
  4876. keylen = tok->normalized.len;
  4877. switch (map->type) {
  4878. case RSPAMD_LUA_MAP_SET:
  4879. case RSPAMD_LUA_MAP_HASH:
  4880. /* We know that tok->normalized is zero terminated in fact */
  4881. if (rspamd_match_hash_map (map->data.hash, key)) {
  4882. matched = TRUE;
  4883. }
  4884. break;
  4885. case RSPAMD_LUA_MAP_REGEXP:
  4886. case RSPAMD_LUA_MAP_REGEXP_MULTIPLE:
  4887. if (rspamd_match_regexp_map_single (map->data.re_map, key,
  4888. keylen)) {
  4889. matched = TRUE;
  4890. }
  4891. break;
  4892. default:
  4893. g_assert_not_reached ();
  4894. break;
  4895. }
  4896. if (matched) {
  4897. nmatched ++;
  4898. lua_pushcfunction (L, &rspamd_lua_traceback);
  4899. err_idx = lua_gettop (L);
  4900. lua_pushvalue (L, cbpos); /* Function */
  4901. rspamd_lua_push_full_word (L, tok);
  4902. if (lua_pcall (L, 1, 0, err_idx) != 0) {
  4903. GString *tb = lua_touserdata (L, -1);
  4904. msg_err_task ("cannot call callback function for lookup words: %s",
  4905. tb->str);
  4906. g_string_free (tb, TRUE);
  4907. }
  4908. lua_settop (L, err_idx - 1);
  4909. }
  4910. }
  4911. return nmatched;
  4912. }
  4913. static gint
  4914. lua_task_lookup_words (lua_State *L)
  4915. {
  4916. LUA_TRACE_POINT;
  4917. struct rspamd_task *task = lua_check_task (L, 1);
  4918. struct rspamd_lua_map *map = lua_check_map (L, 2);
  4919. struct rspamd_mime_text_part *tp;
  4920. guint i, matches = 0;
  4921. if (task == NULL || map == NULL || lua_type (L, 3) != LUA_TFUNCTION) {
  4922. return luaL_error (L, "invalid arguments");
  4923. }
  4924. if (map->type != RSPAMD_LUA_MAP_SET &&
  4925. map->type != RSPAMD_LUA_MAP_REGEXP &&
  4926. map->type != RSPAMD_LUA_MAP_HASH &&
  4927. map->type != RSPAMD_LUA_MAP_REGEXP_MULTIPLE) {
  4928. return luaL_error (L, "invalid map type");
  4929. }
  4930. PTR_ARRAY_FOREACH (task->text_parts, i, tp) {
  4931. if (tp->utf_words) {
  4932. matches += lua_lookup_words_array (L, 3, task, map, tp->utf_words);
  4933. }
  4934. }
  4935. if (task->meta_words) {
  4936. matches += lua_lookup_words_array (L, 3, task, map, task->meta_words);
  4937. }
  4938. lua_pushinteger (L, matches);
  4939. return 1;
  4940. }
  4941. static gint
  4942. lua_task_topointer (lua_State *L)
  4943. {
  4944. LUA_TRACE_POINT;
  4945. struct rspamd_task *task = lua_check_task (L, 1);
  4946. if (task) {
  4947. lua_pushlightuserdata (L, task);
  4948. }
  4949. else {
  4950. return luaL_error (L, "invalid arguments");
  4951. }
  4952. return 1;
  4953. }
  4954. /* Image functions */
  4955. static gint
  4956. lua_image_get_width (lua_State *L)
  4957. {
  4958. LUA_TRACE_POINT;
  4959. struct rspamd_image *img = lua_check_image (L);
  4960. if (img != NULL) {
  4961. lua_pushinteger (L, img->width);
  4962. }
  4963. else {
  4964. return luaL_error (L, "invalid arguments");
  4965. }
  4966. return 1;
  4967. }
  4968. static gint
  4969. lua_image_get_height (lua_State *L)
  4970. {
  4971. LUA_TRACE_POINT;
  4972. struct rspamd_image *img = lua_check_image (L);
  4973. if (img != NULL) {
  4974. lua_pushinteger (L, img->height);
  4975. }
  4976. else {
  4977. return luaL_error (L, "invalid arguments");
  4978. }
  4979. return 1;
  4980. }
  4981. static gint
  4982. lua_image_get_type (lua_State *L)
  4983. {
  4984. LUA_TRACE_POINT;
  4985. struct rspamd_image *img = lua_check_image (L);
  4986. if (img != NULL) {
  4987. lua_pushstring (L, rspamd_image_type_str (img->type));
  4988. }
  4989. else {
  4990. return luaL_error (L, "invalid arguments");
  4991. }
  4992. return 1;
  4993. }
  4994. static gint
  4995. lua_image_get_size (lua_State *L)
  4996. {
  4997. LUA_TRACE_POINT;
  4998. struct rspamd_image *img = lua_check_image (L);
  4999. if (img != NULL) {
  5000. lua_pushinteger (L, img->data->len);
  5001. }
  5002. else {
  5003. return luaL_error (L, "invalid arguments");
  5004. }
  5005. return 1;
  5006. }
  5007. static gint
  5008. lua_image_get_filename (lua_State *L)
  5009. {
  5010. LUA_TRACE_POINT;
  5011. struct rspamd_image *img = lua_check_image (L);
  5012. if (img != NULL) {
  5013. if (img->filename != NULL) {
  5014. lua_pushlstring (L, img->filename->begin, img->filename->len);
  5015. }
  5016. else {
  5017. lua_pushnil (L);
  5018. }
  5019. }
  5020. else {
  5021. return luaL_error (L, "invalid arguments");
  5022. }
  5023. return 1;
  5024. }
  5025. /* Arvhive methods */
  5026. static gint
  5027. lua_archive_get_type (lua_State *L)
  5028. {
  5029. LUA_TRACE_POINT;
  5030. struct rspamd_archive *arch = lua_check_archive (L);
  5031. if (arch != NULL) {
  5032. lua_pushstring (L, rspamd_archive_type_str (arch->type));
  5033. }
  5034. else {
  5035. return luaL_error (L, "invalid arguments");
  5036. }
  5037. return 1;
  5038. }
  5039. static gint
  5040. lua_archive_get_files (lua_State *L)
  5041. {
  5042. LUA_TRACE_POINT;
  5043. struct rspamd_archive *arch = lua_check_archive (L);
  5044. guint i;
  5045. struct rspamd_archive_file *f;
  5046. if (arch != NULL) {
  5047. lua_createtable (L, arch->files->len, 0);
  5048. for (i = 0; i < arch->files->len; i ++) {
  5049. f = g_ptr_array_index (arch->files, i);
  5050. lua_pushlstring (L, f->fname->str, f->fname->len);
  5051. lua_rawseti (L, -2, i + 1);
  5052. }
  5053. }
  5054. else {
  5055. return luaL_error (L, "invalid arguments");
  5056. }
  5057. return 1;
  5058. }
  5059. static gint
  5060. lua_archive_get_files_full (lua_State *L)
  5061. {
  5062. LUA_TRACE_POINT;
  5063. struct rspamd_archive *arch = lua_check_archive (L);
  5064. guint i;
  5065. struct rspamd_archive_file *f;
  5066. if (arch != NULL) {
  5067. lua_createtable (L, arch->files->len, 0);
  5068. for (i = 0; i < arch->files->len; i ++) {
  5069. f = g_ptr_array_index (arch->files, i);
  5070. lua_createtable (L, 0, 4);
  5071. lua_pushstring (L, "name");
  5072. lua_pushlstring (L, f->fname->str, f->fname->len);
  5073. lua_settable (L, -3);
  5074. lua_pushstring (L, "compressed_size");
  5075. lua_pushinteger (L, f->compressed_size);
  5076. lua_settable (L, -3);
  5077. lua_pushstring (L, "uncompressed_size");
  5078. lua_pushinteger (L, f->uncompressed_size);
  5079. lua_settable (L, -3);
  5080. lua_pushstring (L, "encrypted");
  5081. lua_pushboolean (L, (f->flags & RSPAMD_ARCHIVE_FILE_ENCRYPTED) ? true : false);
  5082. lua_settable (L, -3);
  5083. lua_rawseti (L, -2, i + 1);
  5084. }
  5085. }
  5086. else {
  5087. return luaL_error (L, "invalid arguments");
  5088. }
  5089. return 1;
  5090. }
  5091. static gint
  5092. lua_archive_is_encrypted (lua_State *L)
  5093. {
  5094. LUA_TRACE_POINT;
  5095. struct rspamd_archive *arch = lua_check_archive (L);
  5096. if (arch != NULL) {
  5097. lua_pushboolean (L, (arch->flags & RSPAMD_ARCHIVE_ENCRYPTED) ? true : false);
  5098. }
  5099. else {
  5100. return luaL_error (L, "invalid arguments");
  5101. }
  5102. return 1;
  5103. }
  5104. static gint
  5105. lua_archive_get_size (lua_State *L)
  5106. {
  5107. LUA_TRACE_POINT;
  5108. struct rspamd_archive *arch = lua_check_archive (L);
  5109. if (arch != NULL) {
  5110. lua_pushinteger (L, arch->size);
  5111. }
  5112. else {
  5113. return luaL_error (L, "invalid arguments");
  5114. }
  5115. return 1;
  5116. }
  5117. static gint
  5118. lua_archive_get_filename (lua_State *L)
  5119. {
  5120. LUA_TRACE_POINT;
  5121. struct rspamd_archive *arch = lua_check_archive (L);
  5122. if (arch != NULL) {
  5123. lua_pushlstring (L, arch->archive_name->begin, arch->archive_name->len);
  5124. }
  5125. else {
  5126. return luaL_error (L, "invalid arguments");
  5127. }
  5128. return 1;
  5129. }
  5130. /* Text methods */
  5131. static gint
  5132. lua_text_fromstring (lua_State *L)
  5133. {
  5134. LUA_TRACE_POINT;
  5135. const gchar *str;
  5136. gsize l = 0;
  5137. struct rspamd_lua_text *t;
  5138. str = luaL_checklstring (L, 1, &l);
  5139. if (str) {
  5140. t = lua_newuserdata (L, sizeof (*t));
  5141. t->start = g_malloc (l + 1);
  5142. rspamd_strlcpy ((char *)t->start, str, l + 1);
  5143. t->len = l;
  5144. t->flags = RSPAMD_TEXT_FLAG_OWN;
  5145. rspamd_lua_setclass (L, "rspamd{text}", -1);
  5146. }
  5147. else {
  5148. return luaL_error (L, "invalid arguments");
  5149. }
  5150. return 1;
  5151. }
  5152. static gint
  5153. lua_text_fromtable (lua_State *L)
  5154. {
  5155. LUA_TRACE_POINT;
  5156. const gchar *delim = "", *st;
  5157. struct rspamd_lua_text *t, *elt;
  5158. gsize textlen = 0, dlen, stlen, tblen;
  5159. gchar *dest;
  5160. if (!lua_istable (L, 1)) {
  5161. return luaL_error (L, "invalid arguments");
  5162. }
  5163. if (lua_type (L, 2) == LUA_TSTRING) {
  5164. delim = lua_tolstring (L, 2, &dlen);
  5165. }
  5166. else {
  5167. dlen = strlen (delim);
  5168. }
  5169. /* Calculate length needed */
  5170. tblen = rspamd_lua_table_size (L, 1);
  5171. for (guint i = 0; i < tblen; i ++) {
  5172. lua_rawgeti (L, 1, i + 1);
  5173. if (lua_type (L, -1) == LUA_TSTRING) {
  5174. #if LUA_VERSION_NUM >= 502
  5175. stlen = lua_rawlen (L, -1);
  5176. #else
  5177. stlen = lua_objlen (L, -1);
  5178. #endif
  5179. textlen += stlen;
  5180. }
  5181. else {
  5182. elt = lua_check_text (L, -1);
  5183. if (elt) {
  5184. textlen += elt->len;
  5185. }
  5186. }
  5187. lua_pop (L, 1);
  5188. textlen += dlen;
  5189. }
  5190. /* Allocate new text */
  5191. t = lua_newuserdata (L, sizeof (*t));
  5192. dest = g_malloc (textlen);
  5193. t->start = dest;
  5194. t->len = textlen;
  5195. t->flags = RSPAMD_TEXT_FLAG_OWN;
  5196. rspamd_lua_setclass (L, "rspamd{text}", -1);
  5197. for (guint i = 0; i < tblen; i ++) {
  5198. lua_rawgeti (L, 1, i + 1);
  5199. if (lua_type (L, -1) == LUA_TSTRING) {
  5200. st = lua_tolstring (L, -1, &stlen);
  5201. memcpy (dest, st, stlen);
  5202. dest += stlen;
  5203. }
  5204. else {
  5205. elt = lua_check_text (L, -1);
  5206. if (elt) {
  5207. memcpy (dest, elt->start, elt->len);
  5208. }
  5209. }
  5210. memcpy (dest, delim, dlen);
  5211. lua_pop (L, 1);
  5212. }
  5213. return 1;
  5214. }
  5215. static gint
  5216. lua_text_len (lua_State *L)
  5217. {
  5218. LUA_TRACE_POINT;
  5219. struct rspamd_lua_text *t = lua_check_text (L, 1);
  5220. gsize l = 0;
  5221. if (t != NULL) {
  5222. l = t->len;
  5223. }
  5224. else {
  5225. return luaL_error (L, "invalid arguments");
  5226. }
  5227. lua_pushinteger (L, l);
  5228. return 1;
  5229. }
  5230. static gint
  5231. lua_text_str (lua_State *L)
  5232. {
  5233. LUA_TRACE_POINT;
  5234. struct rspamd_lua_text *t = lua_check_text (L, 1);
  5235. if (t != NULL) {
  5236. lua_pushlstring (L, t->start, t->len);
  5237. }
  5238. else {
  5239. return luaL_error (L, "invalid arguments");
  5240. }
  5241. return 1;
  5242. }
  5243. static gint
  5244. lua_text_ptr (lua_State *L)
  5245. {
  5246. LUA_TRACE_POINT;
  5247. struct rspamd_lua_text *t = lua_check_text (L, 1);
  5248. if (t != NULL) {
  5249. lua_pushlightuserdata (L, (gpointer)t->start);
  5250. }
  5251. else {
  5252. return luaL_error (L, "invalid arguments");
  5253. }
  5254. return 1;
  5255. }
  5256. static gint
  5257. lua_text_take_ownership (lua_State *L)
  5258. {
  5259. LUA_TRACE_POINT;
  5260. struct rspamd_lua_text *t = lua_check_text (L, 1);
  5261. gchar *dest;
  5262. if (t != NULL) {
  5263. if (t->flags & RSPAMD_TEXT_FLAG_OWN) {
  5264. /* We already own it */
  5265. lua_pushboolean (L, true);
  5266. }
  5267. else {
  5268. dest = g_malloc (t->len);
  5269. memcpy (dest, t->start, t->len);
  5270. t->start = dest;
  5271. t->flags |= RSPAMD_TEXT_FLAG_OWN;
  5272. lua_pushboolean (L, true);
  5273. }
  5274. }
  5275. else {
  5276. return luaL_error (L, "invalid arguments");
  5277. }
  5278. return 1;
  5279. }
  5280. static gint
  5281. lua_text_save_in_file (lua_State *L)
  5282. {
  5283. LUA_TRACE_POINT;
  5284. struct rspamd_lua_text *t = lua_check_text (L, 1);
  5285. const gchar *fname = NULL;
  5286. guint mode = 00644;
  5287. gint fd = -1;
  5288. gboolean need_close = FALSE;
  5289. if (t != NULL) {
  5290. if (lua_type (L, 2) == LUA_TSTRING) {
  5291. fname = luaL_checkstring (L, 2);
  5292. if (lua_type (L, 3) == LUA_TNUMBER) {
  5293. mode = lua_tonumber (L, 3);
  5294. }
  5295. }
  5296. else if (lua_type (L, 2) == LUA_TNUMBER) {
  5297. /* Created fd */
  5298. fd = lua_tonumber (L, 2);
  5299. }
  5300. if (fd == -1) {
  5301. if (fname) {
  5302. fd = rspamd_file_xopen (fname, O_CREAT | O_WRONLY | O_EXCL, mode, 0);
  5303. if (fd == -1) {
  5304. lua_pushboolean (L, false);
  5305. lua_pushstring (L, strerror (errno));
  5306. return 2;
  5307. }
  5308. need_close = TRUE;
  5309. }
  5310. else {
  5311. fd = STDOUT_FILENO;
  5312. }
  5313. }
  5314. if (write (fd, t->start, t->len) == -1) {
  5315. if (fd != STDOUT_FILENO) {
  5316. close (fd);
  5317. }
  5318. lua_pushboolean (L, false);
  5319. lua_pushstring (L, strerror (errno));
  5320. return 2;
  5321. }
  5322. if (need_close) {
  5323. close (fd);
  5324. }
  5325. lua_pushboolean (L, true);
  5326. }
  5327. else {
  5328. return luaL_error (L, "invalid arguments");
  5329. }
  5330. return 1;
  5331. }
  5332. static gint
  5333. lua_text_gc (lua_State *L)
  5334. {
  5335. LUA_TRACE_POINT;
  5336. struct rspamd_lua_text *t = lua_check_text (L, 1);
  5337. if (t != NULL) {
  5338. if (t->flags & RSPAMD_TEXT_FLAG_OWN) {
  5339. if (t->flags & RSPAMD_TEXT_FLAG_MMAPED) {
  5340. munmap ((gpointer)t->start, t->len);
  5341. }
  5342. else {
  5343. g_free ((gpointer)t->start);
  5344. }
  5345. }
  5346. }
  5347. return 0;
  5348. }
  5349. /* Init part */
  5350. static gint
  5351. lua_load_task (lua_State * L)
  5352. {
  5353. lua_newtable (L);
  5354. luaL_register (L, NULL, tasklib_f);
  5355. return 1;
  5356. }
  5357. static gint
  5358. lua_load_text (lua_State * L)
  5359. {
  5360. lua_newtable (L);
  5361. luaL_register (L, NULL, textlib_f);
  5362. return 1;
  5363. }
  5364. static void
  5365. luaopen_archive (lua_State * L)
  5366. {
  5367. rspamd_lua_new_class (L, "rspamd{archive}", archivelib_m);
  5368. lua_pop (L, 1);
  5369. }
  5370. void
  5371. luaopen_task (lua_State * L)
  5372. {
  5373. rspamd_lua_new_class (L, "rspamd{task}", tasklib_m);
  5374. lua_pop (L, 1);
  5375. rspamd_lua_add_preload (L, "rspamd_task", lua_load_task);
  5376. luaopen_archive (L);
  5377. }
  5378. void
  5379. luaopen_image (lua_State * L)
  5380. {
  5381. rspamd_lua_new_class (L, "rspamd{image}", imagelib_m);
  5382. lua_pop (L, 1);
  5383. }
  5384. void
  5385. luaopen_text (lua_State *L)
  5386. {
  5387. rspamd_lua_new_class (L, "rspamd{text}", textlib_m);
  5388. lua_pop (L, 1);
  5389. rspamd_lua_add_preload (L, "rspamd_text", lua_load_text);
  5390. }
  5391. void
  5392. rspamd_lua_task_push (lua_State *L, struct rspamd_task *task)
  5393. {
  5394. struct rspamd_task **ptask;
  5395. ptask = lua_newuserdata (L, sizeof (gpointer));
  5396. rspamd_lua_setclass (L, "rspamd{task}", -1);
  5397. *ptask = task;
  5398. }