Changeset 3413 for pykota/trunk/bin/pknotify
- Timestamp:
- 09/27/08 22:02:37 (16 years ago)
- Files:
-
- 1 modified
Legend:
- Unmodified
- Added
- Removed
-
pykota/trunk/bin/pknotify
r3411 r3413 9 9 # the Free Software Foundation, either version 3 of the License, or 10 10 # (at your option) any later version. 11 # 11 # 12 12 # This program is distributed in the hope that it will be useful, 13 13 # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 15 # GNU General Public License for more details. 16 # 16 # 17 17 # You should have received a copy of the GNU General Public License 18 18 # along with this program. If not, see <http://www.gnu.org/licenses/>. … … 30 30 try : 31 31 import PAM 32 except ImportError : 32 except ImportError : 33 33 hasPAM = False 34 else : 34 else : 35 35 hasPAM = True 36 36 … … 53 53 -v | --version Prints pknotify's version number then exits. 54 54 -h | --help Prints this message then exits. 55 55 56 56 -d | --destination h[:p] Sets the destination hostname and optional 57 57 port onto which contact the remote PyKotIcon 58 58 application. This option is mandatory. 59 59 When not specified, the port defaults to 7654. 60 60 61 61 -a | --ask Tells pknotify to ask something to the end 62 62 user. Then pknotify will output the result. 63 63 64 64 -C | --checkauth When --ask is used and both an 'username' and a 65 65 'password' are asked to the end user, then … … 70 70 be printed. If the user is authenticated, then 71 71 "USERNAME=xxxx" will be printed as well. 72 73 -c | --confirm Tells pknotify to ask for either a confirmation 72 73 -c | --confirm Tells pknotify to ask for either a confirmation 74 74 or abortion. 75 76 -D | --denyafter N With --checkauth above, makes pknotify loop 75 76 -D | --denyafter N With --checkauth above, makes pknotify loop 77 77 up to N times if the password is incorrect. 78 78 After having reached the limit, "DENY" will … … 80 80 The default value of N is 1, meaning the job 81 81 is denied after the first unsuccessful try. 82 82 83 83 -N | --noremote action If it's impossible to connect to the remote 84 84 PyKotIcon machine, do this action instead. 85 Allowed actions are 'CONTINUE' and 'CANCEL', 85 Allowed actions are 'CONTINUE' and 'CANCEL', 86 86 which will respectively allow the processing 87 87 of the print job to continue, or the job to 88 88 be cancelled. The default value is CANCEL. 89 89 90 90 -n | --notify Tells pknotify to send an informational message 91 91 to the end user. 92 92 93 93 -q | --quit Tells pknotify to send a message asking the 94 94 PyKotIcon application to exit. This option can 95 95 be combined with the other ones to make PyKotIcon 96 96 exit after having sent the answer from the dialog. 97 97 98 98 -t | --timeout T Tells pknotify to ignore the end user's answer if 99 99 it comes past T seconds after the dialog box being 100 opened. The default value is 0 seconds, which 100 opened. The default value is 0 seconds, which 101 101 tells pknotify to wait indefinitely. 102 102 Use this option to avoid having an user who 103 103 leaved his computer stall a whole print queue. 104 104 105 105 You MUST specify either --ask, --confirm, --notify or --quit. 106 106 107 arguments : 108 107 arguments : 108 109 109 -a | --ask : Several arguments are accepted, of the form 110 110 "label:varname:defaultvalue". The result will … … 119 119 it is not printed, it will be used to check if 120 120 authentication is valid if you specify --checkauth. 121 121 122 122 -c | --confirm : A single argument is expected, representing the 123 123 message to display. If the dialog is confirmed 124 124 then pknotify will print OK, else CANCEL. 125 126 -n | --notify : A single argument is expected, representing the 125 126 -n | --notify : A single argument is expected, representing the 127 127 message to display. In this case pknotify will 128 128 always print OK. 129 130 examples : 129 130 examples : 131 131 132 132 pknotify -d client:7654 --noremote CONTINUE --confirm "This job costs 10 credits" 133 133 134 134 Would display the cost of the print job and asks for confirmation. 135 135 If the end user doesn't have PyKotIcon running and accepting connections 136 136 from the print server, PyKota will consider that the end user accepted 137 137 to print this job. 138 138 139 139 pknotify --destination $PYKOTAJOBORIGINATINGHOSTNAME:7654 \\ 140 140 --checkauth --ask "Your name:username:" "Your password:password:" 141 142 Asks an username and password, and checks if they are valid. 141 142 Asks an username and password, and checks if they are valid. 143 143 NB : The PYKOTAJOBORIGINATINGHOSTNAME environment variable is 144 144 only set if you launch pknotify from cupspykota through a directive 145 145 in ~pykota/pykota.conf 146 146 147 147 The TCP port you'll use must be reachable on the client from the 148 148 print server. 149 149 """) 150 151 class TimeoutError(Exception) : 150 151 class TimeoutError(Exception) : 152 152 """An exception for timeouts.""" 153 153 def __init__(self, message = ""): … … 157 157 return self.message 158 158 __str__ = __repr__ 159 160 class PyKotaNotify(Tool) : 159 160 class PyKotaNotify(Tool) : 161 161 """A class for pknotify.""" 162 162 def UTF8ToUserCharset(self, text) : … … 164 164 if text is None : 165 165 return None 166 else : 167 return text.decode("UTF-8", "replace").encode(self.charset, "replace") 168 166 else : 167 return text.decode("UTF-8", "replace").encode(self.charset, "replace") 168 169 169 def userCharsetToUTF8(self, text) : 170 170 """Converts from user's charset to UTF-8.""" 171 171 if text is None : 172 172 return None 173 else : 174 return text.decode(self.charset, "replace").encode("UTF-8", "replace") 175 173 else : 174 return text.decode(self.charset, "replace").encode("UTF-8", "replace") 175 176 176 def sanitizeMessage(self, msg) : 177 177 """Replaces \\n and returns a messagee in xmlrpclib Binary format.""" 178 178 return xmlrpclib.Binary(self.userCharsetToUTF8(msg.replace("\\n", "\n"))) 179 179 180 180 def convPAM(self, auth, queries=[], userdata=None) : 181 181 """Prepares PAM datas.""" … … 191 191 return response 192 192 193 def checkAuth(self, username, password) : 193 def checkAuth(self, username, password) : 194 194 """Checks if we could authenticate an username with a password.""" 195 if not hasPAM : 195 if not hasPAM : 196 196 raise PyKotaToolError, _("You MUST install PyPAM for this functionnality to work !") 197 else : 197 else : 198 198 retcode = False 199 199 self.password = password … … 213 213 retcode = True 214 214 return retcode 215 216 def alarmHandler(self, signum, frame) : 215 216 def alarmHandler(self, signum, frame) : 217 217 """Alarm handler.""" 218 218 raise TimeoutError, _("The end user at %s:%i didn't answer within %i seconds. The print job will be cancelled.") % (self.destination, self.port, self.timeout) 219 219 220 220 def main(self, arguments, options) : 221 221 """Notifies or asks questions to end users through PyKotIcon.""" … … 226 226 self.destination = options["destination"] 227 227 self.port = 7654 228 228 229 229 try : 230 230 denyafter = int(options["denyafter"]) 231 231 if denyafter < 1 : 232 232 raise ValueError 233 except (ValueError, TypeError) : 233 except (ValueError, TypeError) : 234 234 denyafter = 1 235 236 try : 235 236 try : 237 237 self.timeout = int(options["timeout"]) 238 238 if self.timeout < 0 : … … 240 240 except (ValueError, TypeError) : 241 241 self.timeout = 0 242 242 243 243 if self.timeout : 244 244 signal.signal(signal.SIGALRM, self.alarmHandler) 245 245 signal.alarm(self.timeout) 246 247 try : 248 try : 246 247 try : 248 try : 249 249 server = xmlrpclib.ServerProxy("http://%s:%s" % (self.destination, self.port)) 250 250 if options["ask"] : … … 253 253 if denyafter < 1 : 254 254 raise ValueError 255 except (ValueError, TypeError) : 255 except (ValueError, TypeError) : 256 256 denyafter = 1 257 257 labels = [] … … 261 261 try : 262 262 (label, varname, varvalue) = arg.split(":", 2) 263 except ValueError : 263 except ValueError : 264 264 raise PyKotaCommandLineError, "argument '%s' is invalid !" % arg 265 265 labels.append(self.sanitizeMessage(label)) … … 267 267 varnames.append(varname) 268 268 varvalues[varname] = self.sanitizeMessage(varvalue) 269 270 passnumber = 1 269 270 passnumber = 1 271 271 authok = None 272 272 while (authok != "AUTH=YES") and (passnumber <= denyafter) : 273 result = server.askDatas(labels, varnames, varvalues) 273 result = server.askDatas(labels, varnames, varvalues) 274 274 if not options["checkauth"] : 275 275 break 276 276 if result["isValid"] : 277 277 if ("username" in varnames) and ("password" in varnames) : 278 if self.checkAuth(self.UTF8ToUserCharset(result["username"].data[:]), 278 if self.checkAuth(self.UTF8ToUserCharset(result["username"].data[:]), 279 279 self.UTF8ToUserCharset(result["password"].data[:])) : 280 280 authok = "AUTH=YES" 281 else : 281 else : 282 282 authok = "AUTH=NO" 283 else : 284 authok = "AUTH=IMPOSSIBLE" 285 passnumber += 1 286 283 else : 284 authok = "AUTH=IMPOSSIBLE" 285 passnumber += 1 286 287 287 if options["checkauth"] and options["denyafter"] \ 288 288 and (passnumber > denyafter) \ … … 294 294 and ((varname != "username") or (authok in (None, "AUTH=YES"))) : 295 295 print "%s=%s" % (varname.upper(), self.UTF8ToUserCharset(result[varname].data[:])) 296 if authok is not None : 297 print authok 296 if authok is not None : 297 print authok 298 298 elif options["confirm"] : 299 299 print server.showDialog(self.sanitizeMessage(arguments[0]), True) 300 300 elif options["notify"] : 301 301 print server.showDialog(self.sanitizeMessage(arguments[0]), False) 302 303 if options["quit"] : 302 303 if options["quit"] : 304 304 server.quitApplication() 305 305 except (xmlrpclib.ProtocolError, socket.error, socket.gaierror), msg : … … 309 309 #except (AttributeError, IndexError) : 310 310 # pass 311 #else : 311 #else : 312 312 # if errnum == errno.ECONNREFUSED : 313 313 # raise PyKotaToolError, "%s : %s" % (str(msg), (_("Are you sure that PyKotIcon is running and accepting incoming connections on %s:%s ?") % (self.destination, self.port))) 314 314 self.printInfo("%s : %s" % (_("Connection error"), str(msg)), "warn") 315 except TimeoutError, msg : 315 except TimeoutError, msg : 316 316 self.printInfo(msg, "warn") 317 317 print "CANCEL" # Timeout occured : job is cancelled. 318 finally : 319 if self.timeout : 320 signal.alarm(0) 321 318 finally : 319 if self.timeout : 320 signal.alarm(0) 321 322 322 if __name__ == "__main__" : 323 323 retcode = 0 … … 331 331 "timeout=", "ask", "checkauth", "confirm", "notify", \ 332 332 "quit", "noremote=" ] 333 333 334 334 # Initializes the command line tool 335 335 notifier = PyKotaNotify(doc=__doc__) 336 336 notifier.deferredInit() 337 337 338 338 # parse and checks the command line 339 339 (options, args) = notifier.parseCommandline(sys.argv[1:], short_options, long_options) 340 340 341 341 # sets long options 342 342 options["help"] = options["h"] or options["help"] … … 351 351 options["timeout"] = options["t"] or options["timeout"] or defaults["timeout"] 352 352 options["noremote"] = (options["N"] or options["noremote"] or defaults["noremote"]).upper() 353 353 354 354 if options["help"] : 355 355 notifier.display_usage_and_quit() … … 370 370 else : 371 371 retcode = notifier.main(args, options) 372 except KeyboardInterrupt : 372 except KeyboardInterrupt : 373 373 logerr("\nInterrupted with Ctrl+C !\n") 374 374 retcode = -3 375 except PyKotaCommandLineError, msg : 375 except PyKotaCommandLineError, msg : 376 376 logerr("%s : %s\n" % (sys.argv[0], msg)) 377 377 print "CANCEL" # Forces the cancellation of the print job if a command line switch is incorrect 378 378 retcode = -2 379 except SystemExit : 379 except SystemExit : 380 380 pass 381 381 except : 382 382 try : 383 383 notifier.crashed("%s failed" % sys.argv[0]) 384 except : 384 except : 385 385 crashed("%s failed" % sys.argv[0]) 386 386 retcode = -1 387 388 sys.exit(retcode) 387 388 sys.exit(retcode)