124 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
			
		
		
	
	
			124 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
| -----------------------------------------------------------------------------
 | |
| -- Unified SMTP/FTP subsystem
 | |
| -- LuaSocket toolkit.
 | |
| -- Author: Diego Nehab
 | |
| -- RCS ID: $Id: tp.lua,v 1.22 2006/03/14 09:04:15 diego Exp $
 | |
| -----------------------------------------------------------------------------
 | |
| 
 | |
| -----------------------------------------------------------------------------
 | |
| -- Declare module and import dependencies
 | |
| -----------------------------------------------------------------------------
 | |
| local base = _G
 | |
| local string = require("string")
 | |
| local socket = require("socket")
 | |
| local ltn12 = require("ltn12")
 | |
| module("socket.tp")
 | |
| 
 | |
| -----------------------------------------------------------------------------
 | |
| -- Program constants
 | |
| -----------------------------------------------------------------------------
 | |
| 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: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)
 | |
|     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 = 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 connect(host, port, timeout, create)
 | |
|     local c, e = (create or socket.tcp)()
 | |
|     if not c then return nil, e end
 | |
|     c:settimeout(timeout or 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
 | |
| 
 | 
