-- ----------------------------------------------------------------------------- -- -- Unified SMTP/FTP subsystem -- -- LuaSocket toolkit. -- -- Author: Diego Nehab -- ----------------------------------------------------------------------------- -- ----------------------------------------------------------------------------- -- -- Declare module and import dependencies -- ----------------------------------------------------------------------------- -- local base = _G -- local string = require("string") -- local socket = require("socket") -- local ltn12 = require("ltn12") -- socket.tp = {} -- local _M = socket.tp -- ----------------------------------------------------------------------------- -- -- Program constants -- ----------------------------------------------------------------------------- -- _M.TIMEOUT = 60 -- ----------------------------------------------------------------------------- -- -- Implementation -- ----------------------------------------------------------------------------- -- -- gets server reply (works for SMTP and FTP) -- local function get_reply(c) -- local code, current, sep -- local line, err = c:receive() -- local reply = line -- if err then return nil, err end -- code, sep = socket.skip(2, string.find(line, "^(%d%d%d)(.?)")) -- if not code then return nil, "invalid server reply" end -- if sep == "-" then -- reply is multiline -- repeat -- line, err = c:receive() -- if err then return nil, err end -- current, sep = socket.skip(2, string.find(line, "^(%d%d%d)(.?)")) -- reply = reply .. "\n" .. line -- -- reply ends with same code -- until code == current and sep == " " -- end -- return code, reply -- end -- -- metatable for sock object -- local metat = { __index = {} } -- function metat.__index:getpeername() -- return self.c:getpeername() -- end -- function metat.__index:getsockname() -- return self.c:getpeername() -- end -- function metat.__index:check(ok) -- local code, reply = get_reply(self.c) -- if not code then return nil, reply end -- if base.type(ok) ~= "function" then -- if base.type(ok) == "table" then -- for i, v in base.ipairs(ok) do -- if string.find(code, v) then -- return base.tonumber(code), reply -- end -- end -- return nil, reply -- else -- if string.find(code, ok) then return base.tonumber(code), reply -- else return nil, reply end -- end -- else return ok(base.tonumber(code), reply) end -- end -- function metat.__index:command(cmd, arg) -- cmd = string.upper(cmd) -- if arg then -- return self.c:send(cmd .. " " .. arg.. "\r\n") -- else -- return self.c:send(cmd .. "\r\n") -- end -- end -- function metat.__index:sink(snk, pat) -- local chunk, err = self.c:receive(pat) -- return snk(chunk, err) -- end -- function metat.__index:send(data) -- return self.c:send(data) -- end -- function metat.__index:receive(pat) -- return self.c:receive(pat) -- end -- function metat.__index:getfd() -- return self.c:getfd() -- end -- function metat.__index:dirty() -- return self.c:dirty() -- end -- function metat.__index:getcontrol() -- return self.c -- end -- function metat.__index:source(source, step) -- local sink = socket.sink("keep-open", self.c) -- local ret, err = ltn12.pump.all(source, sink, step or ltn12.pump.step) -- return ret, err -- end -- -- closes the underlying c -- function metat.__index:close() -- self.c:close() -- return 1 -- end -- -- connect with server and return c object -- function _M.connect(host, port, timeout, create) -- local c, e = (create or socket.tcp)() -- if not c then return nil, e end -- c:settimeout(timeout or _M.TIMEOUT) -- local r, e = c:connect(host, port) -- if not r then -- c:close() -- return nil, e -- end -- return base.setmetatable({c = c}, metat) -- end -- return _M