Main
Language
Runtime
Tools
FAQs
Changes
Download
Licence
cheesy

The Idle Networking Library

This is the preliminary documentation for the Idle socket and networking library. If you want to use any of its functions, you will need to put a require('socket') statement into your program. As with the Idle runtime, require()ing the main module once automatically makes all the other socket modules available: after a require('socket') you can directly use all function in modules mime or socket.http, without explicitly require()ing them.

All global variables and functions in this library fall into one of seven modules:

Module socket
top of page

This is the core networking module. It provides the basic infrastructure for socket calls and supplies submodules for creating UDP and TCP connection objects, server- and client-side.

socket.BLOCKSIZE
top of page

Blocksize to be used for incoming network data. Default is 2048.

socket.bind(address,port[,backlog])
top of page

This function creates and returns a TCP server object bound to a local address and port, ready to accept client connections. The optional backlog argument is forwarded to the listen method (default is 32). Note: the server object returned will have the option 'reuseaddr' set to true.

socket.connect(address,port[,laddress[,lport]])
top of page

This function creates and returns a TCP client object connected to a remote host at a given port. Local address and port to bind to (laddress and lport) can be specified as well.

socket.dns.gethostname()
top of page

Returns a string with the standard host name for the local machine.

socket.dns.tohostname(address)
top of page

Converts from IP address to host name. address can be an IP address or a host name. The function returns a string with the canonical host name of the given address, followed by a table with all information returned by the resolver. In case of error, the function returns nil followed by an error message. The returned table has the following fields:

socket.dns.toip(address)
top of page

Converts from host name to IP address. address can be an IP address or a host name. Returns a string with the first IP address found for address, followed by a table with all information returned by the resolver (see dns.tohostname()). In case of error, the function returns nil followed by an error message.

socket.gettime()
top of page

Returns the time in seconds, relative to some unspecified start point. You should subtract the values returned by this function to get meaningful values.

socket.newtry(finaliser)
top of page

Creates and returns a try function that allows for cleanup before an exception is raised. finaliser is a function that will be called before the try function throws the exception. finaliser will be called in protected mode. See also socket.try(). A simple example:

foo=socket.protect(function()
  -- connect somewhere
  local c=socket.try(socket.connect('somewhere',42))
  -- create a try function that closes 'c' on error
  local mytry=socket.newtry(function() c:close() end)
  -- do something... whatever happens, c will be closed
  mytry(c:send('hello there?\r\n'))
  local answer=mytry(c:receive())
  -- more stuff to do...
  mytry(c:send('good bye\r\n'))
  c:close()
end)

socket.protect(func)
top of page

Converts a function that can throw an exception into a safe function and returns that. This function catches exceptions thrown by the socket.try() and socket.newtry() functions (see there). func is a function that calls socket.try() (or assert( ) or error( )) to throw exceptions. Returns an equivalent function that instead of throwing exceptions, returns nil followed by an error message. Note: if your function performs some illegal operation that raises an error, the protected function will catch the error and return it as a string. This is because socket.try() uses errors as the mechanism to throw exceptions.

socket.select(recvt,sendt[,timeout])
top of page

Waits for a number of sockets to change status. recvt is an array with sockets to test for data available for reading. Sockets in the sendt array are watched to see if it is acceptable to write on them. timeout is the maximum amount of time (in seconds) to wait for a change in status. A nil, negative or omitted timeout value allows socket.select() to block indefinitely. recvt and sendt can be empty tables or nil. Non-socket values, closed sockets or values with non-numeric indices in both arrays will be ignored.

The function returns a table with the sockets ready for reading and a second table with the sockets ready for writing and an error message. The error message is 'timeout' if a timeout condition was met and nil otherwise. The returned tables are associative, to simplify the test if a specific socket has changed status.

Important note: a known bug in some WinSock versions can cause socket.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.

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 settimeout() method or accept() might block forever.

socket.sink(mode,socket)
top of page

Creates a sink from a stream socket object (see Idle module dataxf for sinks and sources). mode defines the behavior of the sink. The following options are available:

socket is the stream socket object used to send the data. The function returns a sink with the appropriate behavior.

socket.skip(n,...)
top of page

Skips n arguments (after reading n) and returns the remaining arguments. This function is useful to avoid the creation of dummy variables:

