diff options
author | Diego Nehab <diego@tecgraf.puc-rio.br> | 2004-03-16 06:42:53 +0000 |
---|---|---|
committer | Diego Nehab <diego@tecgraf.puc-rio.br> | 2004-03-16 06:42:53 +0000 |
commit | bcc0c2a9f0be2ca796ef5206a78e283fe15e6186 (patch) | |
tree | 65c269d4854aa5ff4a0b2c8eede5cdb18d716033 /src/tp.lua | |
parent | b6edaac2841137cf0ef5105f75358bbab4570d87 (diff) | |
download | luasocket-bcc0c2a9f0be2ca796ef5206a78e283fe15e6186.tar.gz luasocket-bcc0c2a9f0be2ca796ef5206a78e283fe15e6186.tar.bz2 luasocket-bcc0c2a9f0be2ca796ef5206a78e283fe15e6186.zip |
New filter scheme.
ltn12 and mime updated.
smtp/ftp broken.
Diffstat (limited to 'src/tp.lua')
-rw-r--r-- | src/tp.lua | 111 |
1 files changed, 111 insertions, 0 deletions
diff --git a/src/tp.lua b/src/tp.lua new file mode 100644 index 0000000..d8dabc0 --- /dev/null +++ b/src/tp.lua | |||
@@ -0,0 +1,111 @@ | |||
1 | ----------------------------------------------------------------------------- | ||
2 | -- Unified SMTP/FTP subsystem | ||
3 | -- LuaSocket toolkit. | ||
4 | -- Author: Diego Nehab | ||
5 | -- Conforming to: RFC 2616, LTN7 | ||
6 | -- RCS ID: $Id$ | ||
7 | ----------------------------------------------------------------------------- | ||
8 | -- make sure LuaSocket is loaded | ||
9 | if not LUASOCKET_LIBNAME then error('module requires LuaSocket') end | ||
10 | -- get LuaSocket namespace | ||
11 | local socket = _G[LUASOCKET_LIBNAME] | ||
12 | if not socket then error('module requires LuaSocket') end | ||
13 | -- create namespace inside LuaSocket namespace | ||
14 | socket.tp = socket.tp or {} | ||
15 | -- make all module globals fall into namespace | ||
16 | setmetatable(socket.tp, { __index = _G }) | ||
17 | setfenv(1, socket.tp) | ||
18 | |||
19 | TIMEOUT = 60 | ||
20 | |||
21 | -- tries to get a pattern from the server and closes socket on error | ||
22 | local function try_receiving(sock, pattern) | ||
23 | local data, message = sock:receive(pattern) | ||
24 | if not data then sock:close() end | ||
25 | return data, message | ||
26 | end | ||
27 | |||
28 | -- tries to send data to server and closes socket on error | ||
29 | local function try_sending(sock, data) | ||
30 | local sent, message = sock:send(data) | ||
31 | if not sent then sock:close() end | ||
32 | return sent, message | ||
33 | end | ||
34 | |||
35 | -- gets server reply | ||
36 | local function get_reply(sock) | ||
37 | local code, current, separator, _ | ||
38 | local line, message = try_receiving(sock) | ||
39 | local reply = line | ||
40 | if message then return nil, message end | ||
41 | _, _, code, separator = string.find(line, "^(%d%d%d)(.?)") | ||
42 | if not code then return nil, "invalid server reply" end | ||
43 | if separator == "-" then -- reply is multiline | ||
44 | repeat | ||
45 | line, message = try_receiving(sock) | ||
46 | if message then return nil, message end | ||
47 | _,_, current, separator = string.find(line, "^(%d%d%d)(.)") | ||
48 | if not current or not separator then | ||
49 | return nil, "invalid server reply" | ||
50 | end | ||
51 | reply = reply .. "\n" .. line | ||
52 | -- reply ends with same code | ||
53 | until code == current and separator == " " | ||
54 | end | ||
55 | return code, reply | ||
56 | end | ||
57 | |||
58 | -- metatable for sock object | ||
59 | local metatable = { __index = {} } | ||
60 | |||
61 | -- execute the "check" instr | ||
62 | function metatable.__index:check(ok) | ||
63 | local code, reply = get_reply(self.sock) | ||
64 | if not code then return nil, reply end | ||
65 | if type(ok) ~= "function" then | ||
66 | if type(ok) ~= "table" then ok = {ok} end | ||
67 | for i, v in ipairs(ok) do | ||
68 | if string.find(code, v) then return code, reply end | ||
69 | end | ||
70 | return nil, reply | ||
71 | else return ok(code, reply) end | ||
72 | end | ||
73 | |||
74 | function metatable.__index:cmdchk(cmd, arg, ok) | ||
75 | local code, err = self:command(cmd, arg) | ||
76 | if not code then return nil, err end | ||
77 | return self:check(ok) | ||
78 | end | ||
79 | |||
80 | -- execute the "command" instr | ||
81 | function metatable.__index:command(cmd, arg) | ||
82 | if arg then return try_sending(self.sock, cmd .. " " .. arg.. "\r\n") | ||
83 | return try_sending(self.sock, cmd .. "\r\n") end | ||
84 | end | ||
85 | |||
86 | function metatable.__index:sink(snk, pat) | ||
87 | local chunk, err = sock:receive(pat) | ||
88 | return snk(chunk, err) | ||
89 | end | ||
90 | |||
91 | function metatable.__index:source(src, instr) | ||
92 | while true do | ||
93 | local chunk, err = src() | ||
94 | if not chunk then return not err, err end | ||
95 | local ret, err = try_sending(self.sock, chunk) | ||
96 | if not ret then return nil, err end | ||
97 | end | ||
98 | end | ||
99 | |||
100 | -- closes the underlying sock | ||
101 | function metatable.__index:close() | ||
102 | self.sock:close() | ||
103 | end | ||
104 | |||
105 | -- connect with server and return sock object | ||
106 | function connect(host, port) | ||
107 | local sock, err = socket.connect(host, port) | ||
108 | if not sock then return nil, message end | ||
109 | sock:settimeout(TIMEOUT) | ||
110 | return setmetatable({sock = sock}, metatable) | ||
111 | end | ||