FILTER_ANY = "xap_filter_any" FILTER_ABSENT = "xap_filter_absent" Filter = {} function Filter:new() local o={ filterChain = {}, callback = nil } return setmetatable(o, {__index=self}) end function Filter:add(section, key, value) table.insert(self.filterChain, {section=section,key=key,value=value:lower()}) end function Filter:callback(func, userdata) self.callback = func self.userdata = userdata end function Filter:ismatch(frame) local value, match = nil, true -- No filter chain is match function filterAddrSubaddress(filterAddr, addr) if filterAddr == nil then -- empty filterAddr matches all match = true elseif filterAddr:find('*') == nil and filterAddr:find('>') == nil then -- no wildcards - simple compare match = filterAddr == addr else -- Match using wildcard logic filterAddr = filterAddr:gsub('%.','%%.') -- escape the . filterAddr = filterAddr:gsub('\*','[%%w%%-_]+') filterAddr = filterAddr:gsub('>','.*') local start,finish = addr:find(filterAddr) match = start == 1 and finish == #addr end end for _,fk in pairs(self.filterChain) do value = frame:getValue( fk.section, fk.key ) if fk.value == FILTER_ABSENT then match = value == nil elseif fk.value == FILTER_ANY then match = value ~= nil elseif value == nil then match = false else value = value:lower() if fk.section == "xap-header" and (fk.key == "target" or fk.key == "source" or fk.key == "class") then if fk.key == "target" then filterAddrSubaddress(value, fk.value) else -- source /class filterAddrSubaddress(fk.value, value) end else match = value == fk.value end end if not match then break end end return match end function Filter:dispatch(frame) if self.callback and self:ismatch(frame) then pcall(self.callback, frame, self.userdata) end end function Filter:getFilterType() for _,fk in pairs(self.filterChain) do if fk.section == "xap-header" then if fk.key == "source" then return "flt", fk.value end if fk.key == "class" then return "cflt", fk.value end end end return nil end