From 58096449c6044b7aade5cd41cfd71c6bec1d273d Mon Sep 17 00:00:00 2001 From: Diego Nehab Date: Tue, 15 Jun 2004 06:24:00 +0000 Subject: Manual is almost done. HTTP is missing. Implemented new distribution scheme. Select is now purely C. HTTP reimplemented seems faster dunno why. LTN12 functions that coroutines fail gracefully. --- doc/ftp.html | 272 ++++++++++++++++++---------------- doc/ltn12.html | 421 ++++++++++++++++++++++++++++++++++++++++++++++++++++ doc/mime.html | 428 +++++++++++++++++++++++++++++++++++++++++++++++++++++ doc/reference.css | 3 + doc/reference.html | 89 +++++------ doc/smtp.html | 235 ++++++++++++++++++++++++----- doc/socket.html | 25 ++-- doc/tcp.html | 29 ++-- doc/udp.html | 5 + doc/url.html | 76 +++++----- 10 files changed, 1296 insertions(+), 287 deletions(-) create mode 100644 doc/ltn12.html create mode 100644 doc/mime.html (limited to 'doc') diff --git a/doc/ftp.html b/doc/ftp.html index 6776a17..a0c9268 100644 --- a/doc/ftp.html +++ b/doc/ftp.html @@ -35,9 +35,9 @@

FTP (File Transfer Protocol) is a protocol used to transfer files -between hosts. The module ftp.lua offers simple FTP support, -allowing applications to download and upload files, and list directory -contents. The implementation conforms to +between hosts. The module ftp.lua offers simple FTP support. +Applications can easily download and upload files. +The implementation conforms to RFC 959.

