diff options
Diffstat (limited to 'cups-genppdupdate.py.in')
-rwxr-xr-x | cups-genppdupdate.py.in | 1106 |
1 files changed, 1106 insertions, 0 deletions
diff --git a/cups-genppdupdate.py.in b/cups-genppdupdate.py.in new file mode 100755 index 0000000..1f9e350 --- /dev/null +++ b/cups-genppdupdate.py.in @@ -0,0 +1,1106 @@ +#!/usr/bin/python3 +# $Id$ +# Update CUPS PPDs for Gutenprint queues. +# Copyright (C) 2002-2003 Roger Leigh (rleigh@debian.org) +# Copyright (C) 2009, 2011, 2014 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 io +import os +import re +import stat +import subprocess +import sys +from functools import reduce + +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 stat.S_ISDIR (st.st_mode): + os.chdir (dir) + except OSError as err: + (e, s) = err.args + 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=subprocess.DEVNULL, + stdout=subprocess.PIPE, + stderr=subprocess.DEVNULL, + shell=False) + (stdout, stderr) = p.communicate () + except OSError: + return None + + if stdout != None: + stdout = stdout.decode () + + 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 'n' in optargs: + no_action = 1 + + if 'd' in optargs: + try: + debug = int (optargs['d']) + except ValueError: + d = 0 + + if 'v' in optargs: + verbose = 1 + quiet = 0 + + if 'q' in optargs: + verbose = 0 + quiet = 1 + + if 'N' in optargs: + reset_defaults = 1 + + if 'o' in optargs: + opt_o = optargs['o'] + die_if_not_directory (opt_o) + ppd_out_dir = opt_o + + if 'r' in optargs: + opt_r = optargs['r'] + if version != opt_r: + version = opt_r + if 's' in optargs: + 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 's' in optargs: + 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 'p' in optargs: + opt_p = optargs['p'] + die_if_not_directory (opt_p) + ppd_dir = opt_p + + if 'P' in optargs: + 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 'h' in optargs: + help () + + if ('l' in optargs and + optargs['l'].lower () != "original" and + optargs['l'].lower () not in languages): + print ("Unknown language '%s'" % optargs['l'], file=sys.stderr) + + if 'i' in optargs: + 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 check_encoding(filename): + import charset_normalizer + + with open(filename, 'rb') as f: + charenc = charset_normalizer.detect(f.read())['encoding'] + + if debug & 1: + print("File encoding: {}".format(charenc)) + + if charenc in ['ascii', 'utf-8']: + return 'utf-8' + else: + if debug & 1: + print("Trying to use latin1 for decoding {}".format(charenc)) + + return 'latin1' + +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)) + + fenc = check_encoding(ppd_source_filename) + orig = open(ppd_source_filename, encoding=fenc) + 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 = "" + + try: + orig_lines = orig.readlines() + except UnicodeDecodeError: + if debug & 1: + print('PPD {} has an unexpected enconding, ' + 'skipping.'.format(ppd_source_filename)) + + return -1 + + for line in orig_lines: + line.rstrip () + if line.find ("*StpLocale:") != -1: + match = re.search (r'\*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 (r'^\*LanguageVersion:\s*(.*)$', line) + if match: + groups = match.groups () + if len (groups) >= 1: + lingo = groups[0] + elif line.startswith ("*StpDriverName:"): + match = re.search (r'^\*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 (r'^\*%End of\s*(.*).ppd$', line) + if match: + groups = match.groups () + if len (groups) >= 1: + driver = groups[0] + elif line.startswith ("*StpPPDLocation:"): + match = re.search (r'^\*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 (("Skipping %s: not a Gutenprint PPD file" % + # ppd_source_filename), file=sys.stderr) + return -1 + + if ('l' in optargs and + optargs['l'] != "" and + optargs['l'].lower () != "original"): + locale = optargs['l'] + orig_locale = locale + + if debug & 2: + print ("Gutenprint Filename: %s" % filename) + if 'l' in optargs: + 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 = input ("Update PPD %s from %s [nyq]? " % ppd_source_filename) + inp = inp.lower () + if inp.startswith ("q"): + if server_multicat: + source_fd.detach () + else: + source_fd.close () + + print ("Skipping all...") + return -2 + elif not inp.startswith ("y"): + if server_multicat: + source_fd.detach () + else: + 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 server_multicat: + source_fd.detach () + else: + 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.items (): + 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 (r'(\*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 = list(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 (list(resolution_map.keys ())) > 0: + print ("Resolution Map:") + keys = list(resolution_map.keys ()) + keys.sort () + for key in keys: + print (" %s: %s" % (key, resolution_map[key])) + + if len (list(old_resolution_map.keys ())) > 0: + print ("Old Resolution Map:") + keys = list(old_resolution_map.keys ()) + keys.sort () + for key in keys: + print (" %s: %s" % (key, old_resolution_map[key])) + + print ("Non-UI Defaults:") + keys = list(defaults.keys ()) + keys.sort () + for key in keys: + xkey = key + if xkey.startswith ("Default"): + xkey = xkey[7:] + if xkey not in options: + print (" %s: %s" % (key, defaults[key])) + + print ("Default Types of dropped options:") + keys = list(orig_default_types.keys ()) + keys.sort () + for t in keys: + if t not in options: + 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 = list(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 + def_option in old_resolution_map): + 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 + dopt in resolution_map): + 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 = open (tmpnew, "w") + except IOError as err: + (e, s) = err.args + print ("Can't create %s: %s" % (tmpnew, s)) + return 0 + + newppd.writelines (source_data) + try: + newppd.close () + except IOError as err: + (e, s) = err.args + print ("Can't write to %s: %s" % (tmpnew, s)) + return 0 + + chcon = subprocess.Popen (["chcon", "--reference=%s" % ppd_dest_filename, + tmpnew], shell=False, + stdin=subprocess.DEVNULL, + stdout=subprocess.DEVNULL, + stderr=subprocess.STDOUT) + chcon.communicate () + + try: + os.rename (tmpnew, ppd_dest_filename) + except OSError as err: + (e, s) = err.args + 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 & 0o777) + 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 (r'^\*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 (r'^\*%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 (r'^\*(\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 + ('l' in optargs 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=subprocess.DEVNULL) + server_multicat_initialized = mc_proc + + mc_in = io.TextIOWrapper (server_multicat_initialized.stdin) + print ("%s" % url, file=mc_in) + mc_in.flush () + mc_in.detach () + return (new_ppd_filename, + io.TextIOWrapper (server_multicat_initialized.stdout)) + except OSError: + pass + + try: + proc = subprocess.Popen ([driver_bin, "cat", url], + shell=False, + stdin=subprocess.DEVNULL, + stdout=subprocess.PIPE, + stderr=subprocess.DEVNULL) + return (new_ppd_filename, io.TextIOWrapper (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 (("%s: no valid candidate for replacement. Skipping" % + ppd_source_filename), file=sys.stderr) + print (("%s: please upgrade this PPD manually" % + ppd_source_filename), file=sys.stderr) + 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=subprocess.DEVNULL, + stdout=subprocess.PIPE, + stderr=subprocess.DEVNULL) + except OSError as err: + (e, s) = err.args + print ("can't open for decompression: %s" % s) + sys.exit (1) + + return (new_ppd_filename, io.TextIOWrapper (proc.stdout)) + else: + return (new_ppd_filename, open (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 (r'.*/([^/]+\.[0-9]+\.[0-9]+)(\.sim)?(\.ppd)?(\.gz)?$', + gutenprintfilename) + if not match: + return None + + stored_name = match.groups ()[0] + if re.search (r'.*/([^/]*)(\.sim)(\.ppd)?(\.gz)?$', gutenprintfilename): + simplified = ".sim" + else: + simplified = "" + + stored_dir = os.path.dirname (gutenprintfilename) + + current_best_file = "" + current_best_time = 0 + if 's' in optargs: + 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 ('f' in optargs 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=subprocess.DEVNULL, + stdout=subprocess.PIPE, + stderr=subprocess.DEVNULL) + except OSError: + new_file_version = "" + else: + (stdin, stderr) = p.communicate () + new_file_version = stdin.decode ().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 (("***current_best_file " + " is %s" % fn), file=sys.stderr) + elif debug & 8: + print (" Format invalid") + else: + if (not stat.S_ISDIR (st.st_mode) and + not fn.endswith ("/")): + print (("%s: not a regular file, " + "or insecure ownership and " + "permissions. Skipped" % fn), + file=sys.stderr) + + 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 (0o177) + + +# 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 (("Cannot find file %s/%s, %s/%s.ppd, or %s/%s.PPD" % + ppd_dir, f, ppd_dir, f, ppd_dir, f), file=sys.stderr) + +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 g not in ppd_map: + 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 (('o' not in optargs) 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) |