2004-03-16 07:42:53 +01:00
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
-- Unified SMTP/FTP subsystem
|
|
|
|
-- LuaSocket toolkit.
|
|
|
|
-- Author: Diego Nehab
|
|
|
|
-- Conforming to: RFC 2616, LTN7
|
|
|
|
-- RCS ID: $Id$
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
-- make sure LuaSocket is loaded
|
|
|
|
if not LUASOCKET_LIBNAME then error('module requires LuaSocket') end
|
|
|
|
-- get LuaSocket namespace
|
|
|
|
local socket = _G[LUASOCKET_LIBNAME]
|
|
|
|
if not socket then error('module requires LuaSocket') end
|
|
|
|
-- create namespace inside LuaSocket namespace
|
|
|
|
socket.tp = socket.tp or {}
|
|
|
|
-- make all module globals fall into namespace
|
|
|
|
setmetatable(socket.tp, { __index = _G })
|
|
|
|
setfenv(1, socket.tp)
|
|
|
|
|
|
|
|
TIMEOUT = 60
|
|
|
|
|
|
|
|
-- gets server reply
|
|
|
|
local function get_reply(sock)
|
|
|
|
local code, current, separator, _
|
2004-03-18 08:01:14 +01:00
|
|
|
local line, err = sock:receive()
|
2004-03-16 07:42:53 +01:00
|
|
|
local reply = line
|
2004-03-18 08:01:14 +01:00
|
|
|
if err then return nil, err end
|
2004-03-16 07:42:53 +01:00
|
|
|
_, _, code, separator = string.find(line, "^(%d%d%d)(.?)")
|
|
|
|
if not code then return nil, "invalid server reply" end
|
|
|
|
if separator == "-" then -- reply is multiline
|
|
|
|
repeat
|
2004-03-18 08:01:14 +01:00
|
|
|
line, err = sock:receive()
|
|
|
|
if err then return nil, err end
|
2004-03-16 07:42:53 +01:00
|
|
|
_,_, current, separator = string.find(line, "^(%d%d%d)(.)")
|
|
|
|
if not current or not separator then
|
|
|
|
return nil, "invalid server reply"
|
|
|
|
end
|
|
|
|
reply = reply .. "\n" .. line
|
|
|
|
-- reply ends with same code
|
|
|
|
until code == current and separator == " "
|
|
|
|
end
|
|
|
|
return code, reply
|
|
|
|
end
|
|
|
|
|
|
|
|
-- metatable for sock object
|
|
|
|
local metatable = { __index = {} }
|
|
|
|
|
|
|
|
function metatable.__index:check(ok)
|
|
|
|
local code, reply = get_reply(self.sock)
|
|
|
|
if not code then return nil, reply end
|
|
|
|
if type(ok) ~= "function" then
|
2004-03-18 08:01:14 +01:00
|
|
|
if type(ok) == "table" then
|
|
|
|
for i, v in ipairs(ok) do
|
|
|
|
if string.find(code, v) then return code, reply end
|
|
|
|
end
|
|
|
|
return nil, reply
|
|
|
|
else
|
|
|
|
if string.find(code, ok) then return code, reply
|
|
|
|
else return nil, reply end
|
2004-03-16 07:42:53 +01:00
|
|
|
end
|
|
|
|
else return ok(code, reply) end
|
|
|
|
end
|
|
|
|
|
|
|
|
function metatable.__index:command(cmd, arg)
|
2004-03-18 08:01:14 +01:00
|
|
|
if arg then return self.sock:send(cmd .. " " .. arg.. "\r\n")
|
|
|
|
else return self.sock:send(cmd .. "\r\n") end
|
2004-03-16 07:42:53 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
function metatable.__index:sink(snk, pat)
|
|
|
|
local chunk, err = sock:receive(pat)
|
|
|
|
return snk(chunk, err)
|
|
|
|
end
|
|
|
|
|
2004-03-18 08:01:14 +01:00
|
|
|
function metatable.__index:send(data)
|
|
|
|
return self.sock:send(data)
|
|
|
|
end
|
|
|
|
|
|
|
|
function metatable.__index:receive(pat)
|
|
|
|
return self.sock:receive(pat)
|
|
|
|
end
|
|
|
|
|
2004-03-16 07:42:53 +01:00
|
|
|
function metatable.__index:source(src, instr)
|
|
|
|
while true do
|
|
|
|
local chunk, err = src()
|
|
|
|
if not chunk then return not err, err end
|
2004-03-19 06:04:03 +01:00
|
|
|
local ret, err = self.sock:send(chunk)
|
2004-03-16 07:42:53 +01:00
|
|
|
if not ret then return nil, err end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
-- closes the underlying sock
|
|
|
|
function metatable.__index:close()
|
|
|
|
self.sock:close()
|
|
|
|
end
|
|
|
|
|
|
|
|
-- connect with server and return sock object
|
|
|
|
function connect(host, port)
|
|
|
|
local sock, err = socket.connect(host, port)
|
2004-03-19 06:04:03 +01:00
|
|
|
if not sock then return nil, err end
|
2004-03-16 07:42:53 +01:00
|
|
|
sock:settimeout(TIMEOUT)
|
|
|
|
return setmetatable({sock = sock}, metatable)
|
|
|
|
end
|