@@ -49,175 +49,191 @@ URLs MUST conform to
-[ftp://][<user>[:<password>]@]<host>[:<port>][/<path>][type=a|i|d] +[ftp://][<user>[:<password>]@]<host>[:<port>][/<path>][type=a|i]
+

+High level functions are provided supporting the most common operations. +These high level functions are implemented on top of a lower level +interface. By using the low-level interface, users can easily create their +own functions to access any operation supported by the FTP +protocol. For that, check the implementation. +

+ +

+To use some of the functions in this module, a good understanding of + +LTN012, Filters sources and sinks is necessary. +

+ +

+The following constants can be set to control the default behaviour of +the FTP module: +

+ + +

-socket.ftp.get(url)
-socket.ftp.get{
-  url = string,
-  type = string,
-  user = string,
-  password = string
+ftp.get(url)
+ftp.get{
+  host = string,
+  sink = LTN12 sink,
+  argument or path = string,
+  [user = string,]
+  [password = string]
+  [command = string,]
+  [port = number,]
+  [type = string,]
+  [step = LTN12 pump step],
}

-Downloads an URL from a FTP server. +The get function has two forms. The simple form has fixed +functionality: it downloads the contents of a URL and returns it as a +string. The generic form allows a lot more control, as explained +below.

-The function can be called either directly with a url -or with a request table. -Fields passed explicitly in the request table override those -present in the url. -

- -

-The parameter type accepts values 'a' (ASCII, the -default), 'i' (binary) or 'd' (directory listing) and -determines the transfer type. If <path> ends with a -'/' or type is 'd', a directory listing of -<path> is returned. If no user is provided in the -url or explicitly, the function tries to log in as user -'anonymous'. +If the argument of the get function is a table, the function +expects at least the fields host, sink, and one of +argument or path (argument takes +precedence). Host is the server to connect to. Sink is +the LTN12 sink that will receive the downloaded data. Argument or +path give the target path to the resource in the server. The +optional arguments are the following:

+

-If successful, the function returns -the file content as a string. In case of error, the function returns -nil and an error message describing the error. +If successful, the simple version returns the URL contents as a +string, and the generic function returns 1. In case of error, both +functions return nil and an error message describing the +error.

--- Log as user "anonymous" on server "ftp.tecgraf.puc-rio.br",
--- go to directory "pub/lua" and get file "lua.tar.gz" as binary.
-f, e = socket.ftp.get("ftp://ftp.tecgraf.puc-rio.br/pub/lua/lua.tar.gz;type=i")
+-- load the ftp support
+local ftp = require("ftp")
 
 -- Log as user "anonymous" on server "ftp.tecgraf.puc-rio.br",
--- go to director "pub" and retrieve directory listing of directory "lua"
-f, e = socket.ftp.get("ftp://ftp.tecgraf.puc-rio.br/pub/lua;type=d")
-
--- Log as user "diego", password "nehab", on server "ftp.tecgraf.puc-rio.br",
--- go to directory "tec/luasocket/bin" and retrieve file "luasocket.exe"
--- (actually, fails because of wrong password, of course)
-f, e = socket.ftp.get{
-  url = "ftp://ftp.tecgraf.puc-rio.br/tec/luasocket/bin/luasocket.exe",
-  user = "diego",
-  password = "nehab",
-  type = "i"
-}
--- f returns nil, and e returns an appropriate error message
+-- and get file "lua.tar.gz" from directory "pub/lua" as binary.
+f, e = ftp.get("ftp://ftp.tecgraf.puc-rio.br/pub/lua/lua.tar.gz;type=i")
 
- - -

-socket.ftp.get_cb{
-  url = string,
-  type = string,
-  content_cb = receive-callback,
-  user = string,
-  password = string
-} -

- -

-Same as get, but the library returns -the content of the downloaded file to the receive callback -content_cb. -

- -

-Note: for more information on callbacks, refer to -Streaming with callbacks. -

+
+-- load needed modules
+local ftp = require("ftp")
+local ltn12 = require("ltn12")
+local url = require("url")
+
+-- a function that returns a directory listing
+function ls(u)
+    local t = {}
+    local p = url.parse(u)
+    p.command = "nlst"
+    p.sink = ltn12.sink.table(t)
+    local r, e = ftp.get(p)
+    return r and table.concat(t), e
+end
+

-socket.ftp.put(url, content)
-socket.ftp.put{
-  url = string,
-  content = string,
-  type = string,
-  user = string,
-  password = string
+ftp.put(url, content)
+ftp.put{
+  host = string,
+  source = LTN12 sink,
+  argument or path = string,
+  [user = string,]
+  [password = string]
+  [command = string,]
+  [port = number,]
+  [type = string,]
+  [step = LTN12 pump step],
}

-Upload a file to a FTP server. +The put function has two forms. The simple form has fixed +functionality: it uploads a string of content into a URL. The generic form +allows a lot more control, as explained below.

-The function can be called directly with a -url and content parameters, or with a -request table. -Values passed explicitly in the request table override those present in -the url. The parameter type accept values -'a' (ASCII, the default) or 'i' (binary) and -determines the transfer type. If no user is provided, the -function tries to log in as 'anonymous'. +If the argument of the put function is a table, the function +expects at least the fields host, source, and one of +argument or path (argument takes +precedence). Host is the server to connect to. Source is +the LTN12 source that will provide the contents to be uploaded. +Argument or +path give the target path to the resource in the server. The +optional arguments are the following:

+

-If successful, the function returns 1. In case of error, the -function returns nil followed by a string describing the error. +Both functions return 1 if successful, or nil and an error +message describing the reason for failure.

--- Log as user "anonymous" on server "ftp.free.org" and store file
--- "hello" with contents "hello world!", using binary mode for the transfer
-r, e = socket.ftp.put("ftp://ftp.free.org/hello;type=i", "hello world!\n")
-
--- Does exactly the same, but logging in as diego
-r, e = socket.ftp.put{
-  url = "ftp://ftp.free.org/hello",
-  type = "i",
-  user = "diego",
-  password = "nehab",
-  content = "hello world\n"
-}
-
- - - - -

-socket.ftp.put_cb{
-  url = string,
-  type = string,
-  content_cb = send-callback,
-  user = string,
-  password = string
-} -

- -

-Same as put, but the -library obtains the contents of the file to be uploaded using the send -callback content_cb. -

+-- load the ftp support +local ftp = require("ftp") -

-Note: for more information on callbacks, refer to -Streaming with callbacks. -

+-- Log as user "diego" on server "ftp.tecgraf.puc-rio.br", +-- using password "nehab", and store a file "README" with contents +-- "wrong password, of course" +f, e = ftp.put("ftp://diego:nehab@ftp.tecgraf.puc-rio.br/README", "wrong password, of course") +
--- Log as user "anonymous" on server "ftp.free.org" and store file
--- "hello" with contents of the same file in the current directory, 
--- using binary mode for the transfer
-r, e = socket.ftp.put_cb{
-  url = "ftp://ftp.free.org/hello",
-  type = "i",
-  content_cb = socket.callback.send_file(io.open("hello", "r"))
+-- load the ftp support
+local ftp = require("ftp")
+local ltn12 = require("ltn12")
+
+-- Log as user "diego" on server "ftp.tecgraf.puc-rio.br",
+-- using password "nehab", and append to the file "LOG", sending the
+-- contents of a local file 
+f, e = ftp.put{
+  host = "ftp.tecgraf.puc-rio.br", 
+  user = "diego",
+  password = "nehab",
+  command = "appe",
+  argument = "LOG",
+  source = ltn12.source.file(io.open("LOCAL-LOG", "r"))
 }
 
- + diff --git a/doc/ltn12.html b/doc/ltn12.html new file mode 100644 index 0000000..363ce43 --- /dev/null +++ b/doc/ltn12.html @@ -0,0 +1,421 @@ + + + + +LuaSocket: Network support for the Lua language + + + + + + + +
+
+
+ + + +
+LuaSocket +
Network support for the Lua language +
+

+home · +download · +introduction · +reference +

+
+
+
+ + + +

LTN12

+ +

The LTN12 module implements the ideas described in + +LTN012, Filters sources and sinks. This manual simply describe the +functions. Please refer to the LTN for a deeper explanation of the +functionality provided by this module. +

+ + + +

Filters

+ + + +

+ltn12.filter.chain(filter1, filter2 +[, ... filterN]) +

+ +

+Returns a filter that passes all data it receives through each of a +series of given filters. +

+ +

+Filter1 to filterN are simple +filters. +

+ +

+The function returns the chained filter. +

+ +

+The nesting of filters can be arbritrary. For instance, the useless filter +below doesn't do anything but return the data that was passed to it, +unaltered. +

+ +
+-- load required modules
+ltn12 = require("ltn12")
+mime = require("mime")
+
+-- create a silly identity filter
+id = ltn12.filter.chain(
+  mime.encode("quoted-printable"),
+  mime.encode("base64"),
+  mime.decode("base64"),
+  mime.decode("quoted-printable")
+)
+
+ + + +

+ltn12.filter.cycle(low [, ctx, extra]) +

+ +

+Returns a high-level filter that cycles though a low-level filter by +passing it each chunk and updating a context between calls. +

+ +

+Low is the low-level filter to be cycled, +ctx is the initial context and extra is any extra +argument the low-level filter might take. +

+ +

+The function returns the high-level filter. +

+ +
+-- load the ltn12 module
+local ltn12 = require("ltn12")
+
+-- the base64 mime filter factory
+encodet['base64'] = function()
+    return ltn12.filter.cycle(b64, "")
+end
+
+ + + +

Pumps

+ + + +

+ltn12.pump.all(source, sink) +

+ +

+Pumps all data from a source to a sink. +

+ +

+If successful, the function returns a value that evaluates to +true. In case +of error, the function returns a false value, followed by an error message. +

+ + + +

+ltn12.pump.step(source, sink) +

+ +

+Pumps one chunk of data from a source to a sink. +

+ +

+If successful, the function returns a value that evaluates to +true. In case +of error, the function returns a false value, followed by an error message. +

+ + + +

Sinks

+ + + +

+ltn12.sink.chain(filter, sink) +

+ +

+Creates a new sink that passes data through a filter before sending +it to a given sink. +

+ +

+The function returns the new sink. +

+ + + +

+ltn12.sink.error(message) +

+ +

+Creates and returns a sink that aborts transmission with an error +message. +

+ + + +

+ltn12.sink.file(handle, message) +

+ +

+Creates a sink that sends data to a file. +

+ +

+Handle is a file handle. If handle is nil, +message should give the reason for failure. +

+ +

+The function returns a sink that sends all data to the given handle +and closes the file when done, or a sink that aborts the transmission with +an error message +

+ +

+In the following example, notice how the prototype is designed to +fit nicely with the io.open function. +

+ +
+-- load the ltn12 module
+local ltn12 = require("ltn12")
+
+-- copy a file
+ltn12.pump.all(
+  ltn12.source.file(io.open("original.png")),
+  ltn12.sink.file(io.open("copy.png"))
+)
+
+ + + +

+ltn12.sink.null() +

+ +

+Returns a sink that ignores all data it receives. +

+ + + +

+ltn12.sink.simplify(sink) +

+ +

+Creates and returns a simple sink given a fancy sink. +

+ + + +

+ltn12.sink.table([table]) +

+ +

+Creates a sink that stores all chunks in a table. The chunks can later be +efficiently concatenated into a single string. +

+ +

+Table is used to hold the chunks. If +nil, the function creates its own table. +

+ +

+The function returns the sink and the table. +

+ +
+-- load needed modules
+local http = require("http")
+local ltn12 = require("ltn12")
+
+-- the http.get function
+function get(u)
+  local t = {}
+  local respt = request{
+    url = u,
+    sink = ltn12.sink.table(t)
+  }
+  return table.concat(t), respt.headers, respt.code, respt.error
+end
+
+ + + +

Sources

+ + + +

+ltn12.source.cat(source1 [, source2, ..., +sourceN]) +

+ +

+Creates a new source that produces the concatenation of the data produced +by a number of sources. +

+ +

+Source1 to sourceN are the original +sources. +

+ +

+The function returns the new source. +

+ + + +

+ltn12.source.chain(source, filter) +

+ +

+Creates a new source that passes data through a filter +before returning it. +

+ +

+The function returns the new source. +

+ + + +

+ltn12.source.empty() +

+ +

+Creates and returns an empty source. +

+ + + +

+ltn12.source.error(message) +

+ +

+Creates and returns a source that aborts transmission with an error +message. +

+ + + +

+ltn12.source.file(handle, message) +

+ +

+Creates a source that produces the contents of a file. +

+ +

+Handle is a file handle. If handle is nil, +message should give the reason for failure. +

+ +

+The function returns a source that reads chunks of data from +given handle and returns it to the user, +closing the file when done, or a source that aborts the transmission with +an error message +

+ +

+In the following example, notice how the prototype is designed to +fit nicely with the io.open function. +

+ +
+-- load the ltn12 module
+local ltn12 = require("ltn12")
+
+-- copy a file
+ltn12.pump.all(
+  ltn12.source.file(io.open("original.png")),
+  ltn12.sink.file(io.open("copy.png"))
+)
+
+ + + +

+ltn12.source.simplify(source) +

+ +

+Creates and returns a simple source given a fancy source. +

+ + + +

+ltn12.source.string(string) +

+ +

+Creates and returns a source that produces the contents of a +string, chunk by chunk. +

+ + + + + + + diff --git a/doc/mime.html b/doc/mime.html new file mode 100644 index 0000000..d2fcc3c --- /dev/null +++ b/doc/mime.html @@ -0,0 +1,428 @@ + + + + +LuaSocket: Network support for the Lua language + + + + + + + +
+
+
+ + + +
+LuaSocket +
Network support for the Lua language +
+

+home · +download · +introduction · +reference +

+
+
+
+ + + +

MIME

+ +

+The MIME module offers filters that apply and remove common +content transfer encodings, such as Base64 and Quoted-Printable. +It also provides functions to break text into lines and change +the end-of-line convention. +MIME is described mainly in +RFC 2045, +2046, +2047, +2048 and +2049. +

+ +

+All functionality provided by the MIME module +follows the ideas presented in + +LTN012, Filters sources and sinks. +

+ + + +

High-level filters

+ + + +

+mime.normalize([marker]) +

+ +

+Converts most common end-of-line markers to a specific given marker. +

+ +

+Marker is the new marker. It defaults to CRLF, the canonic +end-of-line marker defined by the MIME standard. +

+ +

+The function returns a filter that performs the conversion. +

+ +

+Note: There is no perfect solution to this problem. Different end-of-line +markers are an evil that will probably plague developers forever. +This function, however, will work perfectly for text created with any of +the most common end-of-line markers, i.e. the MacOS (CR), the Unix (LF), +or the DOS (CRLF) conventions. Even if the data has mixed end-of-line +markers, the function will still work well, although it doesn't +guarantee that the number of empty lines will be correct. +

+ + + +

+mime.decode("base64")
+mime.decode("quoted-printable") +

+ +

+Returns a filter that decodes data from a given transfer content +encoding. +

+ +

+The function returns the created filter. +

+ + + +

+mime.encode("base64")
+mime.encode("quoted-printable" [, mode]) +

+ +

+Returns a filter that encodes data according to a given transfer content +encoding. +

+ +

+In the Quoted-Printable case, the user can specify whether the data is +textual or binary, by passing the mode strings "text" or +"binary". Mode defaults to "text". +

+ +

+The function returns the created filter. +

+ +

+Although both transfer content encodings specify a limit for the line +length, the encoding filters do not break text into lines (for +added flexibility). +Below is a filter that converts binary data to the Base64 transfer content +encoding and breaks it into lines of the correct size. +

+ +
+base64 = ltn12.filter.chain(
+  mime.encode("base64"),
+  mime.wrap("base64")
+)
+
+ +

+Note: Text data has to be converted to canonic form +before being encoded. +

+ +
+base64 = ltn12.filter.chain(
+  mime.normalize(),
+  mime.encode("base64"),
+  mime.wrap("base64")
+)
+
+ + + +

+mime.wrap("text" [, length])
+mime.wrap("base64")
+mime.wrap("quoted-printable") +

+ +

+Returns a filter that breaks data into lines. +

+ +

+The "text" line-wrap filter simply breaks text into lines by +inserting CRLF end-of-line markers at appropriate positions. +Length defaults 76. +The "base64" line-wrap filter works just like the default +"text" line-wrap filter with default length. +The function can also wrap "quoted-printable" lines, taking care +not to break lines in the middle of an escaped character. In that case, the +line length is fixed at 76. +

+ +

+The function returns the created filter. +

+ +

+For example, to create an encoding filter for the Quoted-Printable transfer content encoding of text data, do the following: +

+ +
+qp = ltn12.filter.chain(
+  mime.normalize(),
+  mime.encode("quoted-printable"),
+  mime.wrap("quoted-printable")
+)
+
+ +

+Note: To break into lines with a different end-of-line convention, apply +a normalization filter after the line break filter. +

+ + + +

Low-level filters

+ + + +

+A, B = mime.b64(C [, D]) +

+ +

+Low-level filter to perform Base64 encoding. +

+ +

+A is the encoded version of the largest prefix of +C..D +that can be encoded unambiguously. B has the remaining bytes of +C..D, before encoding. +If D is nil, A is padded with +the encoding of the remaining bytes of C. +

+ +

+Note: The simplest use of this function is to encode a string into it's +Base64 transfer content encoding. Notice the extra parenthesis around the +call to mime.b64, to discard the second return value. +

+ +
+print((mime.b64("diego:password")))
+--> ZGllZ286cGFzc3dvcmQ=
+
+ + + +

+A, B = mime.eol(C [, D, marker]) +

+ +

+Low-level filter to perform end-of-line marker translation. +For each chunk, the function needs to know if the last character of the +previous chunk could be part of an end-of-line marker or not. This is the +context the function receives besides the chunk. An updated version of +the context is returned after each new chunk. +

+ +

+A is the translated version of D. C is the +ASCII value of the last character of the previous chunk, if it was a +candidate for line break, or 0 otherwise. +B is the same as C, but for the current +chunk. If D is nil, A includes a +new end-of-line marker, depending on C. +Marker gives the new end-of-line marker and defaults to CRLF. +

+ +
+-- translates the end-of-line marker to UNIX
+unix = mime.eol(0, dos, "\n") 
+
+ + + +

+A, B = mime.qp(C [, D, marker]) +

+ +

+Low-level filter to perform Quoted-Printable encoding. +

+ +

+A is the encoded version of the largest prefix of +C..D +that can be encoded unambiguously. B has the remaining bytes of +C..D, before encoding. +If D is nil, A is padded with +the encoding of the remaining bytes of C. +Throughout encoding, occurences of CRLF are replaced by the +marker, which itself defaults to CRLF. +

+ +

+Note: The simplest use of this function is to encode a string into it's +Quoted-Printable transfer content encoding. +Notice the extra parenthesis around the call to mime.qp, to discard the second return value. +

+ +
+print((mime.qp("maçã")))
+--> ma=E7=E3=
+
+ + + +

+A, m = mime.qpwrp(n [, B, length]) +

+ +

+Low-level filter to break Quoted-Printable text into lines. +

+ +

+A is a copy of B, broken into lines of at most +length bytes (defaults to 76). +'n' should tell how many bytes are left for the first +line of B and 'm' returns the number of bytes +left in the last line of A. +

+ +

+Note: Besides breaking text into lines, this function makes sure the line +breaks don't fall in the middle of an escaped character combination. Also, +this function only breaks lines that are bigger than length bytes. +

+ + + +

+A, B = mime.unb64(C [, D]) +

+ +

+Low-level filter to perform Base64 decoding. +

+ +

+A is the decoded version of the largest prefix of +C..D +that can be decoded unambiguously. B has the remaining bytes of +C..D, before decoding. +If D is nil, A is the empty string +and B returns whatever couldn't be decoded. +

+ +

+Note: The simplest use of this function is to decode a string from it's +Base64 transfer content encoding. +Notice the extra parenthesis around the call to mime.unqp, to discard the second return value. +

+ +
+print((mime.unb64("ZGllZ286cGFzc3dvcmQ=")))
+--> diego:password
+
+ + + +

+A, B = mime.unqp(C [, D]) +

+ +

+Low-level filter to remove the Quoted-Printable transfer content encoding +from data. +

+ +

+A is the decoded version of the largest prefix of +C..D +that can be decoded unambiguously. B has the remaining bytes of +C..D, before decoding. +If D is nil, A is augmented with +the encoding of the remaining bytes of C. +

+ +

+Note: The simplest use of this function is to decode a string from it's +Quoted-Printable transfer content encoding. +Notice the extra parenthesis around the call to mime.unqp, to discard the second return value. +

+ +
+print((mime.qp("ma=E7=E3=")))
+--> maçã
+
+ + + +

+A, m = mime.wrp(n [, B, length]) +

+ +

+Low-level filter to break text into lines with CRLF marker. +Text is assumed to be in the normalize form. +

+ +

+A is a copy of B, broken into lines of at most +length bytes (defaults to 76). +'n' should tell how many bytes are left for the first +line of B and 'm' returns the number of bytes +left in the last line of A. +

+ +

+Note: This function only breaks lines that are bigger than +length bytes. The resulting line length does not include the CRLF +marker. +

+ + + + + + + + diff --git a/doc/reference.css b/doc/reference.css index 607ac4f..7c8148d 100644 --- a/doc/reference.css +++ b/doc/reference.css @@ -10,6 +10,9 @@ tt { h1, h2, h3, h4 { margin-left: 0em; } + +h3 { padding-top: 1em; } + p { margin-left: 1em; } p.name { diff --git a/doc/reference.html b/doc/reference.html index ba519c0..ebcfb5b 100644 --- a/doc/reference.html +++ b/doc/reference.html @@ -36,7 +36,7 @@

Reference

-DNS services (socket.dns) +DNS (in socket)
toip, tohostname, @@ -47,31 +47,17 @@
-FTP (socket.ftp) +FTP
get, -put, -open. +put
- - -
-Global symbols -
-LUASOCKET_LIBNAME, -mime, -ltn12, -socket. -
-
- -
-HTTP (socket.http) +HTTP
get, post, @@ -82,46 +68,45 @@
-LTN012 (ltn12) +LTN12
filter: -chain, -cycle. +chain, +cycle.
pump: -all, -step. +all, +step.
sink: -chain, -error, -file, -null, -simplify, -table. +chain, +error, +file, +null, +simplify, +table.
source: -cat, -chain, -empty, -file, -simplify, -rewind, -string. +cat, +chain, +empty, +error, +file, +simplify, +string.
-MIME (mime) +MIME
high-level: normalize, -chain, decode, encode, wrap. @@ -141,9 +126,8 @@
-SMTP (socket.smtp) +SMTP
-open, message, send.
@@ -152,26 +136,20 @@
-The socket namespace (socket) +Socket
-bind, -connect, -debug, +DEBUG, dns, -ftp, -http, protect, select, sink, source, sleep, -smtp, time, tcp, try, udp, -url, -version. +VERSION.
@@ -179,7 +157,7 @@
-TCP (socket.tcp) +TCP (in socket)
accept, bind, @@ -198,7 +176,7 @@
-UDP (socket.udp) +UDP (in socket)
close, getpeername, @@ -210,23 +188,22 @@ setpeername, setsockname, setoption, -settimeout, -shutdown. +settimeout.
-URL (socket.url) +URL
absolute, build, build_path, -quote, +escape, parse, parse_path, -unquote. +unescape.
diff --git a/doc/smtp.html b/doc/smtp.html index 0862de0..b0ae634 100644 --- a/doc/smtp.html +++ b/doc/smtp.html @@ -35,15 +35,22 @@

SMTP

-

-The smtp.lua module provides functionality to send e-mail +

The smtp.lua module provides functionality to send e-mail messages. The implementation conforms to the Simple Mail Transfer Protocol, RFC 2821. -The other RFC of interest in this implementation is -RFC 2822, +Another RFC of interest is RFC 2822, which governs the Internet Message Format. +Multipart messages (those that contain attatchments) are part +of the MIME standard, but described mainly +in RFC +2046 -

+

In the description below, good understanding of LTN012, Filters +sources and sinks and the MIME module is +assumed. In fact, the SMTP module was the main reason for their +creation.

MIME headers are represented as a Lua table in the form: @@ -78,29 +85,56 @@ Note: MIME headers are independent of order. Therefore, there is no problem in representing them in a Lua table.

- +

+The following constants can be set to control the default behaviour of +the SMTP module: +

-

-socket.smtp.mail{
+

    +
  • DOMAIN: domain used to greet the server; +
  • PORT: default port used for the connection; +
  • SERVER: default server used for the connection; +
  • TIMEOUT: default timeout for all I/O operations; +
  • ZONE: default time zone. +
+ + + +

+smtp.send{
  from = string,
  rcpt = string or string-table,
-  body = string,
-  headers = headers-table,
-  server = string
+  source = LTN12 source,
+  [server = string],
+  [port = string]
+  [domain = string],
+  [step = LTN12 pump step],
}

-Sends a message to a recipient list. +Sends a message to a recipient list. Since sending messages is not as +simple as downloading an URL from a FTP or HTTP server, this function +doesn't have a simple interface. However, see the +message source factory for +a very powerful way to define the message contents.

-Rcpt is a Lua table with one entry for each recipient, or a string +The sender is given by the e-mail address in the from field. +Rcpt is a Lua table with one entry for each recipient e-mail +address, or a string in case there is just one recipient. -The sender is given by the e-mail address from. -The message is composed by the optional MIME Headers headers -and text body. The message is sent using the server -server. +The contents of the message are given by a LTN12 source. Several +arguments are optional: +

    +
  • server: Server to connect to. Defaults to "localhost"; +
  • port: Port to connect to. Defaults to 25; +
  • domain: Domain name used to greet the server; Defaults to the +local machine host name; +
  • step: LTN12 pump step function used to pass data from the +source to the server. Defaults to the LTN12 pump.step function. +

@@ -108,6 +142,13 @@ If successful, the function returns 1. Otherwise, the function returns nil followed by an error message.

+

+Note: SMTP servers are can be very picky with the format of e-mail +addresses. To be safe, use only addresses of the form +"<fulano@tecgraf.puc-rio.br>" in the from and +rcpt arguments to the send function. In headers, e-mail +addresses can take whatever form you like.

+

Big note: There is a good deal of misconception with the use of the destination address field headers, i.e., the 'To', 'Cc', @@ -117,11 +158,12 @@ exact opposite of what you expect.

-Only recipients specified in the recipient list will receive a copy of the +Only recipients specified in the rcpt list will receive a copy of the message. Each recipient of an SMTP mail message receives a copy of the -message body along with the headers, and nothing more. The headers are -considered as part of the message. The list of recipients is not -part of the message. +message body along with the headers, and nothing more. The headers +are part of the message and should be produced by the LTN12 +source function. The rcpt list is not +part of the message and will not be sent to anyone.

@@ -143,9 +185,9 @@ Copy") contains addresses of recipients of the message whose addresses are not t

-The LuaSocket mail function does not interpret the headers you -pass to, but it gives you full control over what is sent and to whom -it is sent: +The LuaSocket send function does not care or interpret the +headers you send, but it gives you full control over what is sent and +to whom it is sent:

  • If someone is to receive the message, the e-mail address has @@ -171,36 +213,147 @@ and

    +-- load the smtp support
    +local smtp = require("smtp")
    +
     -- Connects to server "localhost" and sends a message to users
     -- "fulano@tecgraf.puc-rio.br",  "beltrano@tecgraf.puc-rio.br", 
     -- and "sicrano@tecgraf.puc-rio.br".
     -- Note that "fulano" is the primary recipient, "beltrano" receives a
     -- carbon copy and neither of them knows that "sicrano" received a blind
     -- carbon copy of the message.
    -headers = {
    -  to = "fulano@tecgraf.puc-rio.br",
    -  cc = "beltrano@tecgraf.puc-rio.br",
    -  subject = "LuaSocket test message"
    -}
    -
    -from = "luasocket@tecgraf.puc-rio.br"
    +from = "<luasocket@tecgraf.puc-rio.br>"
     
     rcpt = {
    -  "fulano@tecgraf.puc-rio.br",
    -  "beltrano@tecgraf.puc-rio.br",
    -  "sicrano@tecgraf.puc-rio.br"
    +  "<fulano@tecgraf.puc-rio.br>",
    +  "<beltrano@tecgraf.puc-rio.br>",
    +  "<sicrano@tecgraf.puc-rio.br>"
     }
     
    -body = "This is a test message. Please ignore."
    -
    -server = "localhost"
    +mesgt = {
    +  headers = {
    +    to = "Fulano da Silva <fulano@tecgraf.puc-rio.br>",
    +    cc = '"Beltrano F. Nunes" <beltrano@tecgraf.puc-rio.br>',
    +    subject = "My first message"
    +  }
    +  body = "I hope this works. If it does, I can send you another 1000 copies."
    +}
     
    -r, e = socket.smtp.mail{
    +r, e = smtp.send{
       from = from,
       rcpt = rcpt, 
    -  headers = headers, 
    -  body = body, 
    -  server = server
    +  source = smtp.message(mesgt)
    +}
    +
    + + + +

    +smtp.message(mesgt) +

    + +

    +Returns a LTN12 source that sends an SMTP message body, possibly multipart +(arbitrarily deep). +

    + +

    +The only parameter of the function is a table describing the message. +Mesgt has the following form (notice the recursive structure): +

    + +
    + + +
    +mesgt = {
    +  headers = header-table,
    +  body = LTN12 source or string or +multipart-mesgt
    +}

    +multipart-mesgt = {
    +  preamble = string
    +  [1] = mesgt,
    +  [2] = mesgt,
    +  ...
    +  [n] = mesgt,
    +  epilogue = string,
    +}
    +
    +
    + +

    +For a simple message, all that is needed is a set of headers +and the body. The message body can be given as a string +or as a LTN12 source. For multipart messages, the body is a table that +recursively defines each part as an independent message, plus a preamble +and an epilogue. +

    + +

    +The function returns an LTN12 source that produces the message contents as +defined by mesgt. Hopefuly, the following example will make +things clear. When in doubt, refer to the appropriate RFC as listed in the +introduction.

    + +
    +-- load the smtp support and its friends
    +local smtp = require("smtp")
    +local mime = require("mime")
    +local ltn12 = require("ltn12")
    +
    +-- creates a source to send a message with two parts. The first part is 
    +-- plain text, the second part is a PNG image, encoded as base64.
    +source = smtp.message{
    +  headers = {
    +     -- Remember that headers are *ignored* by smtp.send. 
    +     from = "Sicrano de Oliveira <sicrano@tecgraf.puc-rio.br>",
    +     to = "Fulano da Silva <fulano@tecgraf.puc-rio.br>",
    +     subject = "Here is a message with attachments"
    +  },
    +  body = {
    +    preamble = "If your client doesn't understand attachments, \r\n" ..
    +               "it will still display the preamble and the epilogue.\r\n",
    +               "Preamble might show up even in a MIME enabled client.",
    +    -- first part: no headers means plain text, us-ascii.
    +    -- The mime.eol low-level filter normalizes end-of-line markers.
    +    [1] = { 
    +      body = mime.eol(0, [[
    +        Lines in a message body should always end with CRLF. 
    +        The smtp module will *NOT* perform translation. It will
    +        perform necessary stuffing or '.' characters, though.
    +      ]])
    +    },
    +    -- second part: headers describe content to be a png image, 
    +    -- sent under the base64 transfer content encoding.
    +    -- notice that nothing happens until the message is actually sent. 
    +    -- small chunks are loaded into memory right before transmission and 
    +    -- translation happens on the fly.
    +    [2] = { 
    +      headers = {
    +        ["content-type"] = 'image/png; name="image.png"',
    +        ["content-disposition"] = 'attachment; filename="image.png"',
    +        ["content-description"] = 'a beautiful image',
    +        ["content-transfer-encoding"] = "BASE64"
    +      },
    +      body = ltn12.source.chain(
    +        ltn12.source.file(io.open("image.png", "rb")),
    +        ltn12.filter.chain(
    +          mime.encode("base64"),
    +          mime.wrap()
    +        )
    +      )
    +    },
    +    epilogue = "This might also show up, but after the attachments"
    +  }
    +}
    +
    +-- finally send it
    +r, e = smtp.send{
    +    from = "<sicrano@tecgraf.puc-rio.br>",
    +    rcpt = "<fulano@tecgraf.puc-rio.br>",
    +    source = source,
     }
     
    diff --git a/doc/socket.html b/doc/socket.html index bde882b..eccc676 100644 --- a/doc/socket.html +++ b/doc/socket.html @@ -36,16 +36,13 @@

    The socket namespace

    -The socket namespace contains the namespace tables for all -LuaSocket modules as well as function that didn't belong in any specific -module, functions that are so commonly used that deserve a shortcut and a -few constants. +The socket namespace contains the core functionality of LuaSocket.

    -socket.debug +socket.DEBUG

    @@ -57,7 +54,7 @@ with debug support.

    -socket.protect(function) +socket.protect(func)

    @@ -65,12 +62,12 @@ Converts a function that throws exceptions into a safe function.

    -Function is a function that calls +Funct is a function that calls try to throw exceptions.

    -The function an equivalent function that instead of throwing exceptoins, +Returns an equivalent function that instead of throwing exceptions, returns nil followed by an error message.

    @@ -103,16 +100,16 @@ simplify the test if a specific socket has changed status.

    -Important Note: a known bug in WinSock causes select to fail +Important note: a known bug in WinSock causes select to fail on non-blocking TCP sockets. The function may return a socket as writable even though the socket is not ready for sending.

    -Important note: calling select with a server socket in the receive +Another important note: calling select with a server socket in the receive parameter before a call to accept does not guarantee accept will return immediately. -Use the timeout +Use the settimeout method or accept might block forever.

    @@ -131,7 +128,7 @@ socket.sink(mode, socket)

    Creates an -LTN012 +LTN12 sink from a stream socket object.

    @@ -163,7 +160,7 @@ socket.source(mode, socket [, length])

    Creates an -LTN012 +LTN12 source from a stream socket object.

    @@ -217,7 +214,7 @@ c = socket.try(socket.connect("localhost", 80))

    -socket.version +socket.VERSION

    diff --git a/doc/tcp.html b/doc/tcp.html index 34d6c6e..7a49660 100644 --- a/doc/tcp.html +++ b/doc/tcp.html @@ -241,18 +241,16 @@ method returns nil followed by an error message.

    -client:receive([pattern1, pattern2, -... patternN]) +client:receive([pattern])

    Reads data from a client object, according to the specified read -patterns. Patterns follow the Lua file I/O format, and the difference in performance between all patterns is negligible. +pattern. Patterns follow the Lua file I/O format, and the difference in performance between all patterns is negligible.

    -The parameters pattern1, pattern2, ... -patternN can be any of the following: +Pattern can be any of the following:

      @@ -267,16 +265,21 @@ of bytes from the socket.

    -The method returns one value for each pattern, followed by a single -error code that can be nil in case of success, the string -'closed' in case the connection was closed before the -transmission was completed or the string 'timeout' in case -there was a timeout during the operation. +If successful, the method returns the received pattern. In case of error, +the method returns nil followed by an error message which +can be the string 'closed' in case the connection was +closed before the transmission was completed or the string +'timeout' in case there was a timeout during the operation. +Also, after the error message, the function returns the partial result of +the transmission.

    -Note: In case of error, the method always return everything it managed -to download before the error condition was met. +Important note: This function was changed severely. It used +to support multiple patterns (but I have never seen this feature used) and +partial results used to be returned in the same way as successful results. +This last feature violated the idea that all functions should return +nil on error. Thus the change.

    @@ -428,7 +431,7 @@ client:shutdown(mode)

    -Shuts down part of a full duplex connection. +Shuts down part of a full-duplex connection.

    diff --git a/doc/udp.html b/doc/udp.html index 9f5cf8f..5ae0a89 100644 --- a/doc/udp.html +++ b/doc/udp.html @@ -29,6 +29,11 @@


    + + + +

    UDP

    +

    diff --git a/doc/url.html b/doc/url.html index f3a7cb7..cd699a2 100644 --- a/doc/url.html +++ b/doc/url.html @@ -59,7 +59,7 @@ An URL is defined by the following grammar:

    -socket.url.absolute(base, relative) +url.absolute(base, relative)

    @@ -79,7 +79,7 @@ The function returns a string with the absolute URL. Note: The rules that govern the composition are fairly complex, and are described in detail in RFC 2396. -The example bellow should give an idea of what are the rules. +The example bellow should give an idea of what the rules are.

    @@ -114,7 +114,7 @@ g;x?y#s  =  http://a/b/c/g;x?y#s
     
     
     

    -socket.url.build(parsed_url) +url.build(parsed_url)

    @@ -135,7 +135,7 @@ The function returns a string with the built URL.

    -socket.url.build_path(segments, unsafe) +url.build_path(segments, unsafe)

    @@ -157,10 +157,39 @@ The function returns a string with the built <path> component.

    + + +

    +url.escape(content) +

    + +

    +Applies the URL escaping content coding to a string +Each byte is encoded as a percent character followed +by the two byte hexadecimal representation of its integer +value. +

    + +

    +Content is the string to be encoded. +

    + +

    +The function returns the encoded string. +

    + +
    +-- load url module
    +url = require("url")
    +
    +code = url.escape("/#?;")
    +-- code = "%2f%23%3f%3b"
    +
    +

    -socket.url.parse(url, default) +url.parse(url, default)

    @@ -196,7 +225,10 @@ parsed_url = {

-parsed_url = socket.url.parse("http://www.puc-rio.br/~diego/index.lua?a=2#there")
+-- load url module
+url = require("url")
+
+parsed_url = url.parse("http://www.puc-rio.br/~diego/index.lua?a=2#there")
 -- parsed_url = {
 --   scheme = "http",
 --   authority = "www.puc-rio.br",
@@ -206,7 +238,7 @@ parsed_url = socket.url.parse("http://www.puc-rio.br/~diego/index.lua?a=2#there"
 --   host = "www.puc-rio.br",
 -- }
 
-parsed_url = socket.url.parse("ftp://root:passwd@unsafe.org/pub/virus.exe;type=i")
+parsed_url = url.parse("ftp://root:passwd@unsafe.org/pub/virus.exe;type=i")
 -- parsed_url = {
 --   scheme = "ftp",
 --   authority = "root:passwd@unsafe.org",
@@ -222,7 +254,7 @@ parsed_url = socket.url.parse("ftp://root:passwd@unsafe.org/pub/virus.exe;type=i
 
 
 

-socket.url.parse_path(path) +url.parse_path(path)

@@ -241,36 +273,10 @@ returning a list with all the parsed segments, the function unescapes all of them.

- - -

-socket.url.escape(content) -

- -

-Applies the URL escaping content coding to a string -Each byte is encoded as a percent character followed -by the two byte hexadecimal representation of its integer -value. -

- -

-Content is the string to be encoded. -

- -

-The function returns the encoded string. -

- -
-code = socket.url.escape("/#?;")
--- code = "%2f%23%3f%3b"
-
-

-socket.url.unescape(content) +url.unescape(content)

-- cgit v1.2.3-55-g6feb