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 173KB

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