-- get status code and separator from SMTP server reply
local code,sep=socket.skip(2,string.find(line,'^(%d%d%d)(.?)'))

socket.sleep(n)
top of page

Sleeps for n seconds (n is truncated to the nearest integer). Under Windows, this call is equivalent to os.sleep(n*1000).

socket.source(mode,socket[,length]))
top of page

Creates a source from a stream socket object (see module dataxf for sinks and sources). mode defines the behavior of the source. The following options are available:

Socket is the stream socket object used to receive the data. The function returns a source with the appropriate behavior.

socket.tcp()
top of page

Creates and returns a TCP master object. A master object can be transformed into a server object with the listen() method (after a call to bind()) or into a client object with the connect() method. The only other method supported by a master object is close(). In case of success, the function will return a new master object. In case of error, nil is returned, followed by an error message. See tcp object methods for descriptions of the methods defined for tcp objects.

socket.try(...)
top of page

Throws an exception in case of error. The exception must be caught by the socket.protect() function. The arguments can be arbitrary, but are usually the return values of a function call nested within socket.try(). The function returns the arguments if the first argument is not nil. Otherwise, it calls error( ) passing the second argument. Example:

-- connects or throws an exception with the appropriate error message
c = socket.try(socket.connect('localhost', 80))

socket.udp()
top of page

Creates and returns an unconnected UDP object. Unconnected objects support the udp:sendto( ), udp:receive( ), udp:receivefrom( ), udp:getsockname( ), udp:setoption( ), udp:settimeout( ), udp:setpeername( ), udp:setsockname( ) and udp:close( ) methods. udp:setpeername( ) is used to connect the object. The function returns a new unconnected UDP object or, in case of error, nil followed by an error message. See udp object methods for descriptions of the methods defined for udp objects.

tcp object methods
top of page

A tcp object is either a master, a server or a client, although not all tcp methods work with all object types. See the following descriptions.

server:accept()
top of page

Waits for a remote connection on the server object. If a connection is successfully initiated, a client object representing that connection is returned. If a timeout condition is met, the method returns nil followed by the error string 'timeout'. Other errors are reported by nil followed by a message describing the error. Note: calling socket.select() with a server object in the recvt parameter before a call to accept() does not guarantee accept() will return immediately. Use the settimeout() method or accept() might block until another client shows up.

master:bind(address,port)
top of page

Binds a master object to address and port on the local host. address can be an IP address or a host name. port must be an integer number in the range [0..64K). If address is '*', the system binds to all local interfaces using the INADDR_ANY constant. If port is 0, the system automatically chooses an ephemeral port. In case of success, the method returns 1. In case of error, the method returns nil followed by an error message. Note: The function socket.bind() is a shortcut for the creation of server sockets.

master:close()
top of page

client:close()

server:close()
top of page

Closes a TCP object. The internal socket used by the object is closed and the local address to which the object was bound is made available to other applications. No further operations (except for further calls to the close method) are allowed on a closed socket. Note: It is important to close all used sockets if they are not needed anymore: in many systems, each socket uses a file descriptor, which is a limited system resource. Garbage-collected objects are automatically closed before destruction.

master:connect(address,port)
top of page

Attempts to connect a master object to a remote host, transforming it into a client object. Client objects support methods send(), receive(), getsockname(), getpeername(), settimeout(), and close(). address can be an IP address or a host name. port must be an integer number in the range [1..64K). In case of error, the method returns nil followed by a string describing the error. In case of success, the method returns 1.

The settimeout() method affects the behavior of connect(), causing it to return with an error in case of a timeout. If that happens, you can still call socket.select() with the socket in the sendt table. The socket will be writable when the connection is established.

Note: The function socket.connect() is a shortcut for the creation of client sockets.

client:getpeername()
top of page

Queries information about the remote side of a connected client object. Returns a string with the IP address of the peer, followed by the port number that peer is using for the connection. In case of an error, the method returns nil. Note: It makes no sense to call this method on server objects.

master:getsockname()
top of page

client:getsockname()

server:getsockname()
top of page

Returns the local address information associated to the object. The method returns a string with local IP address and a number with the port. In case of an error, the method returns nil.

master:getstats()
top of page

client:getstats()

server:getstats()
top of page

