summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCoprDistGit <infra@openeuler.org>2025-03-24 13:58:49 +0000
committerCoprDistGit <infra@openeuler.org>2025-03-24 13:58:49 +0000
commita0749a3273bba247e73c7c620d97ba2d77ad5e40 (patch)
treef3be6f61b155227d5efa52c8696253e0eb9c3176
parentf2f443387aa1f754263a00c8664563817ac14b8e (diff)
automatic import of gutenprintopeneuler24.03_LTS
-rw-r--r--.gitignore1
-rwxr-xr-xcups-genppdupdate.py.in1106
-rw-r--r--gutenprint-manpage.patch27
-rw-r--r--gutenprint-menu.patch11
-rw-r--r--gutenprint-postscriptdriver.patch98
-rw-r--r--gutenprint-yyin.patch26
-rw-r--r--gutenprint.spec159
-rw-r--r--sources1
8 files changed, 1429 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
index e69de29..77c9a74 100644
--- a/.gitignore
+++ b/.gitignore
@@ -0,0 +1 @@
+/gutenprint-5.3.5.tar.xz
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)
diff --git a/gutenprint-manpage.patch b/gutenprint-manpage.patch
new file mode 100644
index 0000000..07689ad
--- /dev/null
+++ b/gutenprint-manpage.patch
@@ -0,0 +1,27 @@
+diff -up gutenprint-5.2.9/man/escputil.1.in.manpage gutenprint-5.2.9/man/escputil.1.in
+--- gutenprint-5.2.9/man/escputil.1.in.manpage 2013-06-27 15:02:09.997386927 +0100
++++ gutenprint-5.2.9/man/escputil.1.in 2013-06-27 15:08:16.236046768 +0100
+@@ -20,6 +20,7 @@ escputil \- maintain Epson Stylus inkjet
+ .SH SYNOPSIS
+ .B escputil
+ [ \fI\-P\fP \fIprinter\fP | \fI\-r\fP \fIdevice\fP ] [ \fI\-m\fP \fImodel\fP ] [
++\fI\-S\fP ] [ \fI\-C\fP ] [ \fI\-p\fP ] [
+ \fI\-u\fP ] [ \fI\-c\fP | \fI\-n\fP | \fI\-a\fP | \fI\-i\fP | \fI\-d\fP |
+ \fI\-o\fP | \fI\-s\fP | \fI\-l\fP | \fI\-M\fP | \fI\-h\fP ] [ \fI\-q\fP ]
+ .SH DESCRIPTION
+@@ -46,6 +47,15 @@ Specify the precise printer model for he
+ .B \-u, \-\-new
+ The printer is a new printer (Stylus Color 740 or newer).
+ .TP
++.B \-S, \-\-short\-name
++Print the short name of the printer with \-\-identify.
++.TP
++.B \-C, \-\-choices
++Specify the number of pattern choices for alignment.
++.TP
++.B \-p, \-\-patterns
++Specify the number of sets of patterns for alignment.
++.TP
+ .B \-c, \-\-clean\-head
+ Clean the print head. This can also be performed from the printer
+ front panel.
diff --git a/gutenprint-menu.patch b/gutenprint-menu.patch
new file mode 100644
index 0000000..2c76a41
--- /dev/null
+++ b/gutenprint-menu.patch
@@ -0,0 +1,11 @@
+--- gutenprint-5.0.0/src/gimp2/print-print.c.menu 2007-03-02 17:08:51.000000000 +0000
++++ gutenprint-5.0.0/src/gimp2/print-print.c 2007-03-02 17:09:10.000000000 +0000
+@@ -43,7 +43,7 @@
+ (BAD_CONST_CHAR) copy,
+ (BAD_CONST_CHAR) VERSION " - " RELEASE_DATE,
+ /* Do not translate the prefix "<Image>" */
+- (BAD_CONST_CHAR) N_("<Image>/File/Print..."),
++ (BAD_CONST_CHAR) N_("<Image>/File/Send/Print..."),
+ (BAD_CONST_CHAR) types,
+ GIMP_PLUGIN,
+ n_args, 0,
diff --git a/gutenprint-postscriptdriver.patch b/gutenprint-postscriptdriver.patch
new file mode 100644
index 0000000..d4b5ff7
--- /dev/null
+++ b/gutenprint-postscriptdriver.patch
@@ -0,0 +1,98 @@
+diff -up gutenprint-5.3.3/src/main/gutenprint-internal.h.postscriptdriver gutenprint-5.3.3/src/main/gutenprint-internal.h
+--- gutenprint-5.3.3/src/main/gutenprint-internal.h.postscriptdriver 2018-01-28 03:32:45.000000000 +0100
++++ gutenprint-5.3.3/src/main/gutenprint-internal.h 2019-11-06 12:13:29.936061606 +0100
+@@ -54,6 +54,8 @@ extern void stpi_init_printer(void);
+ #define BUFFER_FLAG_FLIP_X 0x1
+ #define BUFFER_FLAG_FLIP_Y 0x2
+ extern stp_image_t* stpi_buffer_image(stp_image_t* image, unsigned int flags);
++extern stp_list_t *stp_paths_copy_with_prefix(stp_list_t* list,
++ const char *prefix);
+
+ #define STPI_ASSERT(x,v) \
+ do \
+diff -up gutenprint-5.3.3/src/main/module.c.postscriptdriver gutenprint-5.3.3/src/main/module.c
+--- gutenprint-5.3.3/src/main/module.c.postscriptdriver 2019-05-25 16:34:21.000000000 +0200
++++ gutenprint-5.3.3/src/main/module.c 2019-11-06 12:13:29.936061606 +0100
+@@ -159,12 +159,20 @@ int stp_module_load(void)
+ }
+ else
+ {
++ const char *prefix = getenv("DESTDIR");
+ #ifdef USE_LTDL
+ stp_path_split(dir_list, getenv("LTDL_LIBRARY_PATH"));
+ stp_path_split(dir_list, lt_dlgetsearchpath());
+ #else
+ stp_path_split(dir_list, PKGMODULEDIR);
+ #endif
++ if (prefix)
++ {
++ stp_list_t *prefix_list;
++ prefix_list = stp_paths_copy_with_prefix(dir_list, prefix);
++ stp_list_destroy(dir_list);
++ dir_list = prefix_list;
++ }
+ }
+ #ifdef USE_LTDL
+ file_list = stp_path_search(dir_list, ".la");
+diff -up gutenprint-5.3.3/src/main/path.c.postscriptdriver gutenprint-5.3.3/src/main/path.c
+--- gutenprint-5.3.3/src/main/path.c.postscriptdriver 2019-05-25 16:34:21.000000000 +0200
++++ gutenprint-5.3.3/src/main/path.c 2019-11-06 12:29:30.709190171 +0100
+@@ -154,6 +154,17 @@ stp_generate_path(const char *path)
+ return NULL;
+ stp_list_set_freefunc(dir_list, stp_list_node_free_data);
+ stp_path_split(dir_list, path);
++ if (!strncmp(PKGXMLDATADIR, path, strlen(path)))
++ {
++ const char *prefix = getenv("DESTDIR");
++ if (prefix)
++ {
++ stp_list_t *prefix_list;
++ prefix_list = stp_paths_copy_with_prefix(dir_list, prefix);
++ stp_list_destroy(dir_list);
++ dir_list = prefix_list;
++ }
++ }
+ return dir_list;
+ }
+
+@@ -262,6 +273,40 @@ stp_path_split(stp_list_t *list, /* List
+ }
+ }
+
++/*
++ * Split a PATH-type string (colon-delimited) into separate
++ * directories.
++ */
++stp_list_t *
++stp_paths_copy_with_prefix(stp_list_t *list, /* List to add prefix to */
++ const char *prefix) /* Prefix to add */
++{
++ stp_list_t *new_list;
++ stp_list_item_t *item;
++ int prefixlen = strlen (prefix);
++ if (!(new_list = stp_list_create()))
++ return NULL;
++
++ item = stp_list_get_start (list);
++ while (item)
++ {
++ const char *data;
++ char *new_data;
++ int len;
++ data = stp_list_item_get_data (item);
++ len = strlen (data);
++ new_data = (char *) stp_malloc(prefixlen + 1 + len + 1);
++ strncpy(new_data, prefix, prefixlen);
++ new_data[prefixlen] = '/';
++ strcpy(new_data + prefixlen + 1, data);
++ stp_list_item_create(new_list, NULL, new_data);
++
++ item = stp_list_item_next (item);
++ }
++
++ return new_list;
++}
++
+ /* Adapted from GNU libc <dirent.h>
+ These macros extract size information from a `struct dirent *'.
+ They may evaluate their argument multiple times, so it must not
diff --git a/gutenprint-yyin.patch b/gutenprint-yyin.patch
new file mode 100644
index 0000000..79658ca
--- /dev/null
+++ b/gutenprint-yyin.patch
@@ -0,0 +1,26 @@
+diff -up gutenprint-5.2.9/src/gutenprintui2/Makefile.am.yyin gutenprint-5.2.9/src/gutenprintui2/Makefile.am
+--- gutenprint-5.2.9/src/gutenprintui2/Makefile.am.yyin 2010-09-12 14:52:53.000000000 +0100
++++ gutenprint-5.2.9/src/gutenprintui2/Makefile.am 2012-12-18 16:27:11.705127153 +0000
+@@ -55,7 +55,8 @@ libgutenprintui2_la_CFLAGS = $(AM_CFLAGS
+ # Uncomment to build a versioned library
+ libgutenprintui2_la_LDFLAGS = \
+ -version-info $(GUTENPRINTUI2_CURRENT_INTERFACE):$(GUTENPRINTUI2_INTERFACE_AGE):$(GUTENPRINTUI2_BINARY_AGE) \
+- -rpath $(libdir) -no-undefined
++ -rpath $(libdir) -no-undefined \
++ -export-symbols-regex '^([^y]|y[^y])'
+
+ AM_LFLAGS = -i
+ AM_YFLAGS = -d
+diff -up gutenprint-5.2.9/src/gutenprintui2/Makefile.in.yyin gutenprint-5.2.9/src/gutenprintui2/Makefile.in
+--- gutenprint-5.2.9/src/gutenprintui2/Makefile.in.yyin 2012-07-07 16:36:19.000000000 +0100
++++ gutenprint-5.2.9/src/gutenprintui2/Makefile.in 2012-12-18 16:27:11.705127153 +0000
+@@ -367,7 +367,8 @@ libgutenprintui2_la_CFLAGS = $(AM_CFLAGS
+ # Uncomment to build a versioned library
+ libgutenprintui2_la_LDFLAGS = \
+ -version-info $(GUTENPRINTUI2_CURRENT_INTERFACE):$(GUTENPRINTUI2_INTERFACE_AGE):$(GUTENPRINTUI2_BINARY_AGE) \
+- -rpath $(libdir) -no-undefined
++ -rpath $(libdir) -no-undefined \
++ -export-symbols-regex '^([^y]|y[^y])'
+
+ AM_LFLAGS = -i
+ AM_YFLAGS = -d
diff --git a/gutenprint.spec b/gutenprint.spec
new file mode 100644
index 0000000..edfda66
--- /dev/null
+++ b/gutenprint.spec
@@ -0,0 +1,159 @@
+%bcond_with gimp
+
+Name: gutenprint
+Version: 5.3.5
+Release: 1
+Summary: A suite of printer drivers
+License: GPL-2.0-or-later AND LGPL-2.0-or-later AND MIT AND GPL-3.0-or-later WITH Bison-exception-2.2
+URL: https://gimp-print.sourceforge.io/
+Source0: https://downloads.sourceforge.net/gimp-print/%{name}-%{version}.tar.xz
+Source1: cups-genppdupdate.py.in
+Patch0: gutenprint-menu.patch
+Patch1: gutenprint-postscriptdriver.patch
+Patch2: gutenprint-yyin.patch
+Patch3: gutenprint-manpage.patch
+
+%if %{with gimp}
+BuildRequires: pkgconfig(gimpui-2.0), gimp
+Requires: gimp
+Provides: %{name}-plugin%{?_isa} %{name}-plugin
+Obsoletes: %{name}-plugin
+%endif
+
+BuildRequires: cups-libs, cups-devel, cups, gettext-devel, pkgconfig, libtiff-devel, libjpeg-devel, libpng-devel
+BuildRequires: pkgconfig(libusb-1.0), pkgconfig(gtk+-2.0), chrpath, python3-cups
+BuildRequires: autoconf, automake, libtool, python3-devel
+Requires: cups
+Provides: %{name}-doc%{?_isa} %{name}-doc
+Obsoletes: %{name}-doc
+Provides: %{name}-libs%{?_isa} %{name}-libs
+Obsoletes: %{name}-libs
+Provides: %{name}-libs-ui%{?_isa} %{name}-libs-ui
+Obsoletes: %{name}-libs-ui
+Provides: %{name}-extras%{?_isa} %{name}-extras
+Obsoletes: %{name}-extras
+Provides: %{name}-cups%{?_isa} %{name}-cups
+Obsoletes: %{name}-cups
+
+%description
+Gutenprint, formerly named Gimp-Print, is a suite of printer drivers that may be used with CUPS,
+the Common UNIX Printing System. CUPS is the printing system used by all modern Linux and UNIX systems.
+These drivers provide high quality printing for UNIX (including Macintosh OS X 10.2 and later)
+and Linux systems that in many cases equal or exceed proprietary vendor-supplied drivers in quality
+and functionality, and can be used for demanding printing tasks requiring flexibility and high quality.
+This software package include an enhanced Print plugin for the GIMP that replaces the plugin packaged
+with the GIMP in addition to the CUPS driver.
+Gutenprint has been renamed in order to clearly distinguish it from the GIMP. While this package
+started out as the original Print plugin for the GIMP, it has expanded into a collection of general
+purpose printer drivers, and the new, enhanced Print plugin for the GIMP is now only a small part of
+the package. Furthermore, the name Gutenprint recognizes Johannes Gutenberg, the inventor of the movable
+type printing press. Finally, the word guten is the German word for good.
+Gutenprint 5.2 incorporates extensive feedback from the beta and release candidate programs.
+Gutenprint supports only the printer portion of multi-function devices (devices that typically include
+scanning, copying, and fax capabilities).
+Gutenprint currently supports over 700 printer models.
+
+%package devel
+Summary: Development files for %{name}
+Requires: %{name}%{?_isa} = %{version}-%{release}, gtk2-devel
+
+%description devel
+This package includes development files for %{name}.
+
+%package_help
+
+%prep
+%autosetup -p1 -n %{name}-%{version}
+cp %{SOURCE1} src/cups/cups-genppdupdate.in
+
+%build
+sed -i -e 's,^\(TESTS *=.*\) run-weavetest,\1,' test/Makefile.in
+
+%configure --disable-dependency-tracking --disable-static --enable-samples --enable-escputil --enable-test \
+ --disable-rpath --enable-cups-1_2-enhancements --disable-cups-ppds --enable-simplified-cups-ppds
+
+%make_build
+
+%install
+%make_install
+%delete_la
+
+install -d $RPM_BUILD_ROOT%{_sbindir}
+
+rm -rf $RPM_BUILD_ROOT%{_datadir}/%{name}/doc
+rm -rf $RPM_BUILD_ROOT%{_datadir}/foomatic/kitload.log
+rm -rf $RPM_BUILD_ROOT%{_libdir}/%{name}/5.2/modules/*.la
+rm -rf $RPM_BUILD_ROOT%{_sysconfdir}/cups/command.types
+
+%find_lang %{name}
+sed 's!%{_datadir}/locale/\([^/]*\)/LC_MESSAGES/gutenprint.mo!%{_datadir}/locale/\1/gutenprint_\1.po!g' %{name}.lang >%{name}-po.lang
+rm -rf %{name}.lang
+%find_lang %{name} --all-name
+cat %{name}-po.lang >>%{name}.lang
+
+echo .so man8/cups-genppd.8 > $RPM_BUILD_ROOT%{_mandir}/man8/cups-genppd.5.2.8
+
+chrpath -d $RPM_BUILD_ROOT%{_sbindir}/cups-genppd.5.3
+%if %{with gimp}
+chrpath -d $RPM_BUILD_ROOT%{_libdir}/gimp/*/plug-ins/*
+%endif
+chrpath -d $RPM_BUILD_ROOT%{_libdir}/*.so.*
+chrpath -d $RPM_BUILD_ROOT%{_cups_serverbin}/driver/*
+chrpath -d $RPM_BUILD_ROOT%{_cups_serverbin}/filter/*
+chrpath -d $RPM_BUILD_ROOT%{_bindir}/*
+
+%post
+/usr/sbin/cups-genppdupdate &>/dev/null || :
+/sbin/service cups reload &>/dev/null || :
+exit 0
+
+%files -f %{name}.lang
+%license COPYING
+%doc AUTHORS NEWS README doc/FAQ.html doc/%{name}-users-manual.odt doc/%{name}-users-manual.pdf
+%{_bindir}/escputil
+%{_bindir}/testpattern
+%{_bindir}/cups-calibrate
+%{_sbindir}/cups-genppd*
+%{_datadir}/%{name}
+%{_datadir}/%{name}/samples/*
+%{_datadir}/cups/calibrate.ppm
+%{_datadir}/cups/usb/net.sf.gimp-print.usb-quirks
+%{_libdir}/%{name}
+%{_libdir}/*.so.*
+%if %{with gimp}
+%{_libdir}/gimp/*/plug-ins/%{name}
+%endif
+%{_cups_serverbin}/filter/*
+%{_cups_serverbin}/driver/*
+%{_cups_serverbin}/backend/*
+
+%files devel
+%doc doc/developer/reference-html doc/developer/%{name}.pdf doc/%{name}*
+%{_includedir}/%{name}*/
+%{_libdir}/*.so
+%{_libdir}/pkgconfig/*.pc
+
+%files help
+%{_mandir}/man*/*
+
+%changelog
+* Mon Mar 24 2025 Funda Wang <fundawang@yeah.net> - 5.3.5-1
+- update to 5.3.5
+
+* Mon Oct 09 2023 Ge Wang <wang__Ge@126.com> - 5.3.4-1
+- Update to version 5.3.4
+
+* Mon Jan 9 2023 yaoguangzhong <yaoguangzhong@xfusion.com> - 5.2.14-8
+- backport Minor doc issues
+
+* Sat Jan 7 2023 yaoguangzhong <yaoguangzhong@xfusion.com> - 5.2.14-7
+- backport add Epson Expression ET-2600 EcoTank
+
+* Sat Feb 20 2021 lingsheng <lingsheng@huawei.com> - 5.2.14-6
+- Disable gimp plugins build
+
+* Thu Nov 26 2020 liuweibo <liuweibo10@hauwei.com> - 5.2.14-5
+- Fix install warning
+
+* Sat Nov 30 2019 openEuler Buildteam <buildteam@openeuler.org> - 5.2.14-4
+- Package init
diff --git a/sources b/sources
new file mode 100644
index 0000000..94a0479
--- /dev/null
+++ b/sources
@@ -0,0 +1 @@
+18968a1376a0fb0155afea4ce832d7fd gutenprint-5.3.5.tar.xz