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

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