Returns accounting information on the socket, useful for throttling of bandwidth. The method returns the number of bytes received, the number of bytes sent, and the age of the socket object in seconds.

master:listen(backlog)
top of page

Specifies the socket is willing to receive connections, transforming the object into a server object. Server objects support the accept(), getsockname(), setoption(), settimeout(), and close() methods. The parameter backlog specifies the number of client connections that can be queued waiting for service. If the queue is full and another client attempts connection, the connection is refused. In case of success, the method returns 1. In case of an error, the method returns nil followed by an error message.

client:receive([pattern[,prefix]])
top of page

Reads data from a client object, according to the specified read pattern. This pattern follows the Idle file I/O format; the difference in performance between different patterns is negligible. pattern can be any of the following:

prefix is an optional string to be concatenated to the beginning of any received data. If successful, the method returns the received pattern. In case of an 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.

client:send(data[,i[,j]])
top of page

Sends data through client object. data is the string to be sent. The optional arguments i and j work exactly like the standard string.sub() function to allow the selection of a substring to be sent. If successful, the method returns the index of the last byte within [i,j] that has been sent. Notice that, if i is 1 or absent, this is effectively the total number of bytes sent. In case of an error, the method returns nil, followed by an error message, followed by the index of the last byte within [i,j] that has been sent. You might want to try again from the byte following that. The error message can be '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.

Note: Output is not buffered. For small strings, it is better to concatenate them in Idle (with the '..' operator) and send the result in one call instead of calling this method several times.

client:setoption(option[,value])
top of page

server:setoption(option[,value])

Sets options for the TCP object. Options are only needed by low-level or time-critical applications. You should only modify an option if you are sure you need it. option is a string with the option name, and value depends on the option being set:

The method returns 1 in case of success, or nil otherwise.

master:setstats(received,sent,age)
top of page

client:setstats(received,sent,age)

server:setstats(received,sent,age)
top of page

Resets accounting information on the socket, useful for throttling of bandwidth. received is a number with the new number of bytes received. sent is a number with the new number of bytes sent. age is the new age in seconds. The method returns 1 in case of success and nil otherwise.

master:settimeout(value[,mode])
top of page

client:settimeout(value[,mode])

server:settimeout(value[,mode])
top of page

Changes the timeout values for the object. By default, all I/O operations are blocking. That is, any call to the methods send(), receive(), and accept() will block indefinitely, until the operation completes. The settimeout() method defines a limit on the amount of time the I/O methods can block. When a timeout is set and the specified amount of time has elapsed, the affected methods give up and fail with an error code.

The amount of time to wait is specified in parameter value, in seconds. There are two timeout modes and both can be used together for fine tuning:

* 't': total timeout. Specifies the upper limit on the amount of time the socket library can block a script before returning from a call.

A negative timeout value or nil allows operations to block indefinitely.

Note: large blocks can cause I/O functions not to respect timeout values due to the time the library takes to transfer blocks to and from the OS and to and from the Idle interpreter. Also, functions that accept host names and perform automatic name resolution might be blocked by the resolver for longer than the specified timeout value.

client:shutdown([mode])
top of page

Shuts down part of a full-duplex connection. mode tells which direction of the connection should be shut down; it can take the following values:

This function returns 1.

udp object methods
top of page

A udp object is either connected or unconnected and not all methods work with both types. See the following descriptions.

connected:close()
top of page

unconnected:close()

Closes a UDP object. The internal socket used by the object is closed and the local address to which the object was bound is made available to other applications. No further operations (except for further calls to the close method) are allowed on a closed socket. Note: It is important to close all used sockets if they are not needed anymore: in many systems, each socket uses a file descriptor, which is a limited system resource. Garbage-collected objects are automatically closed before destruction.

connected:getpeername()
top of page

Retrieves information about the peer associated with a connected UDP object. Returns the IP address and port number of the peer. Note: It makes no sense to call this method on unconnected objects.

connected:getsockname()
top of page

unconnected:getsockname()

Returns the local address information associated to the object. The method returns a string with local IP address and a number with the port. In case of error, the method returns nil. Note: UDP sockets are not bound to an address until the setsockname() or the sendto() method is called for the first time (in which case it is bound to an ephemeral port and the wild-card address).

connected:receive([size])
top of page

unconnected:receive([size])

