cups-genppdupdate.py.in 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059
  1. #!/usr/bin/python
  2. # $Id$
  3. # Update CUPS PPDs for Gutenprint queues.
  4. # Copyright (C) 2002-2003 Roger Leigh (rleigh@debian.org)
  5. # Copyright (C) 2009, 2011 Red Hat, Inc.
  6. #
  7. # This program is free software; you can redistribute it and/or modify
  8. # it under the terms of the GNU General Public License as published by
  9. # the Free Software Foundation; either version 2, or (at your option)
  10. # any later version.
  11. #
  12. # This program is distributed in the hope that it will be useful,
  13. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. # GNU General Public License for more details.
  16. #
  17. # You should have received a copy of the GNU General Public License
  18. # along with this program; if not, write to the Free Software
  19. # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  20. import getopt
  21. import glob
  22. import os
  23. import re
  24. import stat
  25. import subprocess
  26. import sys
  27. global optargs
  28. global debug
  29. global verbose
  30. global interactive
  31. global quiet
  32. global no_action
  33. global reset_defaults
  34. global version
  35. global micro_version
  36. global use_static_ppd
  37. global file_version
  38. global ppd_dir
  39. global ppd_root_dir
  40. global ppd_base_dir
  41. global ppd_out_dir
  42. global gzext
  43. global updated_ppd_count
  44. global skipped_ppd_count
  45. global failed_ppd_count
  46. global exit_after_parse_args
  47. global languages
  48. global serverdir
  49. global driver_bin
  50. global driver_version
  51. global server_multicat
  52. global server_multicat_initialized
  53. global ppd_files
  54. global languagemappings
  55. def help():
  56. print """
  57. Usage: %s [OPTION]... [PPD_FILE]...
  58. Update CUPS+Gutenprint PPD files.
  59. -d flags Enable debugging
  60. -h Display this help text
  61. -n No-action. Don't overwrite any PPD files.
  62. -q Quiet mode. No messages except errors.
  63. -s ppd_dir Use ppd_dir as the source PPD directory.
  64. -p ppd_dir Update PPD files in ppd_dir.
  65. -P driver Use the specified driver binary to generate PPD files.
  66. -v Verbose messages.
  67. -N Reset options to defaults.
  68. -o out_dir Output PPD files to out_dir.
  69. -r version Use PPD files for Gutenprint major.minor version.
  70. -f Ignore new PPD file safety checks.
  71. -i Prompt (interactively) for each PPD file.
  72. -l language Language choice (Gutenprint 5.1 or below).
  73. Choices: %s
  74. Or -loriginal to preserve original language
  75. with Gutenprint 5.2 or above
  76. """ % (sys.argv[0],
  77. reduce (lambda x,y: "%s %s" % (x,y), languages))
  78. sys.exit (0)
  79. def die_if_not_directory (dir):
  80. try:
  81. st = os.stat (dir)
  82. if not st.S_ISDIR (st.st_mode):
  83. os.chdir (dir)
  84. except OSError, (e, s):
  85. print "%s: invalid directory: %s" % (dir, s)
  86. sys.exit (1)
  87. def get_driver_version():
  88. global server_multicat
  89. global driver_version
  90. def run_with_arg (arg):
  91. try:
  92. p = subprocess.Popen ([driver_bin, arg],
  93. stdin=file("/dev/null"),
  94. stdout=subprocess.PIPE,
  95. stderr=file("/dev/null", "w"),
  96. shell=False)
  97. (stdout, stderr) = p.communicate ()
  98. except OSError:
  99. return None
  100. return stdout
  101. stdout = run_with_arg ("org.gutenprint.extensions")
  102. if stdout == None:
  103. return
  104. for line in stdout.split ("\n"):
  105. if line == "org.gutenprint.multicat":
  106. server_multicat = 1
  107. break
  108. stdout = run_with_arg ("VERSION")
  109. if stdout == None:
  110. return
  111. driver_version = stdout.strip ()
  112. def parse_options():
  113. try:
  114. opts, args = getopt.getopt (sys.argv[1:], "d:hnqs:vNo:p:P:r:ifl:")
  115. except getopt.GetoptError:
  116. help ()
  117. global optargs
  118. global debug
  119. global verbose
  120. global interactive
  121. global quiet
  122. global no_action
  123. global reset_defaults
  124. global version
  125. global micro_version
  126. global use_static_ppd
  127. global file_version
  128. global ppd_dir
  129. global ppd_out_dir
  130. global ppd_base_dir
  131. global ppd_root_dir
  132. global serverdir
  133. global driver_bin
  134. global driver_version
  135. global server_multicat
  136. global languages
  137. optargs = dict()
  138. for opt, optarg in opts:
  139. optargs[opt[1]] = optarg
  140. if optargs.has_key ('n'):
  141. no_action = 1
  142. if optargs.has_key ('d'):
  143. try:
  144. debug = int (optargs['d'])
  145. except ValueError:
  146. d = 0
  147. if optargs.has_key ('v'):
  148. verbose = 1
  149. quiet = 0
  150. if optargs.has_key ('q'):
  151. verbose = 0
  152. quiet = 1
  153. if optargs.has_key ('N'):
  154. reset_defaults = 1
  155. if optargs.has_key ('o'):
  156. opt_o = optargs['o']
  157. die_if_not_directory (opt_o)
  158. ppd_out_dir = opt_o
  159. if optargs.has_key ('r'):
  160. opt_r = optargs['r']
  161. if version != opt_r:
  162. version = opt_r
  163. if optargs.has_key ('s'):
  164. opt_s = optargs['s']
  165. die_if_not_directory (opt_s)
  166. ppd_base_dir = opt_s
  167. driver_bin = ""
  168. server_multicat = 0
  169. use_static_ppd = "yes"
  170. else:
  171. ppd_base_dir = ppd_root_dir + "/gutenprint/" + version
  172. driver_bin = serverdir + "/driver/gutenprint." + version
  173. driver_version = ""
  174. # If user specifies version, we're not going to be able to check
  175. # for an exact match.
  176. file_version = '"' + version
  177. if os.access (driver_bin, os.X_OK):
  178. get_driver_version ()
  179. use_static_ppd = "no"
  180. file_version = "\"%s\"$" % driver_version
  181. else:
  182. print "Gutenprint %s does not appear to be installed!" % version
  183. sys.exit (1)
  184. if optargs.has_key ('s'):
  185. opt_s = optargs['s']
  186. die_if_not_directory (opt_s)
  187. ppd_base_dir = opt_s
  188. driver_bin = ""
  189. server_multicat = 0
  190. driver_version = ""
  191. use_static_ppd = "yes"
  192. if optargs.has_key ('p'):
  193. opt_p = optargs['p']
  194. die_if_not_directory (opt_p)
  195. ppd_dir = opt_p
  196. if optargs.has_key ('P'):
  197. opt_P = optargs['P']
  198. if os.access (opt_P, os.X_OK):
  199. driver_bin = opt_P
  200. get_driver_version ()
  201. use_static_ppd = "no"
  202. else:
  203. print "%s: invalid executable" % opt_P
  204. if optargs.has_key ('h'):
  205. help ()
  206. if (optargs.has_key ('l') and
  207. optargs['l'].lower () != "original" and
  208. optargs['l'].lower () not in languages):
  209. print >>sys.stderr, "Unknown language '%s'" % optargs['l']
  210. if optargs.has_key ('i'):
  211. interactive = 1
  212. if exit_after_parse_args:
  213. sys.exit (0)
  214. if verbose and driver_version != "":
  215. print "Updating PPD files from Gutenprint %s" % driver_version
  216. return args
  217. def update_ppd (ppd_source_filename):
  218. global ppd_dest_filename
  219. global ppd_out_dir
  220. global optargs
  221. global languagemappings
  222. global interactive
  223. global server_multicat
  224. global no_action
  225. global quiet, verbose
  226. global reset_defaults
  227. ppd_dest_filename = ppd_source_filename
  228. if ppd_out_dir:
  229. ppd_dest_filename = "%s/%s" % (ppd_out_dir,
  230. os.path.basename (ppd_dest_filename))
  231. orig = file (ppd_source_filename)
  232. orig_metadata = os.fstat (orig.fileno ())
  233. if debug & 1:
  234. print "Source Filename: %s" % ppd_source_filename
  235. filename = ""
  236. driver = ""
  237. gutenprintdriver = ""
  238. locale = ""
  239. lingo = ""
  240. region = ""
  241. valid = 0
  242. orig_locale = ""
  243. for line in orig.readlines ():
  244. line.rstrip ()
  245. if line.find ("*StpLocale:") != -1:
  246. match = re.search ("\*StpLocale:\s*\"(.*)\"$", line)
  247. if match:
  248. groups = match.groups ()
  249. if len (groups) >= 1:
  250. locale = groups[0]
  251. orig_locale = locale
  252. valid = 1
  253. elif line.startswith ("*LanguageVersion"):
  254. match = re.search ("^\*LanguageVersion:\s*(.*)$", line)
  255. if match:
  256. groups = match.groups ()
  257. if len (groups) >= 1:
  258. lingo = groups[0]
  259. elif line.startswith ("*StpDriverName:"):
  260. match = re.search ("^\*StpDriverName:\s*\"(.*)\"$", line)
  261. if match:
  262. groups = match.groups ()
  263. if len (groups) >= 1:
  264. driver = groups[0]
  265. valid = 1
  266. elif line.find ("*%End of ") != -1 and driver == "":
  267. match = re.search ("^\*%End of\s*(.*).ppd$", line)
  268. if match:
  269. groups = match.groups ()
  270. if len (groups) >= 1:
  271. driver = groups[0]
  272. elif line.startswith ("*StpPPDLocation:"):
  273. match = re.search ("^\*StpPPDLocation:\s*\"(.*)\"$", line)
  274. if match:
  275. groups = match.groups ()
  276. if len (groups) >= 1:
  277. filename = groups[0]
  278. valid = 1
  279. elif line.startswith ("*%Gutenprint Filename:"):
  280. valid = 1
  281. if filename and driver and lingo and locale:
  282. break
  283. if not valid and line.startswith ("*OpenUI"):
  284. break
  285. if not valid:
  286. #print >>sys.stderr, ("Skipping %s: not a Gutenprint PPD file" %
  287. # ppd_source_filename)
  288. return -1
  289. if (optargs.has_key ('l') and
  290. optargs['l'] != "" and
  291. optargs['l'].lower () != "original"):
  292. locale = optargs['l']
  293. orig_locale = locale
  294. if debug & 2:
  295. print "Gutenprint Filename: %s" % filename
  296. if optargs.has_key ('l'):
  297. print "Locale: %s (from -l)" % locale
  298. else:
  299. print "Locale: %s" % locale
  300. print "Language: %s" % lingo
  301. print "Driver: %s" % driver
  302. if locale:
  303. # Split into the language and territory.
  304. s = locale.split ("_", 1)
  305. locale = s[0]
  306. try:
  307. region = s[1]
  308. except IndexError:
  309. region = ""
  310. else:
  311. # Split into the language and territory.
  312. s = lingo.split ("_", 1)
  313. locale = s[0]
  314. try:
  315. region = s[1]
  316. except IndexError:
  317. region = ""
  318. # Convert language into language code.
  319. locale = languagemappings.get (lingo.lower (), "C")
  320. if debug & 2:
  321. print "Base Locale: %s" % locale
  322. print "Region: %s" % region
  323. # Read in the new PPD, decompressing it if needed...
  324. (new_ppd_filename, source_fd) = get_ppd_fh (ppd_source_filename,
  325. filename,
  326. driver,
  327. locale,
  328. region)
  329. if source_fd == None:
  330. print "Unable to retrieve PPD file!"
  331. return 0
  332. if interactive:
  333. inp = raw_input ("Update PPD %s from %s [nyq]? " % ppd_source_filename)
  334. inp = inp.lower ()
  335. if inp.startswith ("q"):
  336. if not server_multicat:
  337. source_fd.close ()
  338. print "Skipping all..."
  339. return -2
  340. elif not inp.startswith ("y"):
  341. if not server_multicat:
  342. source_fd.close ()
  343. print "Skipping..."
  344. return -1
  345. # Extract the default values from the original PPD...
  346. orig.seek (0)
  347. (odt, oopt, ores, odef, unused) = get_ppd_data (orig, 1, 0, 1, 1, 0)
  348. (ndt, nopt, nres, ndef, source_data) = get_ppd_data (source_fd,
  349. 1, 1, 1, 1, 1)
  350. # Close original and temporary files...
  351. orig.close ()
  352. if not server_multicat:
  353. source_fd.close ()
  354. orig_default_types = odt
  355. new_default_types = ndt
  356. defaults = odef
  357. new_defaults = ndef
  358. options = nopt
  359. resolution_map = nres
  360. old_resolution_map = dict()
  361. for key, value in resolution_map.iteritems ():
  362. old_resolution_map[value] = key
  363. # Store previous language in the PPD file so that -l original works
  364. # correctly.
  365. if orig_locale != "":
  366. lines = source_data.rstrip ().split ("\n")
  367. source_data = ""
  368. for line in lines:
  369. m = re.search ("(\*StpLocale:\s*\")(.*)(\")", line)
  370. if m:
  371. groups = m.groups ()
  372. line = groups[0] + orig_locale + groups[2]
  373. source_data += line + "\n"
  374. if debug & 4:
  375. print "Options (Old->New Default Type):"
  376. keys = options.keys ()
  377. keys.sort ()
  378. for t in keys:
  379. old_type = orig_default_types.get (t, "(New)")
  380. new_type = new_default_types.get (t)
  381. if old_type != new_type:
  382. out = " %s (%s -> %s) : " % (t, old_type, new_type)
  383. else:
  384. out = " %s (%s) : " % (t, new_type)
  385. dft = defaults.get ("Default%s" % t)
  386. for opt in options.get (t, []):
  387. if dft != None and dft == opt:
  388. out += "*"
  389. out += "%s " % opt
  390. print out
  391. if len (resolution_map.keys ()) > 0:
  392. print "Resolution Map:"
  393. keys = resolution_map.keys ()
  394. keys.sort ()
  395. for key in keys:
  396. print " %s: %s" % (key, resolution_map[key])
  397. if len (old_resolution_map.keys ()) > 0:
  398. print "Old Resolution Map:"
  399. keys = old_resolution_map.keys ()
  400. keys.sort ()
  401. for key in keys:
  402. print " %s: %s" % (key, old_resolution_map[key])
  403. print "Non-UI Defaults:"
  404. keys = defaults.keys ()
  405. keys.sort ()
  406. for key in keys:
  407. xkey = key
  408. if xkey.startswith ("Default"):
  409. xkey = xkey[7:]
  410. if not options.has_key (xkey):
  411. print " %s: %s" % (key, defaults[key])
  412. print "Default Types of dropped options:"
  413. keys = orig_default_types.keys ()
  414. keys.sort ()
  415. for t in keys:
  416. if not options.has_key (t):
  417. print " %s: %s" % (t, orig_default_types[t])
  418. if no_action:
  419. if not quiet or verbose:
  420. if ppd_dest_filename == ppd_source_filename:
  421. print "Would update %s using %s" % (ppd_source_filename,
  422. new_ppd_filename)
  423. else:
  424. print "Would update %s to %s using %s" % (ppd_source_filename,
  425. ppd_dest_filename,
  426. new_ppd_filename)
  427. return 0
  428. if not reset_defaults:
  429. # Update source buffer with old defaults...
  430. # Loop through each default in turn.
  431. keys = defaults.keys ()
  432. keys.sort ()
  433. for default_option in keys:
  434. default_option_value = defaults[default_option]
  435. option = default_option
  436. if option.startswith ("Default"):
  437. # Strip off `Default'
  438. option = option[7:]
  439. # Check method is valid
  440. orig_method = orig_default_types.get (option)
  441. new_method = new_default_types.get (option)
  442. new_default = new_defaults.get (default_option)
  443. if (orig_method == None or new_method == None or
  444. orig_method != new_method):
  445. continue
  446. if (new_default != None and
  447. default_option_value == new_default):
  448. if verbose:
  449. print "%s: Preserve *%s (%s)" % (ppd_source_filename,
  450. default_option,
  451. default_option_value)
  452. continue
  453. if new_method == "PickOne":
  454. next_default = False
  455. # Check the old setting is valid
  456. for opt in options.get (option, []):
  457. def_option = default_option_value
  458. odef_option = def_option
  459. if (option == "Resolution" and
  460. old_resolution_map.has_key (def_option)):
  461. if debug & 4:
  462. print ("Intermapping old resolution %s to %s" %
  463. def_option, old_resolution_map[def_option])
  464. def_option = old_resolution_map[def_option]
  465. dopts = [def_option]
  466. if def_option != odef_option:
  467. dopts.append (odef_option)
  468. for dopt in dopts:
  469. valid = False
  470. if dopt == opt:
  471. valid = True
  472. elif (option == "Resolution" and
  473. resolution_map.has_key (dopt)):
  474. dopt = resolution_map[dopt]
  475. if dopt == opt:
  476. valid = True
  477. if valid:
  478. # Valid option
  479. # Set the option in the new PPD
  480. lines = source_data.rstrip ().split ("\n")
  481. source_data = ""
  482. attr = "*%s" % default_option
  483. for line in lines:
  484. if line.startswith (attr):
  485. line = "%s:%s" % (attr, dopt)
  486. source_data += line + "\n"
  487. if verbose:
  488. print "%s: Set *%s to %s" % (ppd_source_filename,
  489. default_option,
  490. dopt)
  491. next_default = True
  492. break
  493. if next_default:
  494. break
  495. if next_default:
  496. continue
  497. print ("Warning: %s: Invalid option: *%s: %s. Using default "
  498. "setting %s." % (ppd_source_filename, default_option,
  499. defaults[default_option],
  500. new_defaults[default_option]))
  501. continue
  502. print ("Warning: %s: PPD OpenUI method %s not understood." %
  503. (ppd_source_filename, new_default_types[default_option]))
  504. # Write new PPD...
  505. tmpnew = "%s.new" % ppd_dest_filename
  506. try:
  507. newppd = file (tmpnew, "w")
  508. except IOError, (e, s):
  509. print "Can't create %s: %s" % (tmpnew, s)
  510. return 0
  511. newppd.writelines (source_data)
  512. try:
  513. newppd.close ()
  514. except IOError, (e, s):
  515. print "Can't write to %s: %s" % (tmpnew, s)
  516. return 0
  517. chcon = subprocess.Popen (["chcon", "--reference=%s" % ppd_dest_filename,
  518. tmpnew], shell=False,
  519. stdin=file("/dev/null"),
  520. stdout=file("/dev/null", "w"),
  521. stderr=subprocess.STDOUT)
  522. chcon.communicate ()
  523. try:
  524. os.rename (tmpnew, ppd_dest_filename)
  525. except OSError, (e, s):
  526. print "Can't rename %s to %s: %s" % (tmpnew, ppd_dest_filename, s)
  527. try:
  528. os.unlink (tmpnew)
  529. except OSError:
  530. pass
  531. return 0
  532. try:
  533. os.chown (ppd_dest_filename,
  534. orig_metadata.st_uid,
  535. orig_metadata.st_gid)
  536. except OSError:
  537. pass
  538. try:
  539. os.chmod (ppd_dest_filename,
  540. orig_metadata.st_mode & 0777)
  541. except OSError:
  542. pass
  543. if not quiet or verbose:
  544. if ppd_dest_filename == ppd_source_filename:
  545. print "Updated %s using %s" % (ppd_source_filename,
  546. new_ppd_filename)
  547. else:
  548. print "Updated %s to %s using %s" % (ppd_source_filename,
  549. ppd_dest_filename,
  550. new_ppd_filename)
  551. # All done!
  552. return 1
  553. def get_ppd_data (fh, types, opts, resolutions, defaults, data):
  554. options_map = dict()
  555. defaults_map = dict()
  556. resolution_map = dict()
  557. default_types = dict()
  558. cur_opt = ""
  559. optionlist = []
  560. source_data = ""
  561. if reset_defaults:
  562. types = 0
  563. opts = 0
  564. resolutions = 0
  565. defaults = 0
  566. if resolutions or types or opts or defaults or data:
  567. while True:
  568. line = fh.readline ()
  569. if line == '':
  570. break
  571. if line == "*%*%EOFEOF\n":
  572. break
  573. source_data += line
  574. line = line.strip ()
  575. if (types or opts) and line.startswith ("*OpenUI"):
  576. m = re.search ("^\*OpenUI\s\*(\w+).*:\s(\w+)",
  577. line)
  578. if m:
  579. groups = m.groups ()
  580. key = groups[0]
  581. value = groups[1]
  582. default_types[key] = value
  583. cur_opt = key
  584. elif opts and line.startswith ("*CloseUI"):
  585. if cur_opt != "":
  586. options_map[cur_opt] = optionlist
  587. cur_opt = ""
  588. optionlist = []
  589. elif opts and line.startswith ("*%s" % cur_opt):
  590. m = re.search ("^\*%s\s*(\w+)[\/:]" % cur_opt, line)
  591. if m:
  592. groups = m.groups()
  593. if len (groups) >= 1:
  594. value = m.groups ()[0]
  595. optionlist.append (value)
  596. elif resolutions and line.startswith ("*StpResolutionMap:"):
  597. s = line.split (None, 3)
  598. if len (s) == 3:
  599. new = s[1]
  600. old = s[2]
  601. resolution_map[old] = new
  602. elif defaults and line.startswith ("*Default"):
  603. m = re.search ("^\*(\w+):\s*(\w+)", line)
  604. if m:
  605. groups = m.groups ()
  606. key = groups[0]
  607. value = groups[1]
  608. defaults_map[key] = value
  609. return (default_types, options_map, resolution_map,
  610. defaults_map, source_data)
  611. def get_ppd_fh (ppd_source_filename, filename, driver, locale, region):
  612. global use_static_ppd
  613. global driver_version
  614. global optargs
  615. global driver_bin
  616. global debug
  617. global server_multicat, server_multicat_initialized
  618. global gzext
  619. if use_static_ppd == "no" and driver_version != "":
  620. if re.search (".*/([^/]*)(.sim)(.ppd)?(.gz)?$", filename):
  621. simplified = "simple"
  622. else:
  623. simplified = "expert"
  624. opt_r = optargs.get ('r')
  625. if opt_r:
  626. try:
  627. opt_r = float (opt_r)
  628. except ValueError:
  629. opt_r = None
  630. url_list = []
  631. if (((opt_r != None and opt_r < 5.2) or
  632. (optargs.has_key ('l') and optargs['l'] != "")) and
  633. locale != ""):
  634. if region:
  635. url_list.append ("gutenprint.%s://%s/%s/%s_%s" %
  636. version, driver, simplified, locale, region)
  637. url_list.append ("gutenprint.%s://%s/%s/%s" %
  638. version, driver, simplified, locale)
  639. url_list.append ("gutenprint.%s://%s/%s" % (version, driver,
  640. simplified))
  641. for url in url_list:
  642. new_ppd_filename = url
  643. if debug & 8:
  644. if server_multicat:
  645. cat = ""
  646. else:
  647. cat = "%s cat " % driver_bin
  648. print ("Trying %s%s for %s, %s, %s, %s" %
  649. (cat, url, driver, simplified, locale, region))
  650. if server_multicat:
  651. try:
  652. if not server_multicat_initialized:
  653. mc_proc = subprocess.Popen ([driver_bin,
  654. "org.gutenprint.multicat"],
  655. shell=False,
  656. stdin=subprocess.PIPE,
  657. stdout=subprocess.PIPE,
  658. stderr=file("/dev/null",
  659. "w"))
  660. server_multicat_initialized = mc_proc
  661. print >>server_multicat_initialized.stdin, "%s" % url
  662. server_multicat_initialized.stdin.flush ()
  663. return (new_ppd_filename,
  664. server_multicat_initialized.stdout)
  665. except OSError:
  666. pass
  667. try:
  668. proc = subprocess.Popen ([driver_bin, "cat", url],
  669. shell=False,
  670. stdin=file("/dev/null"),
  671. stdout=subprocess.PIPE,
  672. stderr=file("/dev/null", "w"))
  673. return (new_ppd_filename, proc.stdout)
  674. except OSError:
  675. pass
  676. # Otherwise fall through and try to find a static PPD
  677. # Search for a PPD matching our criteria...
  678. new_ppd_filename = find_ppd (filename, driver, locale, region)
  679. if not new_ppd_filename:
  680. # There wasn't a valid source PPD file, so give up.
  681. print >>sys.stderr, ("%s: no valid candidate for replacement. "
  682. "Skipping" % ppd_source_filename)
  683. print >>sys.stderr, ("%s: please upgrade this PPD manually" %
  684. ppd_source_filename)
  685. return ("", None)
  686. if debug & 1:
  687. print "Candidate PPD: %s" % new_ppd_filename
  688. suffix = "\\" + gzext # Add '\' so the regexp matches the '.'
  689. if new_ppd_filename.endswith (".gz"):
  690. # Decompress input buffer
  691. try:
  692. proc = subprocess.Popen (['gunzip', '-c', new_ppd_filename],
  693. shell=False,
  694. stdin=file("/dev/null"),
  695. stdout=subprocess.PIPE,
  696. stderr=file("/dev/null", "w"))
  697. except OSError, (e, s):
  698. print "can't open for decompression: %s" % s
  699. sys.exit (1)
  700. return (new_ppd_filename, proc.stdout)
  701. else:
  702. return (new_ppd_filename, file (new_ppd_filename))
  703. def find_ppd (gutenprintfilename, drivername, lang, region):
  704. global file_version
  705. global optargs
  706. global ppd_base_dir
  707. global ppd_root_dir
  708. global debug
  709. key = '^\\*FileVersion:[ ]*' + file_version
  710. match = re.search (".*/([^/]+\.[0-9]+\.[0-9]+)(\.sim)?(\.ppd)?(\.gz)?$",
  711. gutenprintfilename)
  712. if not match:
  713. return None
  714. stored_name = match.groups ()[0]
  715. if re.search (".*/([^/]*)(\.sim)(\.ppd)?(\.gz)?$", gutenprintfilename):
  716. simplified = ".sim"
  717. else:
  718. simplified = ""
  719. stored_dir = os.path.dirname (gutenprintfilename)
  720. current_best_file = ""
  721. current_best_time = 0
  722. if optargs.has_key ('s'):
  723. basedirs = [optargs['s']]
  724. else:
  725. basedirs = [ppd_base_dir, stored_dir, ppd_root_dir]
  726. lingos = []
  727. if region != "":
  728. lingos.append ("%s_%s/" % (lang, region))
  729. lingos.append ("%s/" % lang)
  730. if lang != "C":
  731. lingos.append ("C/")
  732. lingos.append ("en/")
  733. lingos.append ("")
  734. lingos.append ("Global/")
  735. bases = ["stp-%s.%s%s" % (drivername, version, simplified),
  736. "%s.%s%s" % (drivername, version, simplified)]
  737. if stored_name not in bases:
  738. bases.append (stored_name)
  739. bases.append (drivername)
  740. # All possible candidates, in order of usefulness and gzippedness
  741. for lingo in lingos:
  742. for suffix in (".ppd%s" % gzext,
  743. ".ppd"):
  744. for base in bases:
  745. for basedir in basedirs:
  746. if basedir == "" or base == "":
  747. continue
  748. fn = "%s/%s%s%s" % (basedir, lingo, base, suffix)
  749. if debug & 8:
  750. print ("Trying %s for %s, %s, %s" %
  751. (fn, gutenprintfilename, lang, region))
  752. try:
  753. st = os.stat (fn)
  754. except OSError:
  755. continue
  756. if (optargs.has_key ('f') or
  757. (stat.S_ISREG (st.st_mode) and
  758. st.st_uid == 0)):
  759. # Check that the file is a valid Gutenprint PPD file
  760. # of the correct version.
  761. if fn.endswith (".gz"):
  762. cmdline = "gunzip -c '%s' | grep '%s'" % (fn, key)
  763. else:
  764. cmdline = "cat '%s' | grep '%s'" % (fn, key)
  765. try:
  766. p = subprocess.Popen (cmdline,
  767. stdin=file("/dev/null"),
  768. stdout=subprocess.PIPE,
  769. stderr=file("/dev/null", "w"))
  770. except OSError:
  771. new_file_version = ""
  772. else:
  773. (stdin, stderr) = p.communicate ()
  774. new_file_version = stdin.rstrip ()
  775. if new_file_version != "":
  776. if debug & 8:
  777. print (" Format valid: time %s best %s "
  778. "prev %s cur %s!" %
  779. (st.st_mtime, current_best_time,
  780. current_best_file, fn))
  781. if st.st_mtime > current_best_time:
  782. current_best_time = st.st_mtime
  783. current_best_file = fn
  784. if debug & 8:
  785. print >>sys.stderr, ("***current_best_file "
  786. " is %s" % fn)
  787. elif debug & 8:
  788. print " Format invalid"
  789. else:
  790. if (not stat.S_ISDIR (st.st_mode) and
  791. not fn.endswith ("/")):
  792. print >>sys.stderr, ("%s: not a regular file, "
  793. "or insecure ownership and "
  794. "permissions. Skipped" % fn)
  795. if current_best_file:
  796. return current_best_file
  797. # Yikes! Cannot find a valid PPD file!
  798. return None
  799. debug=0
  800. verbose=0
  801. interactive=0
  802. quiet=0
  803. no_action=0
  804. reset_defaults=0
  805. version="@GUTENPRINT_MAJOR_VERSION@.@GUTENPRINT_MINOR_VERSION@"
  806. micro_version="@GUTENPRINT_VERSION@"
  807. use_static_ppd="@BUILD_CUPS_PPDS@"
  808. file_version='"@VERSION@"$'
  809. ppd_dir = "@cups_conf_serverroot@/ppd"
  810. ppd_root_dir = "@cups_conf_datadir@/model";
  811. ppd_base_dir = ppd_root_dir + "/gutenprint/" + version
  812. ppd_out_dir = ""
  813. gzext = ".gz"
  814. updated_ppd_count = 0
  815. skipped_ppd_count = 0
  816. failed_ppd_count = 0
  817. exit_after_parse_args = 0
  818. languages=["Global", "C"] + "@ALL_LINGUAS@".split (' ')
  819. serverdir = "@cups_conf_serverbin@"
  820. driver_bin = serverdir + "/driver/gutenprint." + version
  821. driver_version = ""
  822. server_multicat = 0
  823. server_multicat_initialized = 0
  824. if os.access (driver_bin, os.X_OK):
  825. get_driver_version ()
  826. ppd_files = []
  827. languagemappings = { "chinese": "cn",
  828. "danish": "da",
  829. "dutch": "nl",
  830. "english": "en",
  831. "finnish": "fi",
  832. "french": "fr",
  833. "german": "de",
  834. "greek": "el",
  835. "hungarian": "hu",
  836. "italian": "it",
  837. "japanese": "jp",
  838. "norwegian": "no",
  839. "polish": "pl",
  840. "portuguese": "pt",
  841. "russian": "ru",
  842. "slovak": "sk",
  843. "spanish": "es",
  844. "swedish": "sv",
  845. "turkish": "tr" }
  846. # Check command-line options...
  847. args = parse_options()
  848. # Set a secure umask...
  849. os.umask (0177)
  850. # Find all in-use Gutenprint PPD files...
  851. # For case-insensitive filesystems, use only one of .ppd and .PPD
  852. # (bug 1929738)
  853. for f in args:
  854. if (os.access (f, os.F_OK) and
  855. (f.lower ().endswith (".ppd") or
  856. f.find ("/") != -1)):
  857. ppd_files.append (f)
  858. elif os.access ("%s/%s" % (ppd_dir, f), os.F_OK):
  859. ppd_files.append ("%s/%s" % (ppd_dir, f))
  860. elif os.access ("%s/%s.ppd" % (ppd_dir, f), os.F_OK):
  861. ppd_files.append ("%s/%s.ppd" % (ppd_dir, f))
  862. elif os.access ("%s/%s.PPD" % (ppd_dir, f), os.F_OK):
  863. ppd_files.append ("%s/%s.PPD" % (ppd_dir, f))
  864. else:
  865. print >>sys.stderr, ("Cannot find file %s/%s, %s/%s.ppd, or %s/%s.PPD" %
  866. ppd_dir, f, ppd_dir, f, ppd_dir, f)
  867. if len (args) == 0:
  868. ppdtmp = glob.glob ("%s/*.ppd" % ppd_dir)
  869. ppdtmp += glob.glob ("%s/*.PPD" % ppd_dir)
  870. ppd_map = dict()
  871. for each in ppdtmp:
  872. ppd_map[each] = 1
  873. for f in ppdtmp:
  874. if f.endswith (".PPD"):
  875. g = f[:-4] + ".ppd"
  876. if not ppd_map.has_key (g):
  877. ppd_files.append (f)
  878. else:
  879. ppd_files.append (f)
  880. # Update each of the Gutenprint PPDs, where possible...
  881. for ppd_file in ppd_files:
  882. status = update_ppd (ppd_file)
  883. if status == -2:
  884. break
  885. elif status == 0:
  886. failed_ppd_count += 1
  887. elif status == 1:
  888. updated_ppd_count += 1
  889. elif status == -1:
  890. skipped_ppd_count += 1
  891. if (not quiet) or verbose:
  892. if len (ppd_files) == 0:
  893. print "No Gutenprint PPD files to update."
  894. elif updated_ppd_count > 0:
  895. plural = ""
  896. if updated_ppd_count != 1:
  897. plural = "s"
  898. print "Updated %d PPD file%s" % (updated_ppd_count, plural)
  899. if ((not optargs.has_key ('o')) or
  900. optargs['o'] != ""):
  901. print "Restart cupsd for the changes to take effect."
  902. else:
  903. if failed_ppd_count > 0:
  904. print "Failed to update any PPD files"
  905. else:
  906. print "Did not update any PPD files"
  907. sys.exit (failed_ppd_count > 0)