util-soc.lua / last modification: 2020-01-30 14:16
if not modules then modules = { } end modules ['util-soc'] = {
    version   = 1.001,
    comment   = "support for sockets / protocols",
    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
    copyright = "PRAGMA ADE / ConTeXt Development Team",
    license   = "see context related readme files"


In LuaTeX we provide the socket library that is more or less the standard one for
Lua. It has been around for a while and seems to be pretty stable. The binary
module is copmpiled into LuaTeX and the accompanying .lua files are preloaded.
These files are mostly written by Diego Nehab, Andre Carregal, Javier Guerra, and
Fabio Mascarenhas with contributions from Diego Nehab, Mike Pall, David Burgess,
Leonardo Godinho, Thomas Harning Jr., and Gary NG. The originals are part of and
copyrighted by the Kepler project.

Here we reload a slightly reworked version of these .lua files. We keep the same
(documented) interface but streamlined some fo the code. No more modules, no more
pre 5.2 Lua, etc. Also, as it loads into the ConTeXt ecosystem, we plug in some
logging. (and maybe tracing in the future). As we don't support serial ports in
LuaTeX, related code has been dropped.

The files are reformatted so that we can more easilly add additional features
and/or tracing options. Any error introduced there is our fault! The url module
might be replaced by the one in ConTeXt. When we need mbox a suitable variant
will be provided.


local format = string.format

local smtp  = require("socket.smtp")
local ltn12 = require("ltn12")
local mime  = require("mime")

local mail     = utilities.mail or { }
utilities.mail = mail

local report_mail = logs.reporter("mail")

function mail.send(specification)
    local presets = specification.presets
    if presets then
    local server = specification.server or ""
    if not server then
        report_mail("no server specified")
        return false, "invalid server"
    local to = specification.to or specification.recepient or ""
    if to == "" then
        report_mail("no recipient specified")
        return false, "invalid recipient"
    local from = specification.from or specification.sender or ""
    if from == "" then
        report_mail("no sender specified")
        return false, "invalid sender"
    local message = { }
    local body = specification.body
    if body then
        message[#message+1] = {
            body = body
    local files = specification.files
    if files then
        for i=1,#files do
            local filename = files[i]
            local handle = io.open(filename, "rb")
            if handle then
                report_mail("attaching file %a",filename)
                message[#message+1] = {
                    headers = {
                        ["content-type"]              = format('application/pdf; name="%s"',filename),
                        ["content-disposition"]       = format('attachment; filename="%s"',filename),
                        ["content-description"]       = format('file: %s',filename),
                        ["content-transfer-encoding"] = "BASE64"
                    body = ltn12.source.chain(
                report_mail("file %a not found",filename)
    local user     = specification.user
    local password = specification.password
    local result, detail = smtp.send {
        server   = specification.server,
        port     = specification.port,
        user     = user ~= "" and user or nil,
        password = password ~= "" and password or nil,
        from     = from,
        rcpt     = to,
        source   = smtp.message {
            headers = {
                to      = to,
                from    = from,
                cc      = specification.cc,
                subject = specification.subject or "no subject",
            body = message
    if detail then
        report_mail("error: %s",detail)
        return false, detail
        report_mail("message sent")
        return true

-- for now we have this here:

if socket then

    math.initialseed = tonumber(string.sub(string.reverse(tostring(math.ceil(socket.gettime()*10000))),1,6))