Receives a datagram from the UDP object. If the UDP object is connected, only datagrams coming from the peer are accepted. Otherwise, the returned datagram can come from any host. The optional size parameter specifies the maximum size of the datagram to be retrieved. If there are more than size bytes available in the datagram, the excess bytes are discarded. If there are less then size bytes available in the current datagram, the available bytes are returned. If size is omitted, the maximum datagram size is used (which is currently limited by the implementation to 8192 bytes). In case of success, the method returns the received datagram. In case of timeout, the method returns nil followed by the string 'timeout'.

unconnected:receivefrom([size])
top of page

Works exactly as the receive method, except it returns the IP address and port as extra return values (and is therefore slightly less efficient).

connected:send(datagram)
top of page

Sends a datagram to the UDP peer of a connected object. datagram is a string with the datagram contents. The maximum datagram size for UDP is 64K minus IP layer overhead. However, datagrams larger than the link layer packet size will be fragmented, which may deteriorate performance and/or reliability. If successful, the method returns 1. In case of error, the method returns nil followed by an error message.

Note: In UDP, the send() method never blocks and the only way it can fail is if the underlying transport layer refuses to send a message to the specified address (i.e. no interface accepts the address).

unconnected:sendto(datagram,ip,port)
top of page

Sends a datagram to the specified IP address and port number. datagram is a string with the datagram contents. The maximum datagram size for UDP is 64K minus IP layer overhead. However datagrams larger than the link layer packet size will be fragmented, which may deteriorate performance and/or reliability. ip is the IP address of the recipient. Host names are not allowed for performance reasons. port is the port number at the recipient. If successful, the method returns 1. In case of error, the method returns nil followed by an error message.

Note: In UDP, the send() method never blocks and the only way it can fail is if the underlying transport layer refuses to send a message to the specified address (i.e. no interface accepts the address).

connected:setpeername('*')
top of page

unconnected:setpeername(address,port)

Changes the peer of a UDP object. This method turns an unconnected UDP object into a connected UDP object or vice versa. For connected objects, outgoing datagrams will be sent to the specified peer, and datagrams received from other peers will be discarded by the OS. Connected UDP objects must use the send() and receive() methods instead of sendto() and receivefrom(). address can be an IP address or a host name. port is the port number. If address is '*' and the object is connected, the peer association is removed and the object becomes an unconnected object again. In that case, the port argument is ignored. In case of error, the method returns nil followed by an error message. In case of success, the method returns 1.

Note: Since the address of the peer does not have to be passed to and from the OS, the use of connected UDP objects is recommended when the same peer is used for several transmissions and can result in up to 30% performance gains.

unconnected:setsockname(address,port)
top of page

Binds the UDP object to a local address. address can be an IP address or a host name. If address is '*' the system binds to all local interfaces using the constant INADDR_ANY. If port is 0, the system chooses an ephemeral port. If successful, the method returns 1. In case of error, the method returns nil followed by an error message.

Note: This method can only be called before a datagram is sent through the UDP object, and only once. Otherwise, the system automatically binds the object to all local interfaces and chooses an ephemeral port as soon as the first datagram is sent. After the local address is set, either automatically by the system or explicitly by setsockname, it cannot be changed.

connected:setoption(option[,value])
top of page

unconnected:setoption(option[,value])

Sets options for the UDP object. Options are only needed by low-level or time-critical applications. You should only modify an option if you are sure you need it. option is a string with the option name, and value depends on the option being set:

The method returns 1 in case of success, or nil followed by an error message otherwise.

connected:settimeout(value)
top of page

unconnected:settimeout(value)

Changes the timeout values for the object. By default, the receive() and receivefrom() operations are blocking. That is, any call to the methods will block until data arrives. The settimeout() function defines a limit on the amount of time the functions can block. When a timeout is set and the specified amount of time has elapsed, the affected methods give up and fail with an error code. The time to wait is specified as the value parameter, in seconds. A nil or negative timeout value forces operations to block indefinitely.

Note: For UDP, the send() and sendto() methods never block (the datagram is just passed to the OS and the call returns immediately). Therefore, the settimeout() method has no effect on them.

Module socket.ftp
top of page

This module implements a straightforward high-level interface for ftp connections, in both directions.

ftp.get(url) or ftp.get(table)
top of page

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 accepts a table as the sole argument; this gives much more control over the download process. In generic mode, the function is called like that:

