5adf93e8a4
It was writing an extra newline character after the URI, which caused the gutenprint.5.2 multicat process to exit. This prevented some PPDs from being updated.
1059 lines
34 KiB
Python
Executable File
1059 lines
34 KiB
Python
Executable File
#!/usr/bin/python
|
|
# $Id$
|
|
# Update CUPS PPDs for Gutenprint queues.
|
|
# Copyright (C) 2002-2003 Roger Leigh (rleigh@debian.org)
|
|
# Copyright (C) 2009, 2011 Red Hat, Inc.
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation; either version 2, or (at your option)
|
|
# any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program; if not, write to the Free Software
|
|
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
import getopt
|
|
import glob
|
|
import os
|
|
import re
|
|
import stat
|
|
import subprocess
|
|
import sys
|
|
|
|
global optargs
|
|
global debug
|
|
global verbose
|
|
global interactive
|
|
global quiet
|
|
global no_action
|
|
global reset_defaults
|
|
global version
|
|
global micro_version
|
|
global use_static_ppd
|
|
global file_version
|
|
|
|
global ppd_dir
|
|
global ppd_root_dir
|
|
global ppd_base_dir
|
|
global ppd_out_dir
|
|
global gzext
|
|
global updated_ppd_count
|
|
global skipped_ppd_count
|
|
global failed_ppd_count
|
|
global exit_after_parse_args
|
|
global languages
|
|
|
|
global serverdir
|
|
global driver_bin
|
|
global driver_version
|
|
global server_multicat
|
|
global server_multicat_initialized
|
|
|
|
global ppd_files
|
|
global languagemappings
|
|
|
|
def help():
|
|
print """
|
|
Usage: %s [OPTION]... [PPD_FILE]...
|
|
Update CUPS+Gutenprint PPD files.
|
|
|
|
-d flags Enable debugging
|
|
-h Display this help text
|
|
-n No-action. Don't overwrite any PPD files.
|
|
-q Quiet mode. No messages except errors.
|
|
-s ppd_dir Use ppd_dir as the source PPD directory.
|
|
-p ppd_dir Update PPD files in ppd_dir.
|
|
-P driver Use the specified driver binary to generate PPD files.
|
|
-v Verbose messages.
|
|
-N Reset options to defaults.
|
|
-o out_dir Output PPD files to out_dir.
|
|
-r version Use PPD files for Gutenprint major.minor version.
|
|
-f Ignore new PPD file safety checks.
|
|
-i Prompt (interactively) for each PPD file.
|
|
-l language Language choice (Gutenprint 5.1 or below).
|
|
Choices: %s
|
|
Or -loriginal to preserve original language
|
|
with Gutenprint 5.2 or above
|
|
""" % (sys.argv[0],
|
|
reduce (lambda x,y: "%s %s" % (x,y), languages))
|
|
sys.exit (0)
|
|
|
|
def die_if_not_directory (dir):
|
|
try:
|
|
st = os.stat (dir)
|
|
if not st.S_ISDIR (st.st_mode):
|
|
os.chdir (dir)
|
|
except OSError, (e, s):
|
|
print "%s: invalid directory: %s" % (dir, s)
|
|
sys.exit (1)
|
|
|
|
def get_driver_version():
|
|
global server_multicat
|
|
global driver_version
|
|
|
|
def run_with_arg (arg):
|
|
try:
|
|
p = subprocess.Popen ([driver_bin, arg],
|
|
stdin=file("/dev/null"),
|
|
stdout=subprocess.PIPE,
|
|
stderr=file("/dev/null", "w"),
|
|
shell=False)
|
|
(stdout, stderr) = p.communicate ()
|
|
except OSError:
|
|
return None
|
|
|
|
return stdout
|
|
|
|
stdout = run_with_arg ("org.gutenprint.extensions")
|
|
if stdout == None:
|
|
return
|
|
for line in stdout.split ("\n"):
|
|
if line == "org.gutenprint.multicat":
|
|
server_multicat = 1
|
|
break
|
|
|
|
stdout = run_with_arg ("VERSION")
|
|
if stdout == None:
|
|
return
|
|
|
|
driver_version = stdout.strip ()
|
|
|
|
def parse_options():
|
|
try:
|
|
opts, args = getopt.getopt (sys.argv[1:], "d:hnqs:vNo:p:P:r:ifl:")
|
|
except getopt.GetoptError:
|
|
help ()
|
|
|
|
global optargs
|
|
global debug
|
|
global verbose
|
|
global interactive
|
|
global quiet
|
|
global no_action
|
|
global reset_defaults
|
|
global version
|
|
global micro_version
|
|
global use_static_ppd
|
|
global file_version
|
|
global ppd_dir
|
|
global ppd_out_dir
|
|
global ppd_base_dir
|
|
global ppd_root_dir
|
|
global serverdir
|
|
global driver_bin
|
|
global driver_version
|
|
global server_multicat
|
|
global languages
|
|
optargs = dict()
|
|
for opt, optarg in opts:
|
|
optargs[opt[1]] = optarg
|
|
|
|
if optargs.has_key ('n'):
|
|
no_action = 1
|
|
|
|
if optargs.has_key ('d'):
|
|
try:
|
|
debug = int (optargs['d'])
|
|
except ValueError:
|
|
d = 0
|
|
|
|
if optargs.has_key ('v'):
|
|
verbose = 1
|
|
quiet = 0
|
|
|
|
if optargs.has_key ('q'):
|
|
verbose = 0
|
|
quiet = 1
|
|
|
|
if optargs.has_key ('N'):
|
|
reset_defaults = 1
|
|
|
|
if optargs.has_key ('o'):
|
|
opt_o = optargs['o']
|
|
die_if_not_directory (opt_o)
|
|
ppd_out_dir = opt_o
|
|
|
|
if optargs.has_key ('r'):
|
|
opt_r = optargs['r']
|
|
if version != opt_r:
|
|
version = opt_r
|
|
if optargs.has_key ('s'):
|
|
opt_s = optargs['s']
|
|
die_if_not_directory (opt_s)
|
|
ppd_base_dir = opt_s
|
|
driver_bin = ""
|
|
server_multicat = 0
|
|
use_static_ppd = "yes"
|
|
else:
|
|
ppd_base_dir = ppd_root_dir + "/gutenprint/" + version
|
|
driver_bin = serverdir + "/driver/gutenprint." + version
|
|
|
|
driver_version = ""
|
|
# If user specifies version, we're not going to be able to check
|
|
# for an exact match.
|
|
file_version = '"' + version
|
|
if os.access (driver_bin, os.X_OK):
|
|
get_driver_version ()
|
|
use_static_ppd = "no"
|
|
file_version = "\"%s\"$" % driver_version
|
|
else:
|
|
print "Gutenprint %s does not appear to be installed!" % version
|
|
sys.exit (1)
|
|
|
|
if optargs.has_key ('s'):
|
|
opt_s = optargs['s']
|
|
die_if_not_directory (opt_s)
|
|
ppd_base_dir = opt_s
|
|
driver_bin = ""
|
|
server_multicat = 0
|
|
driver_version = ""
|
|
use_static_ppd = "yes"
|
|
|
|
if optargs.has_key ('p'):
|
|
opt_p = optargs['p']
|
|
die_if_not_directory (opt_p)
|
|
ppd_dir = opt_p
|
|
|
|
if optargs.has_key ('P'):
|
|
opt_P = optargs['P']
|
|
if os.access (opt_P, os.X_OK):
|
|
driver_bin = opt_P
|
|
get_driver_version ()
|
|
use_static_ppd = "no"
|
|
else:
|
|
print "%s: invalid executable" % opt_P
|
|
|
|
if optargs.has_key ('h'):
|
|
help ()
|
|
|
|
if (optargs.has_key ('l') and
|
|
optargs['l'].lower () != "original" and
|
|
optargs['l'].lower () not in languages):
|
|
print >>sys.stderr, "Unknown language '%s'" % optargs['l']
|
|
|
|
if optargs.has_key ('i'):
|
|
interactive = 1
|
|
|
|
if exit_after_parse_args:
|
|
sys.exit (0)
|
|
|
|
if verbose and driver_version != "":
|
|
print "Updating PPD files from Gutenprint %s" % driver_version
|
|
|
|
return args
|
|
|
|
def update_ppd (ppd_source_filename):
|
|
global ppd_dest_filename
|
|
global ppd_out_dir
|
|
global optargs
|
|
global languagemappings
|
|
global interactive
|
|
global server_multicat
|
|
global no_action
|
|
global quiet, verbose
|
|
global reset_defaults
|
|
|
|
ppd_dest_filename = ppd_source_filename
|
|
if ppd_out_dir:
|
|
ppd_dest_filename = "%s/%s" % (ppd_out_dir,
|
|
os.path.basename (ppd_dest_filename))
|
|
|
|
orig = file (ppd_source_filename)
|
|
orig_metadata = os.fstat (orig.fileno ())
|
|
if debug & 1:
|
|
print "Source Filename: %s" % ppd_source_filename
|
|
|
|
filename = ""
|
|
driver = ""
|
|
gutenprintdriver = ""
|
|
locale = ""
|
|
lingo = ""
|
|
region = ""
|
|
valid = 0
|
|
orig_locale = ""
|
|
for line in orig.readlines ():
|
|
line.rstrip ()
|
|
if line.find ("*StpLocale:") != -1:
|
|
match = re.search ("\*StpLocale:\s*\"(.*)\"$", line)
|
|
if match:
|
|
groups = match.groups ()
|
|
if len (groups) >= 1:
|
|
locale = groups[0]
|
|
orig_locale = locale
|
|
valid = 1
|
|
elif line.startswith ("*LanguageVersion"):
|
|
match = re.search ("^\*LanguageVersion:\s*(.*)$", line)
|
|
if match:
|
|
groups = match.groups ()
|
|
if len (groups) >= 1:
|
|
lingo = groups[0]
|
|
elif line.startswith ("*StpDriverName:"):
|
|
match = re.search ("^\*StpDriverName:\s*\"(.*)\"$", line)
|
|
if match:
|
|
groups = match.groups ()
|
|
if len (groups) >= 1:
|
|
driver = groups[0]
|
|
valid = 1
|
|
elif line.find ("*%End of ") != -1 and driver == "":
|
|
match = re.search ("^\*%End of\s*(.*).ppd$", line)
|
|
if match:
|
|
groups = match.groups ()
|
|
if len (groups) >= 1:
|
|
driver = groups[0]
|
|
elif line.startswith ("*StpPPDLocation:"):
|
|
match = re.search ("^\*StpPPDLocation:\s*\"(.*)\"$", line)
|
|
if match:
|
|
groups = match.groups ()
|
|
if len (groups) >= 1:
|
|
filename = groups[0]
|
|
valid = 1
|
|
elif line.startswith ("*%Gutenprint Filename:"):
|
|
valid = 1
|
|
|
|
if filename and driver and lingo and locale:
|
|
break
|
|
|
|
if not valid and line.startswith ("*OpenUI"):
|
|
break
|
|
|
|
if not valid:
|
|
#print >>sys.stderr, ("Skipping %s: not a Gutenprint PPD file" %
|
|
# ppd_source_filename)
|
|
return -1
|
|
|
|
if (optargs.has_key ('l') and
|
|
optargs['l'] != "" and
|
|
optargs['l'].lower () != "original"):
|
|
locale = optargs['l']
|
|
orig_locale = locale
|
|
|
|
if debug & 2:
|
|
print "Gutenprint Filename: %s" % filename
|
|
if optargs.has_key ('l'):
|
|
print "Locale: %s (from -l)" % locale
|
|
else:
|
|
print "Locale: %s" % locale
|
|
|
|
print "Language: %s" % lingo
|
|
print "Driver: %s" % driver
|
|
|
|
if locale:
|
|
# Split into the language and territory.
|
|
s = locale.split ("_", 1)
|
|
locale = s[0]
|
|
try:
|
|
region = s[1]
|
|
except IndexError:
|
|
region = ""
|
|
else:
|
|
# Split into the language and territory.
|
|
s = lingo.split ("_", 1)
|
|
locale = s[0]
|
|
try:
|
|
region = s[1]
|
|
except IndexError:
|
|
region = ""
|
|
|
|
# Convert language into language code.
|
|
locale = languagemappings.get (lingo.lower (), "C")
|
|
|
|
if debug & 2:
|
|
print "Base Locale: %s" % locale
|
|
print "Region: %s" % region
|
|
|
|
# Read in the new PPD, decompressing it if needed...
|
|
(new_ppd_filename, source_fd) = get_ppd_fh (ppd_source_filename,
|
|
filename,
|
|
driver,
|
|
locale,
|
|
region)
|
|
if source_fd == None:
|
|
print "Unable to retrieve PPD file!"
|
|
return 0
|
|
|
|
if interactive:
|
|
inp = raw_input ("Update PPD %s from %s [nyq]? " % ppd_source_filename)
|
|
inp = inp.lower ()
|
|
if inp.startswith ("q"):
|
|
if not server_multicat:
|
|
source_fd.close ()
|
|
|
|
print "Skipping all..."
|
|
return -2
|
|
elif not inp.startswith ("y"):
|
|
if not server_multicat:
|
|
source_fd.close ()
|
|
|
|
print "Skipping..."
|
|
return -1
|
|
|
|
# Extract the default values from the original PPD...
|
|
|
|
orig.seek (0)
|
|
(odt, oopt, ores, odef, unused) = get_ppd_data (orig, 1, 0, 1, 1, 0)
|
|
(ndt, nopt, nres, ndef, source_data) = get_ppd_data (source_fd,
|
|
1, 1, 1, 1, 1)
|
|
|
|
# Close original and temporary files...
|
|
|
|
orig.close ()
|
|
if not server_multicat:
|
|
source_fd.close ()
|
|
|
|
orig_default_types = odt
|
|
new_default_types = ndt
|
|
defaults = odef
|
|
new_defaults = ndef
|
|
options = nopt
|
|
resolution_map = nres
|
|
old_resolution_map = dict()
|
|
for key, value in resolution_map.iteritems ():
|
|
old_resolution_map[value] = key
|
|
|
|
# Store previous language in the PPD file so that -l original works
|
|
# correctly.
|
|
|
|
if orig_locale != "":
|
|
lines = source_data.rstrip ().split ("\n")
|
|
source_data = ""
|
|
for line in lines:
|
|
m = re.search ("(\*StpLocale:\s*\")(.*)(\")", line)
|
|
if m:
|
|
groups = m.groups ()
|
|
line = groups[0] + orig_locale + groups[2]
|
|
|
|
source_data += line + "\n"
|
|
|
|
if debug & 4:
|
|
print "Options (Old->New Default Type):"
|
|
keys = options.keys ()
|
|
keys.sort ()
|
|
for t in keys:
|
|
old_type = orig_default_types.get (t, "(New)")
|
|
new_type = new_default_types.get (t)
|
|
if old_type != new_type:
|
|
out = " %s (%s -> %s) : " % (t, old_type, new_type)
|
|
else:
|
|
out = " %s (%s) : " % (t, new_type)
|
|
|
|
dft = defaults.get ("Default%s" % t)
|
|
for opt in options.get (t, []):
|
|
if dft != None and dft == opt:
|
|
out += "*"
|
|
|
|
out += "%s " % opt
|
|
|
|
print out
|
|
|
|
if len (resolution_map.keys ()) > 0:
|
|
print "Resolution Map:"
|
|
keys = resolution_map.keys ()
|
|
keys.sort ()
|
|
for key in keys:
|
|
print " %s: %s" % (key, resolution_map[key])
|
|
|
|
if len (old_resolution_map.keys ()) > 0:
|
|
print "Old Resolution Map:"
|
|
keys = old_resolution_map.keys ()
|
|
keys.sort ()
|
|
for key in keys:
|
|
print " %s: %s" % (key, old_resolution_map[key])
|
|
|
|
print "Non-UI Defaults:"
|
|
keys = defaults.keys ()
|
|
keys.sort ()
|
|
for key in keys:
|
|
xkey = key
|
|
if xkey.startswith ("Default"):
|
|
xkey = xkey[7:]
|
|
if not options.has_key (xkey):
|
|
print " %s: %s" % (key, defaults[key])
|
|
|
|
print "Default Types of dropped options:"
|
|
keys = orig_default_types.keys ()
|
|
keys.sort ()
|
|
for t in keys:
|
|
if not options.has_key (t):
|
|
print " %s: %s" % (t, orig_default_types[t])
|
|
|
|
if no_action:
|
|
if not quiet or verbose:
|
|
if ppd_dest_filename == ppd_source_filename:
|
|
print "Would update %s using %s" % (ppd_source_filename,
|
|
new_ppd_filename)
|
|
else:
|
|
print "Would update %s to %s using %s" % (ppd_source_filename,
|
|
ppd_dest_filename,
|
|
new_ppd_filename)
|
|
|
|
return 0
|
|
|
|
if not reset_defaults:
|
|
# Update source buffer with old defaults...
|
|
|
|
# Loop through each default in turn.
|
|
keys = defaults.keys ()
|
|
keys.sort ()
|
|
for default_option in keys:
|
|
default_option_value = defaults[default_option]
|
|
option = default_option
|
|
if option.startswith ("Default"):
|
|
# Strip off `Default'
|
|
option = option[7:]
|
|
|
|
# Check method is valid
|
|
orig_method = orig_default_types.get (option)
|
|
new_method = new_default_types.get (option)
|
|
new_default = new_defaults.get (default_option)
|
|
if (orig_method == None or new_method == None or
|
|
orig_method != new_method):
|
|
continue
|
|
|
|
if (new_default != None and
|
|
default_option_value == new_default):
|
|
if verbose:
|
|
print "%s: Preserve *%s (%s)" % (ppd_source_filename,
|
|
default_option,
|
|
default_option_value)
|
|
|
|
continue
|
|
|
|
if new_method == "PickOne":
|
|
next_default = False
|
|
|
|
# Check the old setting is valid
|
|
for opt in options.get (option, []):
|
|
def_option = default_option_value
|
|
odef_option = def_option
|
|
if (option == "Resolution" and
|
|
old_resolution_map.has_key (def_option)):
|
|
if debug & 4:
|
|
print ("Intermapping old resolution %s to %s" %
|
|
def_option, old_resolution_map[def_option])
|
|
|
|
def_option = old_resolution_map[def_option]
|
|
|
|
dopts = [def_option]
|
|
if def_option != odef_option:
|
|
dopts.append (odef_option)
|
|
|
|
for dopt in dopts:
|
|
valid = False
|
|
if dopt == opt:
|
|
valid = True
|
|
elif (option == "Resolution" and
|
|
resolution_map.has_key (dopt)):
|
|
dopt = resolution_map[dopt]
|
|
if dopt == opt:
|
|
valid = True
|
|
|
|
if valid:
|
|
# Valid option
|
|
|
|
# Set the option in the new PPD
|
|
lines = source_data.rstrip ().split ("\n")
|
|
source_data = ""
|
|
attr = "*%s" % default_option
|
|
for line in lines:
|
|
if line.startswith (attr):
|
|
line = "%s:%s" % (attr, dopt)
|
|
|
|
source_data += line + "\n"
|
|
|
|
if verbose:
|
|
print "%s: Set *%s to %s" % (ppd_source_filename,
|
|
default_option,
|
|
dopt)
|
|
|
|
next_default = True
|
|
break
|
|
if next_default:
|
|
break
|
|
|
|
if next_default:
|
|
continue
|
|
|
|
print ("Warning: %s: Invalid option: *%s: %s. Using default "
|
|
"setting %s." % (ppd_source_filename, default_option,
|
|
defaults[default_option],
|
|
new_defaults[default_option]))
|
|
continue
|
|
|
|
print ("Warning: %s: PPD OpenUI method %s not understood." %
|
|
(ppd_source_filename, new_default_types[default_option]))
|
|
|
|
# Write new PPD...
|
|
tmpnew = "%s.new" % ppd_dest_filename
|
|
try:
|
|
newppd = file (tmpnew, "w")
|
|
except IOError, (e, s):
|
|
print "Can't create %s: %s" % (tmpnew, s)
|
|
return 0
|
|
|
|
newppd.writelines (source_data)
|
|
try:
|
|
newppd.close ()
|
|
except IOError, (e, s):
|
|
print "Can't write to %s: %s" % (tmpnew, s)
|
|
return 0
|
|
|
|
chcon = subprocess.Popen (["chcon", "--reference=%s" % ppd_dest_filename,
|
|
tmpnew], shell=False,
|
|
stdin=file("/dev/null"),
|
|
stdout=file("/dev/null", "w"),
|
|
stderr=subprocess.STDOUT)
|
|
chcon.communicate ()
|
|
|
|
try:
|
|
os.rename (tmpnew, ppd_dest_filename)
|
|
except OSError, (e, s):
|
|
print "Can't rename %s to %s: %s" % (tmpnew, ppd_dest_filename, s)
|
|
try:
|
|
os.unlink (tmpnew)
|
|
except OSError:
|
|
pass
|
|
|
|
return 0
|
|
|
|
try:
|
|
os.chown (ppd_dest_filename,
|
|
orig_metadata.st_uid,
|
|
orig_metadata.st_gid)
|
|
except OSError:
|
|
pass
|
|
|
|
try:
|
|
os.chmod (ppd_dest_filename,
|
|
orig_metadata.st_mode & 0777)
|
|
except OSError:
|
|
pass
|
|
|
|
if not quiet or verbose:
|
|
if ppd_dest_filename == ppd_source_filename:
|
|
print "Updated %s using %s" % (ppd_source_filename,
|
|
new_ppd_filename)
|
|
else:
|
|
print "Updated %s to %s using %s" % (ppd_source_filename,
|
|
ppd_dest_filename,
|
|
new_ppd_filename)
|
|
|
|
# All done!
|
|
return 1
|
|
|
|
def get_ppd_data (fh, types, opts, resolutions, defaults, data):
|
|
options_map = dict()
|
|
defaults_map = dict()
|
|
resolution_map = dict()
|
|
default_types = dict()
|
|
cur_opt = ""
|
|
optionlist = []
|
|
source_data = ""
|
|
|
|
if reset_defaults:
|
|
types = 0
|
|
opts = 0
|
|
resolutions = 0
|
|
defaults = 0
|
|
|
|
if resolutions or types or opts or defaults or data:
|
|
while True:
|
|
line = fh.readline ()
|
|
if line == '':
|
|
break
|
|
if line == "*%*%EOFEOF\n":
|
|
break
|
|
source_data += line
|
|
line = line.strip ()
|
|
|
|
if (types or opts) and line.startswith ("*OpenUI"):
|
|
m = re.search ("^\*OpenUI\s\*(\w+).*:\s(\w+)",
|
|
line)
|
|
if m:
|
|
groups = m.groups ()
|
|
key = groups[0]
|
|
value = groups[1]
|
|
default_types[key] = value
|
|
cur_opt = key
|
|
elif opts and line.startswith ("*CloseUI"):
|
|
if cur_opt != "":
|
|
options_map[cur_opt] = optionlist
|
|
cur_opt = ""
|
|
|
|
optionlist = []
|
|
elif opts and line.startswith ("*%s" % cur_opt):
|
|
m = re.search ("^\*%s\s*(\w+)[\/:]" % cur_opt, line)
|
|
if m:
|
|
groups = m.groups()
|
|
if len (groups) >= 1:
|
|
value = m.groups ()[0]
|
|
optionlist.append (value)
|
|
elif resolutions and line.startswith ("*StpResolutionMap:"):
|
|
s = line.split (None, 3)
|
|
if len (s) == 3:
|
|
new = s[1]
|
|
old = s[2]
|
|
resolution_map[old] = new
|
|
elif defaults and line.startswith ("*Default"):
|
|
m = re.search ("^\*(\w+):\s*(\w+)", line)
|
|
if m:
|
|
groups = m.groups ()
|
|
key = groups[0]
|
|
value = groups[1]
|
|
defaults_map[key] = value
|
|
|
|
return (default_types, options_map, resolution_map,
|
|
defaults_map, source_data)
|
|
|
|
def get_ppd_fh (ppd_source_filename, filename, driver, locale, region):
|
|
global use_static_ppd
|
|
global driver_version
|
|
global optargs
|
|
global driver_bin
|
|
global debug
|
|
global server_multicat, server_multicat_initialized
|
|
global gzext
|
|
|
|
if use_static_ppd == "no" and driver_version != "":
|
|
if re.search (".*/([^/]*)(.sim)(.ppd)?(.gz)?$", filename):
|
|
simplified = "simple"
|
|
else:
|
|
simplified = "expert"
|
|
|
|
opt_r = optargs.get ('r')
|
|
if opt_r:
|
|
try:
|
|
opt_r = float (opt_r)
|
|
except ValueError:
|
|
opt_r = None
|
|
|
|
url_list = []
|
|
if (((opt_r != None and opt_r < 5.2) or
|
|
(optargs.has_key ('l') and optargs['l'] != "")) and
|
|
locale != ""):
|
|
if region:
|
|
url_list.append ("gutenprint.%s://%s/%s/%s_%s" %
|
|
version, driver, simplified, locale, region)
|
|
url_list.append ("gutenprint.%s://%s/%s/%s" %
|
|
version, driver, simplified, locale)
|
|
|
|
url_list.append ("gutenprint.%s://%s/%s" % (version, driver,
|
|
simplified))
|
|
for url in url_list:
|
|
new_ppd_filename = url
|
|
if debug & 8:
|
|
if server_multicat:
|
|
cat = ""
|
|
else:
|
|
cat = "%s cat " % driver_bin
|
|
|
|
print ("Trying %s%s for %s, %s, %s, %s" %
|
|
(cat, url, driver, simplified, locale, region))
|
|
|
|
if server_multicat:
|
|
try:
|
|
if not server_multicat_initialized:
|
|
mc_proc = subprocess.Popen ([driver_bin,
|
|
"org.gutenprint.multicat"],
|
|
shell=False,
|
|
stdin=subprocess.PIPE,
|
|
stdout=subprocess.PIPE,
|
|
stderr=file("/dev/null",
|
|
"w"))
|
|
server_multicat_initialized = mc_proc
|
|
|
|
print >>server_multicat_initialized.stdin, "%s" % url
|
|
server_multicat_initialized.stdin.flush ()
|
|
return (new_ppd_filename,
|
|
server_multicat_initialized.stdout)
|
|
except OSError:
|
|
pass
|
|
|
|
try:
|
|
proc = subprocess.Popen ([driver_bin, "cat", url],
|
|
shell=False,
|
|
stdin=file("/dev/null"),
|
|
stdout=subprocess.PIPE,
|
|
stderr=file("/dev/null", "w"))
|
|
return (new_ppd_filename, proc.stdout)
|
|
except OSError:
|
|
pass
|
|
|
|
# Otherwise fall through and try to find a static PPD
|
|
|
|
# Search for a PPD matching our criteria...
|
|
|
|
new_ppd_filename = find_ppd (filename, driver, locale, region)
|
|
if not new_ppd_filename:
|
|
# There wasn't a valid source PPD file, so give up.
|
|
print >>sys.stderr, ("%s: no valid candidate for replacement. "
|
|
"Skipping" % ppd_source_filename)
|
|
print >>sys.stderr, ("%s: please upgrade this PPD manually" %
|
|
ppd_source_filename)
|
|
return ("", None)
|
|
|
|
if debug & 1:
|
|
print "Candidate PPD: %s" % new_ppd_filename
|
|
|
|
suffix = "\\" + gzext # Add '\' so the regexp matches the '.'
|
|
if new_ppd_filename.endswith (".gz"):
|
|
# Decompress input buffer
|
|
try:
|
|
proc = subprocess.Popen (['gunzip', '-c', new_ppd_filename],
|
|
shell=False,
|
|
stdin=file("/dev/null"),
|
|
stdout=subprocess.PIPE,
|
|
stderr=file("/dev/null", "w"))
|
|
except OSError, (e, s):
|
|
print "can't open for decompression: %s" % s
|
|
sys.exit (1)
|
|
|
|
return (new_ppd_filename, proc.stdout)
|
|
else:
|
|
return (new_ppd_filename, file (new_ppd_filename))
|
|
|
|
def find_ppd (gutenprintfilename, drivername, lang, region):
|
|
global file_version
|
|
global optargs
|
|
global ppd_base_dir
|
|
global ppd_root_dir
|
|
global debug
|
|
|
|
key = '^\\*FileVersion:[ ]*' + file_version
|
|
match = re.search (".*/([^/]+\.[0-9]+\.[0-9]+)(\.sim)?(\.ppd)?(\.gz)?$",
|
|
gutenprintfilename)
|
|
if not match:
|
|
return None
|
|
|
|
stored_name = match.groups ()[0]
|
|
if re.search (".*/([^/]*)(\.sim)(\.ppd)?(\.gz)?$", gutenprintfilename):
|
|
simplified = ".sim"
|
|
else:
|
|
simplified = ""
|
|
|
|
stored_dir = os.path.dirname (gutenprintfilename)
|
|
|
|
current_best_file = ""
|
|
current_best_time = 0
|
|
if optargs.has_key ('s'):
|
|
basedirs = [optargs['s']]
|
|
else:
|
|
basedirs = [ppd_base_dir, stored_dir, ppd_root_dir]
|
|
|
|
lingos = []
|
|
if region != "":
|
|
lingos.append ("%s_%s/" % (lang, region))
|
|
|
|
lingos.append ("%s/" % lang)
|
|
if lang != "C":
|
|
lingos.append ("C/")
|
|
|
|
lingos.append ("en/")
|
|
lingos.append ("")
|
|
lingos.append ("Global/")
|
|
bases = ["stp-%s.%s%s" % (drivername, version, simplified),
|
|
"%s.%s%s" % (drivername, version, simplified)]
|
|
if stored_name not in bases:
|
|
bases.append (stored_name)
|
|
|
|
bases.append (drivername)
|
|
|
|
# All possible candidates, in order of usefulness and gzippedness
|
|
for lingo in lingos:
|
|
for suffix in (".ppd%s" % gzext,
|
|
".ppd"):
|
|
for base in bases:
|
|
for basedir in basedirs:
|
|
if basedir == "" or base == "":
|
|
continue
|
|
|
|
fn = "%s/%s%s%s" % (basedir, lingo, base, suffix)
|
|
if debug & 8:
|
|
print ("Trying %s for %s, %s, %s" %
|
|
(fn, gutenprintfilename, lang, region))
|
|
|
|
try:
|
|
st = os.stat (fn)
|
|
except OSError:
|
|
continue
|
|
|
|
if (optargs.has_key ('f') or
|
|
(stat.S_ISREG (st.st_mode) and
|
|
st.st_uid == 0)):
|
|
# Check that the file is a valid Gutenprint PPD file
|
|
# of the correct version.
|
|
if fn.endswith (".gz"):
|
|
cmdline = "gunzip -c '%s' | grep '%s'" % (fn, key)
|
|
else:
|
|
cmdline = "cat '%s' | grep '%s'" % (fn, key)
|
|
|
|
try:
|
|
p = subprocess.Popen (cmdline,
|
|
stdin=file("/dev/null"),
|
|
stdout=subprocess.PIPE,
|
|
stderr=file("/dev/null", "w"))
|
|
except OSError:
|
|
new_file_version = ""
|
|
else:
|
|
(stdin, stderr) = p.communicate ()
|
|
new_file_version = stdin.rstrip ()
|
|
|
|
if new_file_version != "":
|
|
if debug & 8:
|
|
print (" Format valid: time %s best %s "
|
|
"prev %s cur %s!" %
|
|
(st.st_mtime, current_best_time,
|
|
current_best_file, fn))
|
|
|
|
if st.st_mtime > current_best_time:
|
|
current_best_time = st.st_mtime
|
|
current_best_file = fn
|
|
if debug & 8:
|
|
print >>sys.stderr, ("***current_best_file "
|
|
" is %s" % fn)
|
|
elif debug & 8:
|
|
print " Format invalid"
|
|
else:
|
|
if (not stat.S_ISDIR (st.st_mode) and
|
|
not fn.endswith ("/")):
|
|
print >>sys.stderr, ("%s: not a regular file, "
|
|
"or insecure ownership and "
|
|
"permissions. Skipped" % fn)
|
|
|
|
if current_best_file:
|
|
return current_best_file
|
|
|
|
# Yikes! Cannot find a valid PPD file!
|
|
return None
|
|
|
|
debug=0
|
|
verbose=0
|
|
interactive=0
|
|
quiet=0
|
|
no_action=0
|
|
reset_defaults=0
|
|
version="@GUTENPRINT_MAJOR_VERSION@.@GUTENPRINT_MINOR_VERSION@"
|
|
micro_version="@GUTENPRINT_VERSION@"
|
|
use_static_ppd="@BUILD_CUPS_PPDS@"
|
|
file_version='"@VERSION@"$'
|
|
|
|
ppd_dir = "@cups_conf_serverroot@/ppd"
|
|
ppd_root_dir = "@cups_conf_datadir@/model";
|
|
ppd_base_dir = ppd_root_dir + "/gutenprint/" + version
|
|
ppd_out_dir = ""
|
|
gzext = ".gz"
|
|
updated_ppd_count = 0
|
|
skipped_ppd_count = 0
|
|
failed_ppd_count = 0
|
|
exit_after_parse_args = 0
|
|
languages=["Global", "C"] + "@ALL_LINGUAS@".split (' ')
|
|
|
|
serverdir = "@cups_conf_serverbin@"
|
|
driver_bin = serverdir + "/driver/gutenprint." + version
|
|
driver_version = ""
|
|
server_multicat = 0
|
|
server_multicat_initialized = 0
|
|
|
|
if os.access (driver_bin, os.X_OK):
|
|
get_driver_version ()
|
|
|
|
ppd_files = []
|
|
languagemappings = { "chinese": "cn",
|
|
"danish": "da",
|
|
"dutch": "nl",
|
|
"english": "en",
|
|
"finnish": "fi",
|
|
"french": "fr",
|
|
"german": "de",
|
|
"greek": "el",
|
|
"hungarian": "hu",
|
|
"italian": "it",
|
|
"japanese": "jp",
|
|
"norwegian": "no",
|
|
"polish": "pl",
|
|
"portuguese": "pt",
|
|
"russian": "ru",
|
|
"slovak": "sk",
|
|
"spanish": "es",
|
|
"swedish": "sv",
|
|
"turkish": "tr" }
|
|
|
|
# Check command-line options...
|
|
args = parse_options()
|
|
|
|
# Set a secure umask...
|
|
os.umask (0177)
|
|
|
|
|
|
# Find all in-use Gutenprint PPD files...
|
|
# For case-insensitive filesystems, use only one of .ppd and .PPD
|
|
# (bug 1929738)
|
|
|
|
for f in args:
|
|
if (os.access (f, os.F_OK) and
|
|
(f.lower ().endswith (".ppd") or
|
|
f.find ("/") != -1)):
|
|
ppd_files.append (f)
|
|
elif os.access ("%s/%s" % (ppd_dir, f), os.F_OK):
|
|
ppd_files.append ("%s/%s" % (ppd_dir, f))
|
|
elif os.access ("%s/%s.ppd" % (ppd_dir, f), os.F_OK):
|
|
ppd_files.append ("%s/%s.ppd" % (ppd_dir, f))
|
|
elif os.access ("%s/%s.PPD" % (ppd_dir, f), os.F_OK):
|
|
ppd_files.append ("%s/%s.PPD" % (ppd_dir, f))
|
|
else:
|
|
print >>sys.stderr, ("Cannot find file %s/%s, %s/%s.ppd, or %s/%s.PPD" %
|
|
ppd_dir, f, ppd_dir, f, ppd_dir, f)
|
|
|
|
if len (args) == 0:
|
|
ppdtmp = glob.glob ("%s/*.ppd" % ppd_dir)
|
|
ppdtmp += glob.glob ("%s/*.PPD" % ppd_dir)
|
|
ppd_map = dict()
|
|
for each in ppdtmp:
|
|
ppd_map[each] = 1
|
|
|
|
for f in ppdtmp:
|
|
if f.endswith (".PPD"):
|
|
g = f[:-4] + ".ppd"
|
|
if not ppd_map.has_key (g):
|
|
ppd_files.append (f)
|
|
else:
|
|
ppd_files.append (f)
|
|
|
|
# Update each of the Gutenprint PPDs, where possible...
|
|
|
|
for ppd_file in ppd_files:
|
|
status = update_ppd (ppd_file)
|
|
if status == -2:
|
|
break
|
|
elif status == 0:
|
|
failed_ppd_count += 1
|
|
elif status == 1:
|
|
updated_ppd_count += 1
|
|
elif status == -1:
|
|
skipped_ppd_count += 1
|
|
|
|
if (not quiet) or verbose:
|
|
if len (ppd_files) == 0:
|
|
print "No Gutenprint PPD files to update."
|
|
elif updated_ppd_count > 0:
|
|
plural = ""
|
|
if updated_ppd_count != 1:
|
|
plural = "s"
|
|
|
|
print "Updated %d PPD file%s" % (updated_ppd_count, plural)
|
|
if ((not optargs.has_key ('o')) or
|
|
optargs['o'] != ""):
|
|
print "Restart cupsd for the changes to take effect."
|
|
else:
|
|
if failed_ppd_count > 0:
|
|
print "Failed to update any PPD files"
|
|
else:
|
|
print "Did not update any PPD files"
|
|
|
|
sys.exit (failed_ppd_count > 0)
|