luasocket/src/tp.lua

102 lines
3.1 KiB
Lua
Raw Normal View History

-----------------------------------------------------------------------------
-- 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, _
local line, err = sock:receive()
local reply = line
if err then return nil, err end
_, _, 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
line, err = sock:receive()
if err then return nil, err end
_,_, 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
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
end
else return ok(code, reply) end
end
function metatable.__index:command(cmd, arg)
if arg then return self.sock:send(cmd .. " " .. arg.. "\r\n")
else return self.sock:send(cmd .. "\r\n") end
end
function metatable.__index:sink(snk, pat)
local chunk, err = sock:receive(pat)
return snk(chunk, err)
end
function metatable.__index:send(data)
return self.sock:send(data)
end
function metatable.__index:receive(pat)
return self.sock:receive(pat)
end
function metatable.__index:source(src, instr)
while true do
local chunk, err = src()
if not chunk then return not err, err end
local ret, err = try_sending(self.sock, chunk)
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)
if not sock then return nil, message end
sock:settimeout(TIMEOUT)
return setmetatable({sock = sock}, metatable)
end