ftp.get{
  host=string,
  sink=dataxf sink,
  argument (or path)=string,
  [user=string,]
  [password=string,]
  [command=string,]
  [port=number,]
  [type=string,]
  [step=dataxf pump step,]
  [create=function]
}

The fields host, sink, and either argument or path must be given. host is the server to connect to. sink is the simple dataxf sink that will receive the downloaded data. argument or path gives the target path to the resource in the server (if both are given, argument takes precedence). The optional arguments are as follows:

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.

Here is an example for the simple form of socket.ftp.get():

-- load the ftp module
local ftp=require('socket.ftp')
-- Log on as user 'anonymous' on server 'ftp.tecgraf.puc-rio.br',
-- 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')

And a second example for the generic form:

local ftp=require('socket.ftp')
local dataxf=require('dataxf')
local url=require('socket.url')
-- a function that returns a directory listing
function nlst(u)
  local t={}
  local p=url.parse(u)
  p.command='nlst'
  p.sink=dataxf.sink.table(t)
  local r,e=ftp.get(p)
  return r and table.concat(t),e
end

socket.ftp.PASSWORD
top of page

The default password for anonymous ftp ('anonymous@anonymous.org').

socket.ftp.PORT
top of page

The default port used for the control connection (21).

socket.ftp.put(url,content) or socket.ftp.put(table)
top of page

The put function also has two forms. The simple form uploads a string of content into a URL. If the sole argument of socket.ftp.put() is a table, the fields host, source, and either argument or path must be given. host is the server to connect to. source is the simple dataxf source that will provide the data to upload. argument or path gives the target path to the resource in the server (if both are given, argument takes precedence). The optional arguments are as follows:

The function returns 1 if successful, or nil and an error message describing the reason for failure.

-- load the ftp module
local ftp=require('socket.ftp')
-- Log on as user 'thomasl' on server 'ftp.example.com', using password
-- 'pink', and store a file 'README' with contents 'wrong password, of course'
f,e=ftp.put('ftp://thomasl:pink@ftp.example.com/README',
  'wrong password, of course')

An example for the second form:

local ftp = require('socket.ftp')
local dataxf = require('dataxf')
-- Log as user 'thomasl' on server 'ftp.example.com',using password
-- 'green', and append to the remote file 'LOG', sending the contents
-- of the local file 'LOCAL-LOG'
f,e=ftp.put{
  host='ftp.example.com',
  user='thomasl',
  password='green',
  command='appe',
  argument='LOG',
  source=dataxf.source.file(io.open('LOCAL-LOG','r'))
}

socket.ftp.TIMEOUT
top of page

The timeout for all I/O operations (60 seconds).

socket.ftp.USER
top of page

The default username for anonymous ftp ('anonymous').

Module socket.http
top of page

Slightly more complex than socket.ftp, the socket.http module provides http connectivity.

socket.http.PORT
top of page

The default port used for connections (80).

socket.http.PROXY
top of page

Proxy server used for connections. Defaults to no proxy.

socket.http.request(url[,body]) or http.request(table)
top of page

This function has two forms. The simple form downloads a URL given in string url using GET or POST: if the string body is provided, the function will perform a POST, otherwise, it performs a GET. If successful, the simple form returns the response body as a string, followed by the response status code, the response headers and the response status line. In case of failure, the function returns nil followed by an error message. Note: when sending a POST request, the simple interface adds a 'Content-type: application/x-www-form-urlencoded' header to the request. This is the type used by HTML forms. If you need another type, use the generic interface instead.

The generic form of socket.http.request() can perform any HTTP method; it accepts a table as its sole parameter:

socket.http.request{
  url=string,
  [sink=dataxf sink,]
  [method=string,]
  [headers=header-table,]
  [source=dataxf source,]
  [step=dataxf pump step,]
  [proxy=string,]
  [redirect=boolean,]
  [create=function]
}

The most important fields are the url and the simple dataxf sink that will receive the downloaded data. Any part of the url can be overridden by including the appropriate field in the request table. If authentication information is provided, the function uses the Basic Authentication Scheme (see below) to retrieve the document. If sink is nil, the function discards the downloaded data. The optional fields are used as follows:

The generic function returns the same information as the simple form, except that the first return value is simply the number 1 (as the body goes to the sink).

