mirror of
https://github.com/lunarmodules/luasocket.git
synced 2024-12-26 04:28:20 +01:00
Adjusted lp.lua.
This commit is contained in:
parent
7115c12fbc
commit
1812d6ce15
283
etc/lp.lua
283
etc/lp.lua
@ -1,17 +1,40 @@
|
|||||||
|
|
||||||
|
--[[
|
||||||
|
if you have any questions RFC 1179
|
||||||
|
]]
|
||||||
-- make sure LuaSocket is loaded
|
-- make sure LuaSocket is loaded
|
||||||
local socket = require("socket")
|
local socket = require("socket")
|
||||||
local ltn12 = require("ltn12")
|
local ltn12 = require("ltn12")
|
||||||
local lp = {}
|
local test = socket.try
|
||||||
--socket.lp = lp
|
|
||||||
-- make all module globals fall into lp namespace
|
|
||||||
setmetatable(lp, { __index = _G })
|
|
||||||
setfenv(1, lp)
|
|
||||||
|
|
||||||
-- default port
|
-- default port
|
||||||
PORT = 515
|
PORT = 515
|
||||||
SERVER = os.getenv("SERVER_NAME") or os.getenv("COMPUTERNAME") or "localhost"
|
SERVER = os.getenv("SERVER_NAME") or os.getenv("COMPUTERNAME") or "localhost"
|
||||||
PRINTER = os.getenv("PRINTER") or "printer"
|
PRINTER = os.getenv("PRINTER") or "printer"
|
||||||
|
|
||||||
|
local function connect(localhost, option)
|
||||||
|
local host = option.host or SERVER
|
||||||
|
local port = option.port or PORT
|
||||||
|
local skt
|
||||||
|
local try = socket.newtry(function() if skt then skt:close() end end)
|
||||||
|
if option.localbind then
|
||||||
|
-- bind to a local port (if we can)
|
||||||
|
local localport = 721
|
||||||
|
repeat
|
||||||
|
skt = test(socket.tcp())
|
||||||
|
try(skt:settimeout(30))
|
||||||
|
local done, err = skt:bind(localhost, localport)
|
||||||
|
if not done then
|
||||||
|
localport = localport + 1
|
||||||
|
skt:close()
|
||||||
|
skt = nil
|
||||||
|
else break end
|
||||||
|
until localport > 731
|
||||||
|
test(skt, err)
|
||||||
|
else skt = test(socket.tcp()) end
|
||||||
|
try(skt:connect(host, port))
|
||||||
|
return { skt = skt, try = try }
|
||||||
|
end
|
||||||
|
|
||||||
--[[
|
--[[
|
||||||
RFC 1179
|
RFC 1179
|
||||||
@ -50,23 +73,16 @@ RFC 1179
|
|||||||
contain ASCII HT control characters.
|
contain ASCII HT control characters.
|
||||||
]]
|
]]
|
||||||
|
|
||||||
|
|
||||||
-- gets server acknowledement
|
-- gets server acknowledement
|
||||||
local function recv_ack(connection)
|
local function recv_ack(con)
|
||||||
local code, current, separator, _
|
local ack = con.skt:receive(1)
|
||||||
local ack = socket.try(connection:receive(1))
|
con.try(string.char(0) == ack, "failed to receive server acknowledement")
|
||||||
if string.char(0) ~= ack then
|
|
||||||
connection:close(); error"failed to receive server acknowledement"
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- sends client acknowledement
|
-- sends client acknowledement
|
||||||
local function send_ack(connection)
|
local function send_ack(con)
|
||||||
local sent = socket.try(connection:send(string.char(0)))
|
local sent = con.skt:send(string.char(0))
|
||||||
if not sent or sent ~= 1 then
|
con.try(sent == 1, "failed to send acknowledgement")
|
||||||
connection:close();
|
|
||||||
error"failed to send acknowledgement"
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- sends queue request
|
-- sends queue request
|
||||||
@ -86,14 +102,12 @@ end
|
|||||||
-- octet from the daemon. A positive acknowledgement is an octet of
|
-- octet from the daemon. A positive acknowledgement is an octet of
|
||||||
-- zero bits. A negative acknowledgement is an octet of any other
|
-- zero bits. A negative acknowledgement is an octet of any other
|
||||||
-- pattern.
|
-- pattern.
|
||||||
local function send_queue(connection,queue)
|
local function send_queue(con, queue)
|
||||||
if not queue then queue=PRINTER end
|
queue = queue or PRINTER
|
||||||
local str = string.format("\2%s\10",queue)
|
local str = string.format("\2%s\10", queue)
|
||||||
local sent = socket.try(connection:send(str))
|
local sent = con.skt:send(str)
|
||||||
if not sent or sent ~= string.len(str) then
|
con.try(sent == string.len(str), "failed to send print request")
|
||||||
error "failed to send print request"
|
recv_ack(con)
|
||||||
end
|
|
||||||
recv_ack(connection)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- sends control file
|
-- sends control file
|
||||||
@ -145,48 +159,36 @@ end
|
|||||||
-- processing must occur at this point.
|
-- processing must occur at this point.
|
||||||
|
|
||||||
|
|
||||||
local function send_hdr(connection,control)
|
local function send_hdr(con, control)
|
||||||
local sent = socket.try(connection:send(control))
|
local sent = con.skt:send(control)
|
||||||
if not sent or sent < 1 then
|
con.try(sent and sent >= 1 , "failed to send header file")
|
||||||
error "failed to send file"
|
recv_ack(con)
|
||||||
end
|
|
||||||
recv_ack(connection)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function send_control(con, control)
|
||||||
local function send_control(connection,control)
|
local sent = con:send(control)
|
||||||
local sent = socket.try(connection:send(control))
|
con.try(sent and sent >= 1, "failed to send control file")
|
||||||
if not sent or sent < 1 then
|
send_ack(con)
|
||||||
error "failed to send file"
|
|
||||||
end
|
|
||||||
send_ack(connection)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local function send_data(connection,fh,size)
|
local function send_data(con,fh,size)
|
||||||
-- local sink = socket.sink("keep-open", connection)
|
local buf
|
||||||
-- ltn12.pump.all(source, sink)
|
|
||||||
local buf, st, message
|
|
||||||
st = true
|
|
||||||
while size > 0 do
|
while size > 0 do
|
||||||
buf,message = fh:read(8192)
|
buf,message = fh:read(8192)
|
||||||
if buf then
|
if buf then
|
||||||
st = socket.try(connection:send(buf))
|
st = con.try(con:send(buf))
|
||||||
size = size - st
|
size = size - st
|
||||||
else
|
else
|
||||||
if size ~= 0 then
|
con.try(size == 0, "file size mismatch")
|
||||||
connection:close()
|
|
||||||
return nil, "file size mismatch"
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
send_ack(connection)
|
send_ack(con)
|
||||||
recv_ack(connection)
|
recv_ack(con)
|
||||||
return size,nil
|
return size
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--[[
|
--[[
|
||||||
|
|
||||||
local control_dflt = {
|
local control_dflt = {
|
||||||
"H"..string.sub(socket.hostname,1,31).."\10", -- host
|
"H"..string.sub(socket.hostname,1,31).."\10", -- host
|
||||||
"C"..string.sub(socket.hostname,1,31).."\10", -- class
|
"C"..string.sub(socket.hostname,1,31).."\10", -- class
|
||||||
@ -206,44 +208,15 @@ local control_dflt = {
|
|||||||
"r"..file.."\10", -- fortran format
|
"r"..file.."\10", -- fortran format
|
||||||
"U"..file.."\10", -- Unlink (data file only)
|
"U"..file.."\10", -- Unlink (data file only)
|
||||||
}
|
}
|
||||||
|
|
||||||
]]
|
]]
|
||||||
|
|
||||||
-- generate a varying job number
|
-- generate a varying job number
|
||||||
local function getjobno(connection)
|
local seq = 0
|
||||||
-- print(math.mod(socket.time() * 1000, port)) -- ok for windows
|
local function newjob(connection)
|
||||||
-- print(os.time() / port,math.random(0,999))
|
seq = seq + 1
|
||||||
return math.random(0,999)
|
return math.floor(socket.gettime() * 1000 + seq)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function getcon(localhost,option)
|
|
||||||
local skt, st, message
|
|
||||||
local localport = 721
|
|
||||||
if not option then
|
|
||||||
error('no options',0)
|
|
||||||
end
|
|
||||||
if option.localbind then
|
|
||||||
repeat
|
|
||||||
-- bind to a local port (if we can)
|
|
||||||
skt = socket.try(socket.tcp())
|
|
||||||
skt:settimeout(30)
|
|
||||||
|
|
||||||
st, message = skt:bind(localhost,localport,-1);
|
|
||||||
-- print("bind",st,message)
|
|
||||||
if st then
|
|
||||||
st,message = skt:connect(option.host or SERVER, option.port or PORT)
|
|
||||||
-- print("connect",st,message)
|
|
||||||
end
|
|
||||||
-- print(st,localport,message)
|
|
||||||
if not st then
|
|
||||||
localport = localport + 1
|
|
||||||
skt:close()
|
|
||||||
end
|
|
||||||
until st or localport > 731 or (not st and message ~= "local address already in use")
|
|
||||||
if st then return skt end
|
|
||||||
end
|
|
||||||
return socket.try(socket.connect(option.host or SERVER, option.port or PORT))
|
|
||||||
end
|
|
||||||
|
|
||||||
local format_codes = {
|
local format_codes = {
|
||||||
binary = 'l',
|
binary = 'l',
|
||||||
@ -258,43 +231,33 @@ local format_codes = {
|
|||||||
f = 'f'
|
f = 'f'
|
||||||
}
|
}
|
||||||
|
|
||||||
lp.send = socket.protect(function(file, option)
|
-- lp.send
|
||||||
if not file then error "invalid file name" end
|
|
||||||
if not option or type(option) ~= "table" then error "invalid options" end
|
|
||||||
local fh = socket.try(io.open(file,"rb"))
|
|
||||||
-- get total size
|
|
||||||
local datafile_size = fh:seek("end")
|
|
||||||
-- go back to start of file
|
|
||||||
fh:seek("set")
|
|
||||||
math.randomseed(socket.time() * 1000)
|
|
||||||
local localhost = socket.dns.gethostname() or os.getenv("COMPUTERNAME") or "localhost"
|
|
||||||
|
|
||||||
-- local connection, message = skt:connect(option.host or SERVER, option.port or PORT)
|
|
||||||
|
|
||||||
local connection = getcon(localhost,option)
|
|
||||||
|
|
||||||
|
send = socket.protect(function(file, option)
|
||||||
|
test(file, "invalid file name")
|
||||||
|
test(option and type(option) == "table", "invalid options")
|
||||||
|
local fh = test(io.open(file,"rb"))
|
||||||
|
local datafile_size = fh:seek("end") -- get total size
|
||||||
|
fh:seek("set") -- go back to start of file
|
||||||
|
local localhost = socket.dns.gethostname() or os.getenv("COMPUTERNAME")
|
||||||
|
or "localhost"
|
||||||
|
local con = connect(localhost, option)
|
||||||
-- format the control file
|
-- format the control file
|
||||||
local jobno = getjobno(connection)
|
local jobno = newjob()
|
||||||
local localip = socket.dns.toip(localhost)
|
local localip = socket.dns.toip(localhost)
|
||||||
localhost = string.sub(localhost,1,31)
|
localhost = string.sub(localhost,1,31)
|
||||||
|
local user = string.sub(option.user or os.getenv("LPRUSER") or
|
||||||
local user = string.sub(option.user or os.getenv("LPRUSER") or os.getenv("USERNAME")
|
os.getenv("USERNAME") or os.getenv("USER") or "anonymous", 1,31)
|
||||||
or os.getenv("USER") or "anonymous",1,31)
|
|
||||||
|
|
||||||
local lpfile = string.format("dfA%3.3d%-s", jobno, localhost);
|
local lpfile = string.format("dfA%3.3d%-s", jobno, localhost);
|
||||||
|
|
||||||
local fmt = format_codes[option.format] or 'l'
|
local fmt = format_codes[option.format] or 'l'
|
||||||
|
|
||||||
local class = string.sub(option.class or localip or localhost,1,31)
|
local class = string.sub(option.class or localip or localhost,1,31)
|
||||||
|
|
||||||
local _,_,ctlfn = string.find(file,".*[%/%\\](.*)")
|
local _,_,ctlfn = string.find(file,".*[%/%\\](.*)")
|
||||||
ctlfn = string.sub(ctlfn or file,1,131)
|
ctlfn = string.sub(ctlfn or file,1,131)
|
||||||
|
|
||||||
local cfile =
|
local cfile =
|
||||||
string.format("H%-s\nC%-s\nJ%-s\nP%-s\n%.1s%-s\nU%-s\nN%-s\n",
|
string.format("H%-s\nC%-s\nJ%-s\nP%-s\n%.1s%-s\nU%-s\nN%-s\n",
|
||||||
localhost,
|
localhost,
|
||||||
class,
|
class,
|
||||||
option.job or ctlfn,
|
option.job or "LuaSocket",
|
||||||
user,
|
user,
|
||||||
fmt, lpfile,
|
fmt, lpfile,
|
||||||
lpfile,
|
lpfile,
|
||||||
@ -307,96 +270,40 @@ lp.send = socket.protect(function(file, option)
|
|||||||
cfile = cfile .. 'W'..tonumber(option,width)..'\10'
|
cfile = cfile .. 'W'..tonumber(option,width)..'\10'
|
||||||
end
|
end
|
||||||
|
|
||||||
connection:settimeout(option.timeout or 65)
|
con.skt:settimeout(option.timeout or 65)
|
||||||
|
|
||||||
-- send the queue header
|
-- send the queue header
|
||||||
send_queue(connection,option.queue)
|
send_queue(con, option.queue)
|
||||||
|
|
||||||
-- send the control file header
|
-- send the control file header
|
||||||
local cfilecmd = string.format("\2%d cfA%3.3d%-s\n",string.len(cfile), jobno, localhost);
|
local cfilecmd = string.format("\2%d cfA%3.3d%-s\n",string.len(cfile), jobno, localhost);
|
||||||
send_hdr(connection,cfilecmd)
|
send_hdr(con,cfilecmd)
|
||||||
|
|
||||||
-- send the control file
|
-- send the control file
|
||||||
send_control(connection,cfile)
|
send_control(con,cfile)
|
||||||
|
|
||||||
-- send the data file header
|
-- send the data file header
|
||||||
local dfilecmd = string.format("\3%d dfA%3.3d%-s\n",datafile_size, jobno, localhost);
|
local dfilecmd = string.format("\3%d dfA%3.3d%-s\n",datafile_size, jobno, localhost);
|
||||||
send_hdr(connection,dfilecmd)
|
send_hdr(con,dfilecmd)
|
||||||
|
|
||||||
-- send the data file
|
-- send the data file
|
||||||
send_data(connection,fh,datafile_size)
|
send_data(con,fh,datafile_size)
|
||||||
fh:close()
|
fh:close()
|
||||||
connection:close();
|
con.skt:close();
|
||||||
return datafile_size
|
return jobno, datafile_size
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
--
|
||||||
--socket.lpq({host=,queue=printer|'*', format='l'|'s', list=})
|
-- lp.query({host=,queue=printer|'*', format='l'|'s', list=})
|
||||||
lp.query = socket.protect(function(p)
|
--
|
||||||
if not p then p={} end
|
query = socket.protect(function(p)
|
||||||
local localhost = socket.dns.gethostname() or os.getenv("COMPUTERNAME") or "localhost"
|
p = p or {}
|
||||||
local connection = getcon(localhost,p)
|
local localhost = socket.dns.gethostname() or os.getenv("COMPUTERNAME")
|
||||||
local fmt,data
|
or "localhost"
|
||||||
|
local con = connect(localhost,p)
|
||||||
|
local fmt
|
||||||
if string.sub(p.format or 's',1,1) == 's' then fmt = 3 else fmt = 4 end
|
if string.sub(p.format or 's',1,1) == 's' then fmt = 3 else fmt = 4 end
|
||||||
local sent = socket.try(connection:send(string.format("%c%s %s\n", fmt, p.queue or "*", p.list or "")))
|
con.try(con.skt:send(string.format("%c%s %s\n", fmt, p.queue or "*",
|
||||||
local data = socket.try(connection:receive("*a"))
|
p.list or "")))
|
||||||
io.write(data)
|
local data = ltry(connection:receive("*a"))
|
||||||
connection:close()
|
con.skt:close()
|
||||||
return tostring(string.len(data))
|
return data
|
||||||
end)
|
end)
|
||||||
|
|
||||||
--for k,v in arg do print(k,v) end
|
|
||||||
local function usage()
|
|
||||||
print('\nUsage: lp filename [keyword=val...]\n')
|
|
||||||
print('Valid keywords are :')
|
|
||||||
print(
|
|
||||||
' host=remote host or IP address (default "localhost")\n' ..
|
|
||||||
' queue=remote queue or printer name (default "printer")\n' ..
|
|
||||||
' port=remote port number (default 515)\n' ..
|
|
||||||
' user=sending user name\n' ..
|
|
||||||
' format=["binary" | "text" | "ps" | "pr" | "fortran"] (default "binary")\n' ..
|
|
||||||
' banner=true|false\n' ..
|
|
||||||
' indent=number of columns to indent\n' ..
|
|
||||||
' mail=email of address to notify when print is complete\n' ..
|
|
||||||
' title=title to use for "pr" format\n' ..
|
|
||||||
' width=width for "text" or "pr" formats\n' ..
|
|
||||||
' class=\n' ..
|
|
||||||
' job=\n' ..
|
|
||||||
' name=\n' ..
|
|
||||||
' localbind=true|false\n'
|
|
||||||
)
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
|
|
||||||
if not arg or not arg[1] then
|
|
||||||
return usage()
|
|
||||||
end
|
|
||||||
|
|
||||||
do
|
|
||||||
local s="opt = {"
|
|
||||||
for i = 2 , table.getn(arg), 1 do
|
|
||||||
s = s .. string.gsub(arg[i],"[%s%c%p]*([%w]*)=([\"]?[%w%s_!@#$%%^&*()<>:;]+[\"]\?\.?)","%1%=\"%2\",\n")
|
|
||||||
end
|
|
||||||
s = s .. "};\n"
|
|
||||||
assert(loadstring(s))();
|
|
||||||
if not arg[2] then
|
|
||||||
return usage()
|
|
||||||
end
|
|
||||||
if arg[1] ~= "query" then
|
|
||||||
r,e=lp.send(arg[1],opt)
|
|
||||||
io.stderr:write(tostring(r or e),'\n')
|
|
||||||
else
|
|
||||||
r,e=lp.query(opt)
|
|
||||||
io.stderr:write(tostring(r or e),'\n')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- trivial tests
|
|
||||||
--lua lp.lua lp.lua queue=default host=localhost
|
|
||||||
--lua lp.lua lp.lua queue=default host=localhost format=binary localbind=1
|
|
||||||
--lua lp.lua query queue=default host=localhost
|
|
||||||
collectgarbage()
|
|
||||||
collectgarbage()
|
|
||||||
--print(socket.lp.query{host='localhost', queue="default"})
|
|
||||||
|
|
||||||
return nil
|
|
||||||
|
Loading…
Reference in New Issue
Block a user