aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDiego Nehab <diego@tecgraf.puc-rio.br>2004-07-01 03:39:56 +0000
committerDiego Nehab <diego@tecgraf.puc-rio.br>2004-07-01 03:39:56 +0000
commit1812d6ce150d9661bac858b82f81e133409b8409 (patch)
treeedf72005b6b8c83af686dbf155c9bc333a53cdef
parent7115c12fbc9aae1cd46fdf049697a27fb996181a (diff)
downloadluasocket-1812d6ce150d9661bac858b82f81e133409b8409.tar.gz
luasocket-1812d6ce150d9661bac858b82f81e133409b8409.tar.bz2
luasocket-1812d6ce150d9661bac858b82f81e133409b8409.zip
Adjusted lp.lua.
-rw-r--r--etc/lp.lua285
1 files changed, 96 insertions, 189 deletions
diff --git a/etc/lp.lua b/etc/lp.lua
index 80acf86..14ffc70 100644
--- a/etc/lp.lua
+++ b/etc/lp.lua
@@ -1,17 +1,40 @@
1
2--[[
3 if you have any questions RFC 1179
4]]
1-- make sure LuaSocket is loaded 5-- make sure LuaSocket is loaded
2local socket = require("socket") 6local socket = require("socket")
3local ltn12 = require("ltn12") 7local ltn12 = require("ltn12")
4local lp = {} 8local test = socket.try
5--socket.lp = lp
6-- make all module globals fall into lp namespace
7setmetatable(lp, { __index = _G })
8setfenv(1, lp)
9 9
10-- default port 10-- default port
11PORT = 515 11PORT = 515
12SERVER = os.getenv("SERVER_NAME") or os.getenv("COMPUTERNAME") or "localhost" 12SERVER = os.getenv("SERVER_NAME") or os.getenv("COMPUTERNAME") or "localhost"
13PRINTER = os.getenv("PRINTER") or "printer" 13PRINTER = os.getenv("PRINTER") or "printer"
14 14
15local function connect(localhost, option)
16 local host = option.host or SERVER
17 local port = option.port or PORT
18 local skt
19 local try = socket.newtry(function() if skt then skt:close() end end)
20 if option.localbind then
21 -- bind to a local port (if we can)
22 local localport = 721
23 repeat
24 skt = test(socket.tcp())
25 try(skt:settimeout(30))
26 local done, err = skt:bind(localhost, localport)
27 if not done then
28 localport = localport + 1
29 skt:close()
30 skt = nil
31 else break end
32 until localport > 731
33 test(skt, err)
34 else skt = test(socket.tcp()) end
35 try(skt:connect(host, port))
36 return { skt = skt, try = try }
37end
15 38
16--[[ 39--[[
17RFC 1179 40RFC 1179
@@ -50,23 +73,16 @@ RFC 1179
50 contain ASCII HT control characters. 73 contain ASCII HT control characters.
51]] 74]]
52 75
53
54-- gets server acknowledement 76-- gets server acknowledement
55local function recv_ack(connection) 77local function recv_ack(con)
56 local code, current, separator, _ 78 local ack = con.skt:receive(1)
57 local ack = socket.try(connection:receive(1)) 79 con.try(string.char(0) == ack, "failed to receive server acknowledement")
58 if string.char(0) ~= ack then
59 connection:close(); error"failed to receive server acknowledement"
60 end
61end 80end
62 81
63-- sends client acknowledement 82-- sends client acknowledement
64local function send_ack(connection) 83local function send_ack(con)
65 local sent = socket.try(connection:send(string.char(0))) 84 local sent = con.skt:send(string.char(0))
66 if not sent or sent ~= 1 then 85 con.try(sent == 1, "failed to send acknowledgement")
67 connection:close();
68 error"failed to send acknowledgement"
69 end
70end 86end
71 87
72-- sends queue request 88-- sends queue request
@@ -86,14 +102,12 @@ end
86-- octet from the daemon. A positive acknowledgement is an octet of 102-- octet from the daemon. A positive acknowledgement is an octet of
87-- zero bits. A negative acknowledgement is an octet of any other 103-- zero bits. A negative acknowledgement is an octet of any other
88-- pattern. 104-- pattern.
89local function send_queue(connection,queue) 105local function send_queue(con, queue)
90 if not queue then queue=PRINTER end 106 queue = queue or PRINTER
91 local str = string.format("\2%s\10",queue) 107 local str = string.format("\2%s\10", queue)
92 local sent = socket.try(connection:send(str)) 108 local sent = con.skt:send(str)
93 if not sent or sent ~= string.len(str) then 109 con.try(sent == string.len(str), "failed to send print request")
94 error "failed to send print request" 110 recv_ack(con)
95 end
96 recv_ack(connection)
97end 111end
98 112
99-- sends control file 113-- sends control file
@@ -145,48 +159,36 @@ end
145-- processing must occur at this point. 159-- processing must occur at this point.
146 160
147 161
148local function send_hdr(connection,control) 162local function send_hdr(con, control)
149 local sent = socket.try(connection:send(control)) 163 local sent = con.skt:send(control)
150 if not sent or sent < 1 then 164 con.try(sent and sent >= 1 , "failed to send header file")
151 error "failed to send file" 165 recv_ack(con)
152 end
153 recv_ack(connection)
154end 166end
155 167
156 168local function send_control(con, control)
157local function send_control(connection,control) 169 local sent = con:send(control)
158 local sent = socket.try(connection:send(control)) 170 con.try(sent and sent >= 1, "failed to send control file")
159 if not sent or sent < 1 then 171 send_ack(con)
160 error "failed to send file"
161 end
162 send_ack(connection)
163end 172end
164 173
165local function send_data(connection,fh,size) 174local function send_data(con,fh,size)
166-- local sink = socket.sink("keep-open", connection) 175 local buf
167-- ltn12.pump.all(source, sink)
168 local buf, st, message
169 st = true
170 while size > 0 do 176 while size > 0 do
171 buf,message = fh:read(8192) 177 buf,message = fh:read(8192)
172 if buf then 178 if buf then
173 st = socket.try(connection:send(buf)) 179 st = con.try(con:send(buf))
174 size = size - st 180 size = size - st
175 else 181 else
176 if size ~= 0 then 182 con.try(size == 0, "file size mismatch")
177 connection:close()
178 return nil, "file size mismatch"
179 end
180 end 183 end
181 end 184 end
182 send_ack(connection) 185 send_ack(con)
183 recv_ack(connection) 186 recv_ack(con)
184 return size,nil 187 return size
185end 188end
186 189
187 190
188--[[ 191--[[
189
190local control_dflt = { 192local control_dflt = {
191 "H"..string.sub(socket.hostname,1,31).."\10", -- host 193 "H"..string.sub(socket.hostname,1,31).."\10", -- host
192 "C"..string.sub(socket.hostname,1,31).."\10", -- class 194 "C"..string.sub(socket.hostname,1,31).."\10", -- class
@@ -206,44 +208,15 @@ local control_dflt = {
206 "r"..file.."\10", -- fortran format 208 "r"..file.."\10", -- fortran format
207 "U"..file.."\10", -- Unlink (data file only) 209 "U"..file.."\10", -- Unlink (data file only)
208} 210}
209
210]] 211]]
211 212
212-- generate a varying job number 213-- generate a varying job number
213local function getjobno(connection) 214local seq = 0
214-- print(math.mod(socket.time() * 1000, port)) -- ok for windows 215local function newjob(connection)
215-- print(os.time() / port,math.random(0,999)) 216 seq = seq + 1
216 return math.random(0,999) 217 return math.floor(socket.gettime() * 1000 + seq)
217end 218end
218 219
219local function getcon(localhost,option)
220 local skt, st, message
221 local localport = 721
222 if not option then
223 error('no options',0)
224 end
225 if option.localbind then
226 repeat
227 -- bind to a local port (if we can)
228 skt = socket.try(socket.tcp())
229 skt:settimeout(30)
230
231 st, message = skt:bind(localhost,localport,-1);
232 -- print("bind",st,message)
233 if st then
234 st,message = skt:connect(option.host or SERVER, option.port or PORT)
235 -- print("connect",st,message)
236 end
237 -- print(st,localport,message)
238 if not st then
239 localport = localport + 1
240 skt:close()
241 end
242 until st or localport > 731 or (not st and message ~= "local address already in use")
243 if st then return skt end
244 end
245 return socket.try(socket.connect(option.host or SERVER, option.port or PORT))
246end
247 220
248local format_codes = { 221local format_codes = {
249 binary = 'l', 222 binary = 'l',
@@ -258,43 +231,33 @@ local format_codes = {
258 f = 'f' 231 f = 'f'
259} 232}
260 233
261lp.send = socket.protect(function(file, option) 234-- lp.send
262 if not file then error "invalid file name" end 235
263 if not option or type(option) ~= "table" then error "invalid options" end 236send = socket.protect(function(file, option)
264 local fh = socket.try(io.open(file,"rb")) 237 test(file, "invalid file name")
265 -- get total size 238 test(option and type(option) == "table", "invalid options")
266 local datafile_size = fh:seek("end") 239 local fh = test(io.open(file,"rb"))
267 -- go back to start of file 240 local datafile_size = fh:seek("end") -- get total size
268 fh:seek("set") 241 fh:seek("set") -- go back to start of file
269 math.randomseed(socket.time() * 1000) 242 local localhost = socket.dns.gethostname() or os.getenv("COMPUTERNAME")
270 local localhost = socket.dns.gethostname() or os.getenv("COMPUTERNAME") or "localhost" 243 or "localhost"
271 244 local con = connect(localhost, option)
272-- local connection, message = skt:connect(option.host or SERVER, option.port or PORT)
273
274 local connection = getcon(localhost,option)
275
276-- format the control file 245-- format the control file
277 local jobno = getjobno(connection) 246 local jobno = newjob()
278 local localip = socket.dns.toip(localhost) 247 local localip = socket.dns.toip(localhost)
279 localhost = string.sub(localhost,1,31) 248 localhost = string.sub(localhost,1,31)
280 249 local user = string.sub(option.user or os.getenv("LPRUSER") or
281 local user = string.sub(option.user or os.getenv("LPRUSER") or os.getenv("USERNAME") 250 os.getenv("USERNAME") or os.getenv("USER") or "anonymous", 1,31)
282 or os.getenv("USER") or "anonymous",1,31)
283
284 local lpfile = string.format("dfA%3.3d%-s", jobno, localhost); 251 local lpfile = string.format("dfA%3.3d%-s", jobno, localhost);
285
286 local fmt = format_codes[option.format] or 'l' 252 local fmt = format_codes[option.format] or 'l'
287
288 local class = string.sub(option.class or localip or localhost,1,31) 253 local class = string.sub(option.class or localip or localhost,1,31)
289
290 local _,_,ctlfn = string.find(file,".*[%/%\\](.*)") 254 local _,_,ctlfn = string.find(file,".*[%/%\\](.*)")
291 ctlfn = string.sub(ctlfn or file,1,131) 255 ctlfn = string.sub(ctlfn or file,1,131)
292
293 local cfile = 256 local cfile =
294 string.format("H%-s\nC%-s\nJ%-s\nP%-s\n%.1s%-s\nU%-s\nN%-s\n", 257 string.format("H%-s\nC%-s\nJ%-s\nP%-s\n%.1s%-s\nU%-s\nN%-s\n",
295 localhost, 258 localhost,
296 class, 259 class,
297 option.job or ctlfn, 260 option.job or "LuaSocket",
298 user, 261 user,
299 fmt, lpfile, 262 fmt, lpfile,
300 lpfile, 263 lpfile,
@@ -307,96 +270,40 @@ lp.send = socket.protect(function(file, option)
307 cfile = cfile .. 'W'..tonumber(option,width)..'\10' 270 cfile = cfile .. 'W'..tonumber(option,width)..'\10'
308 end 271 end
309 272
310 connection:settimeout(option.timeout or 65) 273 con.skt:settimeout(option.timeout or 65)
311
312-- send the queue header 274-- send the queue header
313 send_queue(connection,option.queue) 275 send_queue(con, option.queue)
314
315-- send the control file header 276-- send the control file header
316 local cfilecmd = string.format("\2%d cfA%3.3d%-s\n",string.len(cfile), jobno, localhost); 277 local cfilecmd = string.format("\2%d cfA%3.3d%-s\n",string.len(cfile), jobno, localhost);
317 send_hdr(connection,cfilecmd) 278 send_hdr(con,cfilecmd)
318 279
319-- send the control file 280-- send the control file
320 send_control(connection,cfile) 281 send_control(con,cfile)
321 282
322-- send the data file header 283-- send the data file header
323 local dfilecmd = string.format("\3%d dfA%3.3d%-s\n",datafile_size, jobno, localhost); 284 local dfilecmd = string.format("\3%d dfA%3.3d%-s\n",datafile_size, jobno, localhost);
324 send_hdr(connection,dfilecmd) 285 send_hdr(con,dfilecmd)
325 286
326-- send the data file 287-- send the data file
327 send_data(connection,fh,datafile_size) 288 send_data(con,fh,datafile_size)
328 fh:close() 289 fh:close()
329 connection:close(); 290 con.skt:close();
330 return datafile_size 291 return jobno, datafile_size
331end) 292end)
332 293
333 294--
334--socket.lpq({host=,queue=printer|'*', format='l'|'s', list=}) 295-- lp.query({host=,queue=printer|'*', format='l'|'s', list=})
335lp.query = socket.protect(function(p) 296--
336 if not p then p={} end 297query = socket.protect(function(p)
337 local localhost = socket.dns.gethostname() or os.getenv("COMPUTERNAME") or "localhost" 298 p = p or {}
338 local connection = getcon(localhost,p) 299 local localhost = socket.dns.gethostname() or os.getenv("COMPUTERNAME")
339 local fmt,data 300 or "localhost"
301 local con = connect(localhost,p)
302 local fmt
340 if string.sub(p.format or 's',1,1) == 's' then fmt = 3 else fmt = 4 end 303 if string.sub(p.format or 's',1,1) == 's' then fmt = 3 else fmt = 4 end
341 local sent = socket.try(connection:send(string.format("%c%s %s\n", fmt, p.queue or "*", p.list or ""))) 304 con.try(con.skt:send(string.format("%c%s %s\n", fmt, p.queue or "*",
342 local data = socket.try(connection:receive("*a")) 305 p.list or "")))
343 io.write(data) 306 local data = ltry(connection:receive("*a"))
344 connection:close() 307 con.skt:close()
345 return tostring(string.len(data)) 308 return data
346end) 309end)
347
348--for k,v in arg do print(k,v) end
349local function usage()
350 print('\nUsage: lp filename [keyword=val...]\n')
351 print('Valid keywords are :')
352 print(
353 ' host=remote host or IP address (default "localhost")\n' ..
354 ' queue=remote queue or printer name (default "printer")\n' ..
355 ' port=remote port number (default 515)\n' ..
356 ' user=sending user name\n' ..
357 ' format=["binary" | "text" | "ps" | "pr" | "fortran"] (default "binary")\n' ..
358 ' banner=true|false\n' ..
359 ' indent=number of columns to indent\n' ..
360 ' mail=email of address to notify when print is complete\n' ..
361 ' title=title to use for "pr" format\n' ..
362 ' width=width for "text" or "pr" formats\n' ..
363 ' class=\n' ..
364 ' job=\n' ..
365 ' name=\n' ..
366 ' localbind=true|false\n'
367 )
368 return nil
369end
370
371if not arg or not arg[1] then
372 return usage()
373end
374
375do
376 local s="opt = {"
377 for i = 2 , table.getn(arg), 1 do
378 s = s .. string.gsub(arg[i],"[%s%c%p]*([%w]*)=([\"]?[%w%s_!@#$%%^&*()<>:;]+[\"]\?\.?)","%1%=\"%2\",\n")
379 end
380 s = s .. "};\n"
381 assert(loadstring(s))();
382 if not arg[2] then
383 return usage()
384 end
385 if arg[1] ~= "query" then
386 r,e=lp.send(arg[1],opt)
387 io.stderr:write(tostring(r or e),'\n')
388 else
389 r,e=lp.query(opt)
390 io.stderr:write(tostring(r or e),'\n')
391 end
392end
393
394-- trivial tests
395--lua lp.lua lp.lua queue=default host=localhost
396--lua lp.lua lp.lua queue=default host=localhost format=binary localbind=1
397--lua lp.lua query queue=default host=localhost
398collectgarbage()
399collectgarbage()
400--print(socket.lp.query{host='localhost', queue="default"})
401
402return nil