Even when the server fails to provide the contents of the requested URL (URL not found, for example), it often returns a message body (a web page informing the URL was not found or some other useless page). To make sure the operation was successful, check the returned status code. For a list of the possible values and their meanings, refer to RFC 2616.

Here are a two examples:

-- load the http module
local http=require('socket.http')
local dataxf=require('dataxf')
-- connect to server 'www.cs.princeton.edu' and retrieves this manual
-- file from /~diego/professional/luasocket/http.html' and print it to stdout
http.request{
  url='http://www.cs.princeton.edu/~diego/professional/luasocket/http.html',
  sink=dataxf.sink.file(io.stdout)
}
-- connect to server 'www.example.com' and try to retrieve
-- '/private/index.html'. Fails because authentication is needed.
b,c,h=http.request('http://www.example.com/private/index.html')
-- b has a page telling about the denied access,
-- h has authentication information
-- and c has the value 401 (Authentication Required)
-- tries to connect to server 'wrong.host' to retrieve '/'
-- and fails because the host does not exist.
r,e=http.request('http://wrong.host/')
-- r is nil; e has the value 'host not found'
-- Requests information about a document, without downloading it.
-- Useful, for example, if you want to display a download gauge and need
-- to know the size of the document in advance
r,c,h=http.request {
  method='HEAD',
  url='http://www.tecgraf.puc-rio.br/~diego'
}
-- r is 1, c is 200, and h would return the following headers:
-- h={
--  date = 'Tue, 18 Sep 2001 20:42:21 GMT',
--  server = 'Apache/1.3.12 (Unix)  (Red Hat/Linux)',
--  ['last-modified'] = 'Wed, 05 Sep 2001 06:11:20 GMT',
--  ['content-length'] = 15652,
--  ['connection'] = 'close',
--  ['content-Type'] = 'text/html'
-- }

Note: Some URLs are protected by their servers from anonymous download. For those URLs, the server must receive some sort of authentication along with the request or it will deny the download and return status '401 Authentication Required'. The HTTP/1.1 standard defines two authentication methods: the Basic Authentication Scheme and the Digest Authentication Scheme, both explained in detail in RFC 2068. The Basic Authentication Scheme sends <user> and <password> unencrypted to the server and is therefore considered unsafe. Unfortunately, by the time of this implementation, the wide majority of servers and browsers support the Basic Scheme only. Therefore, this is the method used by the toolkit whenever authentication is required.

-- load required modules
http=require('socket.http')
mime=require('mime')
-- Connect to server 'www.example.com' and tries to retrieve
-- '/private/index.html', using the provided name and password to
-- authenticate the request
b,c,h=http.request('http://fulano:silva@www.example.com/private/index.html')
-- Alternatively, one could fill the appropriate header and authenticate
-- the request directly:
r,c=http.request {
  url='http://www.example.com/private/index.html',
  headers={ authentication='Basic ' .. (mime.b64('fulano:silva')) }
}

socket.http.TIMEOUT
top of page

The default timeout for all I/O operations (60 seconds).

socket.http.USERAGENT
top of page

User agent reported to server (defaults to the string in Idle._VERSION)

Module socket.smtp
top of page

A tidy module for producing correctly formatted mail messages and sending them via smtp.

socket.smtp.DOMAIN
top of page

Domain name used to greet the server. Defaults to the contents of process environment variable SERVER_NAME, if defined, or 'localhost' otherwise.

socket.smtp.PORT
top of page

Default port used for the connection (25).

socket.smtp.send{table}
top of page

Sends a mail message to a recipient list. Sending messages is unfortunately not as simple as downloading data from a FTP or HTTP server, so this function does not have a simple form; it always requires a correctly initialised table. However, see the example for a message source factory below for a powerful way to define the message contents. The function is called like this:

socket.smtp.send{from=string,
  rcpt=string or string-table,
  source=dataxf source,
  [user=string,]
  [password=string,]
  [server=string,]
  [port=number,]
  [domain=string,]
  [step=dataxf pump step,]
  [create=function]
}

The from field has the e-mail address of the sender. rcpt is a list with one entry for each recipient e-mail address (or a string in case there is only one recipient). The contents of the message are given by a simple dataxf source. The other arguments are optional:

If successful, this function returns 1. Otherwise, the function returns nil followed by an error message.

