- Timestamp:
- 08/10/06 23:08:32 (18 years ago)
- Files:
-
- 1 modified
Legend:
- Unmodified
- Added
- Removed
-
tea4cups/trunk/tea4cups
r677 r679 23 23 # 24 24 # 25 26 """Tea4CUPS is the Swiss Army's knife of the CUPS Administrator. 27 28 29 Licensing terms : 30 31 (c) 2005, 2006 Jerome Alet <alet@librelogiciel.com> 32 (c) 2005 Peter Stuge <stuge-tea4cups@cdy.org> 33 This program is free software; you can redistribute it and/or modify 34 it under the terms of the GNU General Public License as published by 35 the Free Software Foundation; either version 2 of the License, or 36 (at your option) any later version. 37 38 This program is distributed in the hope that it will be useful, 39 but WITHOUT ANY WARRANTY; without even the implied warranty of 40 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 41 GNU General Public License for more details. 42 43 You should have received a copy of the GNU General Public License 44 along with this program; if not, write to the Free Software 45 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 46 47 48 Setup : 49 50 Copy the different files where they belong : 51 52 $ cp tea4cups /usr/lib/cups/backend/ 53 $ chown root.root /usr/lib/cups/backend/tea4cups 54 $ chmod 700 /usr/lib/cups/backend/tea4cups 55 $ cp tea4cups.conf /etc/cupsd/ 56 57 Now edit the configuration file to suit your needs : 58 59 $ vi /etc/cupsd/tea4cups.conf 60 61 NB : you can use emacs as well :-) 62 63 Finally restart CUPS : 64 65 $ /etc/init.d/cupsys restart 66 67 You can now create "Tea4CUPS Managed" print queues from 68 CUPS' web interface, or using lpadmin. 69 70 Send bug reports to : alet@librelogiciel.com 71 """ 25 72 26 73 import sys … … 798 845 raise ConfigError, "Invalid configuration file : no option %s in section [%s]" % (option, section) 799 846 847 def isTrue(option) : 848 """Returns 1 if option is set to true, else 0.""" 849 if (option is not None) and (option.upper().strip() in ['Y', 'YES', '1', 'ON', 'T', 'TRUE']) : 850 return 1 851 else : 852 return 0 853 854 def getCupsConfigDirectives(directives=[]) : 855 """Retrieves some CUPS directives from its configuration file. 856 857 Returns a mapping with lowercased directives as keys and 858 their setting as values. 859 """ 860 dirvalues = {} 861 cupsroot = os.environ.get("CUPS_SERVERROOT", "/etc/cups") 862 cupsdconf = os.path.join(cupsroot, "cupsd.conf") 863 try : 864 conffile = open(cupsdconf, "r") 865 except IOError : 866 raise TeeError, "Unable to open %s" % cupsdconf 867 else : 868 for line in conffile.readlines() : 869 linecopy = line.strip().lower() 870 for di in [d.lower() for d in directives] : 871 if linecopy.startswith("%s " % di) : 872 try : 873 val = line.split()[1] 874 except : 875 pass # ignore errors, we take the last value in any case. 876 else : 877 dirvalues[di] = val 878 conffile.close() 879 return dirvalues 880 800 881 class CupsBackend : 801 882 """Base class for tools with no database access.""" … … 807 888 self.myname = "tea4cups" 808 889 self.pid = os.getpid() 890 self.debug = True 891 self.isCancelled = False 892 self.Title = None 893 self.InputFile = None 894 self.RealBackend = None 895 self.ControlFile = None 896 self.ClientHost = None 897 self.PrinterName = None 898 self.JobBilling = None 899 self.UserName = None 900 self.Copies = None 901 self.Options = None 902 self.DataFile = None 903 self.JobMD5Sum = None 904 self.JobSize = None 905 self.DeviceURI = None 906 self.JobId = None 907 self.Directory = None 908 self.pipes = {} 909 self.config = None 910 self.conffile = None 809 911 810 912 def readConfig(self) : … … 815 917 self.config = ConfigParser.ConfigParser() 816 918 self.config.read([self.conffile]) 817 self.debug = self.isTrue(self.getGlobalOption("debug", ignore=1))919 self.debug = isTrue(self.getGlobalOption("debug", ignore=1)) 818 920 else : 819 921 self.config = FakeConfig() … … 832 934 if self.debug : 833 935 self.logInfo(message, level="debug") 834 835 def isTrue(self, option) :836 """Returns 1 if option is set to true, else 0."""837 if (option is not None) and (option.upper().strip() in ['Y', 'YES', '1', 'ON', 'T', 'TRUE']) :838 return 1839 else :840 return 0841 936 842 937 def getGlobalOption(self, option, ignore=0) : … … 906 1001 # see if the pid contained in the lock file is still running 907 1002 os.kill(pid, 0) 908 except OSError, e :909 if e .errno != errno.EPERM :1003 except OSError, error : 1004 if error.errno != errno.EPERM : 910 1005 # process doesn't exist anymore 911 1006 os.remove(lockfilename) … … 922 1017 answer = os.popen(backend, "r") 923 1018 try : 924 devices = [ line.strip() forline in answer.readlines()]1019 devices = [deviceline.strip() for deviceline in answer.readlines()] 925 1020 except : 926 1021 devices = [] … … 983 1078 fulldevice_uri = device_uri[:] 984 1079 device_uri = fulldevice_uri[len(muststartwith):] 985 for iin range(2) :1080 for dummy in range(2) : 986 1081 if device_uri.startswith("/") : 987 1082 device_uri = device_uri[1:] 988 1083 try : 989 (backend, d estination) = device_uri.split(":", 1)1084 (backend, dummy) = device_uri.split(":", 1) 990 1085 except ValueError : 991 1086 if not device_uri : … … 1015 1110 if type(john) == type([]) : 1016 1111 john = john[-1] 1017 ( chtype, self.ClientHost) = john1112 (dummy, self.ClientHost) = john 1018 1113 try : 1019 1114 jbing = answer.job["job-billing"] … … 1022 1117 if type(jbing) == type([]) : 1023 1118 jbing = jbing[-1] 1024 (jbtype, self.JobBilling) = jbing 1025 1026 def getCupsConfigDirectives(self, directives=[]) : 1027 """Retrieves some CUPS directives from its configuration file. 1028 1029 Returns a mapping with lowercased directives as keys and 1030 their setting as values. 1031 """ 1032 dirvalues = {} 1033 cupsroot = os.environ.get("CUPS_SERVERROOT", "/etc/cups") 1034 cupsdconf = os.path.join(cupsroot, "cupsd.conf") 1035 try : 1036 conffile = open(cupsdconf, "r") 1037 except IOError : 1038 raise TeeError, "Unable to open %s" % cupsdconf 1039 else : 1040 for line in conffile.readlines() : 1041 linecopy = line.strip().lower() 1042 for di in [d.lower() for d in directives] : 1043 if linecopy.startswith("%s " % di) : 1044 try : 1045 val = line.split()[1] 1046 except : 1047 pass # ignore errors, we take the last value in any case. 1048 else : 1049 dirvalues[di] = val 1050 conffile.close() 1051 return dirvalues 1119 (dummy, self.JobBilling) = jbing 1120 1052 1121 1053 1122 def parseIPPRequestFile(self) : … … 1055 1124 requestroot = os.environ.get("CUPS_REQUESTROOT") 1056 1125 if requestroot is None : 1057 cupsdconf = self.getCupsConfigDirectives(["RequestRoot"])1126 cupsdconf = getCupsConfigDirectives(["RequestRoot"]) 1058 1127 requestroot = cupsdconf.get("requestroot", "/var/spool/cups") 1059 1128 if (len(self.JobId) < 5) and self.JobId.isdigit() : … … 1158 1227 def cleanUp(self) : 1159 1228 """Cleans up the place.""" 1160 if (not self.isTrue(self.getPrintQueueOption(self.PrinterName, "keepfiles", ignore=1))) \1229 if (not isTrue(self.getPrintQueueOption(self.PrinterName, "keepfiles", ignore=1))) \ 1161 1230 and os.path.exists(self.DataFile) : 1162 1231 try : … … 1165 1234 self.logInfo("Problem when removing %s : %s" % (self.DataFile, msg), "error") 1166 1235 1167 def sigtermHandler(self, signum, frame) :1168 """Sets an attribute whenever SIGTERM is received."""1169 self.gotSigTerm = 11170 self.logInfo("SIGTERM received for Job %s." % self.JobId)1171 1172 1236 def runBranches(self) : 1173 1237 """Launches each hook defined for the current print queue.""" 1174 1238 self.isCancelled = 0 # did a prehook cancel the print job ? 1175 self.gotSigTerm = 0 1176 signal.signal(signal.SIGTERM, self.sigtermHandler) 1177 serialize = self.isTrue(self.getPrintQueueOption(self.PrinterName, "serialize", ignore=1)) 1239 serialize = isTrue(self.getPrintQueueOption(self.PrinterName, "serialize", ignore=1)) 1178 1240 self.pipes = { 0: (0, 1) } 1179 1241 branches = self.enumBranches(self.PrinterName, "prehook") … … 1183 1245 for p in [ (k, v) for (k, v) in self.pipes.items() if k != 0 ] : 1184 1246 os.close(p[1][1]) 1185 if not self.isCancelled and not self.gotSigTerm:1247 if not self.isCancelled : 1186 1248 if self.RealBackend : 1187 1249 retcode = self.launchOriginalBackend() … … 1192 1254 self.logDebug("Launching onfail script %s" % onfail) 1193 1255 os.system(onfail) 1194 if not self.gotSigTerm : 1195 os.environ["TEASTATUS"] = str(retcode) 1196 branches = self.enumBranches(self.PrinterName, "posthook") 1197 if self.runCommands("posthook", branches, serialize) : 1198 self.logInfo("An error occured during the execution of posthooks.", "warn") 1256 1257 os.environ["TEASTATUS"] = str(retcode) 1258 branches = self.enumBranches(self.PrinterName, "posthook") 1259 if self.runCommands("posthook", branches, serialize) : 1260 self.logInfo("An error occured during the execution of posthooks.", "warn") 1261 1199 1262 for p in [ (k, v) for (k, v) in self.pipes.items() if k != 0 ] : 1200 1263 os.close(p[1][0]) 1201 signal.signal(signal.SIGTERM, signal.SIG_IGN)1202 1264 if not retcode : 1203 1265 self.logInfo("OK") … … 1249 1311 self.logDebug("Begin serialized %ss" % btypetitle) 1250 1312 for branch in branchlist : 1251 if self.gotSigTerm :1252 break1253 1313 retcode = self.runCommand(branch, branches[branch]) 1254 1314 self.logDebug("Exit code for %s %s on printer %s is %s" % (btype, branch, self.PrinterName, retcode)) … … 1265 1325 pids = {} 1266 1326 for branch in branchlist : 1267 if self.gotSigTerm :1268 break1269 1327 pid = os.fork() 1270 1328 if pid : … … 1341 1399 status = os.waitpid(pid, 0)[1] 1342 1400 except OSError, (err, msg) : 1343 if (err == 4) and self.gotSigTerm : 1344 os.kill(pid, signal.SIGTERM) 1401 if err == 4 : 1345 1402 killed = 1 1346 1403 if os.WIFEXITED(status) : 1347 1404 status = os.WEXITSTATUS(status) 1348 1405 if status : 1349 self.logInfo("CUPS backend %s returned %d." % (originalbackend, \1406 self.logInfo("CUPS backend %s returned %d." % (originalbackend, \ 1350 1407 status), "error") 1351 1408 return status 1352 1409 elif not killed : 1353 self.logInfo("CUPS backend %s died abnormally." % originalbackend, \1410 self.logInfo("CUPS backend %s died abnormally." % originalbackend, \ 1354 1411 "error") 1355 1412 return -1 … … 1368 1425 sys.exit(1) 1369 1426 else : 1370 ret code = 11427 returncode = 1 1371 1428 try : 1372 1429 try : … … 1375 1432 wrapper.saveDatasAndCheckSum() 1376 1433 wrapper.exportAttributes() 1377 ret code = wrapper.runBranches()1434 returncode = wrapper.runBranches() 1378 1435 except SystemExit, e : 1379 ret code = e.code1436 returncode = e.code 1380 1437 except : 1381 1438 import traceback 1382 1439 lines = [] 1383 for line in traceback.format_exception(*sys.exc_info()) :1384 lines.extend([l for l in line.split("\n") if l])1385 msg= "ERROR: ".join(["%s (PID %s) : %s\n" % (wrapper.MyName, \1440 for errline in traceback.format_exception(*sys.exc_info()) : 1441 lines.extend([l for l in errline.split("\n") if l]) 1442 errormessage = "ERROR: ".join(["%s (PID %s) : %s\n" % (wrapper.MyName, \ 1386 1443 wrapper.pid, l) \ 1387 1444 for l in (["ERROR: Tea4CUPS v%s" % __version__] + lines)]) 1388 sys.stderr.write( msg)1445 sys.stderr.write(errormessage) 1389 1446 sys.stderr.flush() 1390 ret code = 11447 returncode = 1 1391 1448 finally : 1392 1449 wrapper.cleanUp() 1393 sys.exit(ret code)1450 sys.exit(returncode)