You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

125 lines
3.6 KiB

  1. -----------------------------------------------------------------------------
  2. -- Unified SMTP/FTP subsystem
  3. -- LuaSocket toolkit.
  4. -- Author: Diego Nehab
  5. -- RCS ID: $Id: tp.lua,v 1.23 2009/05/27 09:31:35 diego Exp $
  6. -----------------------------------------------------------------------------
  7. -----------------------------------------------------------------------------
  8. -- Declare module and import dependencies
  9. -----------------------------------------------------------------------------
  10. local base = _G
  11. local string = require("string")
  12. local socket = require("preload.tools.socket")
  13. local ltn12 = require("preload.tools.ltn12")
  14. module("socket.tp")
  15. -----------------------------------------------------------------------------
  16. -- Program constants
  17. -----------------------------------------------------------------------------
  18. TIMEOUT = 60
  19. -----------------------------------------------------------------------------
  20. -- Implementation
  21. -----------------------------------------------------------------------------
  22. -- gets server reply (works for SMTP and FTP)
  23. local function get_reply(c)
  24. local code, current, sep
  25. local line, err = c:receive()
  26. local reply = line
  27. if err then return nil, err end
  28. code, sep = socket.skip(2, string.find(line, "^(%d%d%d)(.?)"))
  29. if not code then return nil, "invalid server reply" end
  30. if sep == "-" then -- reply is multiline
  31. repeat
  32. line, err = c:receive()
  33. if err then return nil, err end
  34. current, sep = socket.skip(2, string.find(line, "^(%d%d%d)(.?)"))
  35. reply = reply .. "\n" .. line
  36. -- reply ends with same code
  37. until code == current and sep == " "
  38. end
  39. return code, reply
  40. end
  41. -- metatable for sock object
  42. local metat = { __index = {} }
  43. function metat.__index:check(ok)
  44. local code, reply = get_reply(self.c)
  45. if not code then return nil, reply end
  46. if base.type(ok) ~= "function" then
  47. if base.type(ok) == "table" then
  48. for i, v in base.ipairs(ok) do
  49. if string.find(code, v) then
  50. return base.tonumber(code), reply
  51. end
  52. end
  53. return nil, reply
  54. else
  55. if string.find(code, ok) then return base.tonumber(code), reply
  56. else return nil, reply end
  57. end
  58. else return ok(base.tonumber(code), reply) end
  59. end
  60. function metat.__index:command(cmd, arg)
  61. cmd = string.upper(cmd)
  62. if arg then
  63. return self.c:send(cmd .. " " .. arg.. "\r\n")
  64. else
  65. return self.c:send(cmd .. "\r\n")
  66. end
  67. end
  68. function metat.__index:sink(snk, pat)
  69. local chunk, err = c:receive(pat)
  70. return snk(chunk, err)
  71. end
  72. function metat.__index:send(data)
  73. return self.c:send(data)
  74. end
  75. function metat.__index:receive(pat)
  76. return self.c:receive(pat)
  77. end
  78. function metat.__index:getfd()
  79. return self.c:getfd()
  80. end
  81. function metat.__index:dirty()
  82. return self.c:dirty()
  83. end
  84. function metat.__index:getcontrol()
  85. return self.c
  86. end
  87. function metat.__index:source(source, step)
  88. local sink = socket.sink("keep-open", self.c)
  89. local ret, err = ltn12.pump.all(source, sink, step or ltn12.pump.step)
  90. return ret, err
  91. end
  92. -- closes the underlying c
  93. function metat.__index:close()
  94. self.c:close()
  95. return 1
  96. end
  97. -- connect with server and return c object
  98. function connect(host, port, timeout, create)
  99. local c, e = (create or socket.tcp)()
  100. if not c then return nil, e end
  101. c:settimeout(timeout or TIMEOUT)
  102. local r, e = c:connect(host, port)
  103. if not r then
  104. c:close()
  105. return nil, e
  106. end
  107. return base.setmetatable({c = c}, metat)
  108. end