Note: SMTP servers can be very picky with the format of e-mail addresses. To be safe, use only addresses of the form '<name@server.com>' in the from and rcpt fields in a socket.smtp.send() call. In message headers, e-mail addresses can take whatever form you like.

Only recipients specified in the rcpt list (or string) will receive a copy of the message. However, each recipient receives a copy of the message body along with all headers. These headers are part of the message and should be produced by the dataxf source function. The rcpt list is not part of the message and will not be sent to anyone. Confusing rcpt list entries (which define the recipients) and message headers (which define what the recipients see) can lead to undesirable results. For instance, adding a 'Bcc' header to your message is almost certainly not what you want because its contents will be seen by all recipients. To send a message to a 'Bcc' recipient, just give the address in the rcpt list, but do not include it in any of the message headers. (RFC 2822 has two important and short sections, '3.6.3. Destination address fields' and '5. Security considerations', explaining the proper use of these headers.)

In other words, the socket.smtp.send() function does neither care about nor interprets the message headers you send. However, it gives you full control over what is sent and to whom it is sent:

-- load the smtp module
local smtp=require('socket.smtp')
-- Connects to server 'localhost' and sends a message to users
-- 'fulano@example.com', 'beltrano@example.com' and 'sicrano@example.com'.
-- 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.
from='<socket.smtp@example.com>'
rcpt={
  '<fulano@example.com>',
  '<beltrano@example.com>',
  '<sicrano@example.com>'
}
mesgt={
  headers={
    to='Fulano da Silva <fulano@example.com>',
    cc=''Beltrano F. Nunes' <beltrano@example.com>',
    subject='a simple test message'
  },
  body='All you ever wanted to know about socket.smtp.send()!'
}
r,e=smtp.send{
  from=from,
  rcpt=rcpt,
  source=smtp.message(mesgt)
}

smtp.message(mesgt)
top of page

Returns a simple dataxf source that sends an SMTP message body, possibly multipart (arbitrarily deep). The only parameter is a table describing the message. mesgt has the following form (note that the structure can be recursive):

mesgt={
  headers=header-table,
  body=dataxf source or string or multipart-mesgt
}
multipart-mesgt={
  [preamble=string,]
  [1]=mesgt,
  [2]=mesgt,
  ...
  [n]=mesgt,
  [epilogue=string]
}

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

The function returns a simple dataxf source that produces the message contents as defined by mesgt, chunk by chunk. The following (longish) example should make things slightly clearer. When in doubt, refer to the appropriate RFC as listed above.

-- load smtp and mime modules
local smtp=require('socket.smtp')
-- 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: these headers are IGNORED by smtp.send()!
    from='Sicrano de Oliveira <sicrano@example.com>',
    to='Fulano da Silva <fulano@example.com>',
    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 will probably appear even in a MIME enabled client.',
    -- First part: no headers means plain text, us-ascii.
    -- The mime.eol low-level filter normalises 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. However, the
        send function *DOES* perform SMTP stuffing, whereas the message
        function does *NOT*.
      ]=])
    },
    -- Second part: headers describe content to be a png image, sent under
    -- the base64 transfer content encoding.
    -- Note that nothing happens until the message is actually sent. Then
    -- 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=dataxf.source.chain(
        dataxf.source.file(io.open('image.png','rb')),
        dataxf.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@example.com>',
    rcpt='<fulano@example.com>', -- this field describes the recipient
    source=source
}

socket.smtp.SERVER
top of page

Server used for the connection; defaults to 'localhost'.

socket.smtp.TIMEOUT
top of page

Default timeout for all I/O operations (60 seconds).

socket.smtp.ZONE
top of page

String with the default time zone ('-0000').

Module mime
top of page

Basic MIME helper functions, mainly for the smtp modules.

mime.normalize([marker])
top of page

