mirror of
				https://github.com/lunarmodules/luasocket.git
				synced 2025-10-31 18:35:45 +01:00 
			
		
		
		
	Adjusted lp.lua.
This commit is contained in:
		
							
								
								
									
										281
									
								
								etc/lp.lua
									
									
									
									
									
								
							
							
						
						
									
										281
									
								
								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(con) | ||||||
|   send_ack(connection) |   recv_ack(con) | ||||||
|   recv_ack(connection) |   return size | ||||||
|   return size,nil |  | ||||||
| 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 |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user