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

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