Converts most common end-of-line markers to a specific given marker. marker is the new marker. It defaults to CRLF, the canonical 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 the problem of normalising line endings. Different end-of-line markers are an evil that will probably plague developers forever. This function, however, will work for text created with any of the most common end-of-line markers, i.e. the Mac OS (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 does not guarantee that the number of empty lines will be correct.

mime.decode("base64") or mime.decode("quoted-printable")
top of page

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

mime.encode("base64") or mime.encode("quoted-printable"[,mode])
top of page

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 string "text" or "binary" (defaults to "text"). 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=dataxf.filter.chain(
  mime.encode("base64"),
  mime.wrap("base64")
)

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

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

mime.stuff()
top of page

Creates and returns a filter that performs stuffing of SMTP messages. Note: The smtp.send() function calls this filter automatically. You do not need to chain it with your source, or apply it to your message body.

mime.wrap("text"[,length]) or mime.wrap("base64") or mime.wrap("quoted-printable")
top of page

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 to 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. To break into lines with a different end-of-line convention, apply a normalization filter after the line break filter.

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

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

Module url
top of page

This module implements a few support functions for URLs. A URL is defined by the following grammar:

<url>::=[<scheme>:][//<authority>][/<path>][;<params>][?<query>][#<fragment>]

<authority>::=[<userinfo>@]<host>[:<port>]

<userinfo>::=<user>[:<password>]

<path>::={<segment>/}<segment>

url.absolute(base,relative)
top of page

Builds an absolute URL from a base URL and a relative URL. base is a string with the base URL or a parsed URL table (see url.parse()). relative is a string with the relative URL. The function returns a string with the absolute URL. The rules that govern the composition of URLs are fairly complex, and are described in detail in RFC 2396. The following example for a base of 'http://a/b/c/d;p?q' should give you a rough idea what the rules are for different relative items:

g:h     = g:h
g       = http://a/b/c/g
./g     = http://a/b/c/g
g/      = http://a/b/c/g/
/g      = http://a/g
//g     = http://g
?y      = http://a/b/c/?y
g?y     = http://a/b/c/g?y
#s      = http://a/b/c/d;p?q#s
g#s     = http://a/b/c/g#s
g?y#s   = http://a/b/c/g?y#s
;x      = http://a/b/c/;x
g;x     = http://a/b/c/g;x
g;x?y#s = http://a/b/c/g;x?y#s
.       = http://a/b/c/
./      = http://a/b/c/
..      = http://a/b/
../     = http://a/b/
../g    = http://a/b/g
../..   = http://a/
../../  = http://a/
../../g = http://a/g

url.build(parsed_url)
top of page

Rebuilds an URL from its parts. parsed_url is a table with the components returned by url.parse(). Lower level components, if specified, take precedence over high level components of the URL grammar. The function returns a string with the final URL.

url.build_path(segments,unsafe)
top of page

Builds a <path> component from a list of <segment> parts. Before composition, any reserved characters found in a segment are escaped into their protected form, so that the resulting path is a valid URL path component. segments is a list of strings with the <segment> parts. If unsafe is anything but nil, reserved characters are left untouched. The function returns a string with the final <path> component.

url.escape(content)
top of page

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
require('url')
code=url.escape('/#?;')
-- code is now '%2f%23%3f%3b'

url.parse(url,default)
top of page

Parses a URL given as a string into a table with the components in their respective fields. url is the URL to be parsed. If the table default is present, it is used to store the parsed fields (otherwise a new, empty table is created). Only fields present in the URL are overwritten. Therefore, this table can be used to pass default values for each field. The function returns a table with the following URL components:

--[=[
parsed_url={
  url=string,
  scheme=string,
  authority=string,
  path=string,
  params=string,
  query=string,
  fragment=string,
  userinfo=string,
  host=string,
  port=string,
  user=string,
  password=string
}
--]=]
require('socket.url')
parsed_url=url.parse('http://www.example.com/cgilua/index.lua?a=2#there')
-- parsed_url will be a table with the fields:
--   scheme = 'http',
--   authority = 'www.example.com',
--   path = '/cgilua/index.lua'
--   query = 'a=2',
--   fragment = 'there',
--   host = 'www.puc-rio.br'

url.parse_path(path)
top of page

Breaks a <path> URL component into all its <segment> parts. path is a string with the path to be parsed. Since some characters are reserved in URLs, they must be escaped whenever present in a <path> component. Therefore, before returning a list with all the parsed segments, the function removes escaping from all of them.

url.unescape(content)
top of page

Removes the URL escaping content coding from a string. content is the string to be decoded. The function returns the decoded string.



$$ built from IdleSocket.txt d106963c4f77 Mon Sep 27 13:27:10 2010 +0000 thomasl $$