Source code for linuxmusterLinuxclient7.printers

import os, subprocess, re
from linuxmusterLinuxclient7 import logging, user

_allowedPrinterUriSchemes = ["ipp", "ipps", "http", "https", "smb", "lpd", "socket", "dnssd"]

[docs] def installPrinter(networkPath, name=None, username=None): """ Installs a networked printer for a user :param networkPath: The network path of the printer in format `ipp://server/printers/PRINTER-01` :type networkPath: str :param name: The name for the printer, defaults to None :type name: str, optional :param username: The username of the user whom the is installed printer for. Defaults to the executing user :type username: str, optional :return: True on success, False otherwise :rtype: bool """ if username == None: username = user.username() if name == None: name = networkPath.split("/")[-1] if user.isRoot(): return _installPrinter(username, networkPath, name) else: # This will call installPrinter() again with root privileges return _installPrinterWithoutRoot(networkPath, name)
[docs] def uninstallAllPrintersOfUser(username): """ Uninstalls all printers of a given user :param username: The username of the user :type username: str :return: True on success, False otherwise :rtype: bool """ logging.info(f"Uninstalling all printers of {username}") installedPrinters = _getInstalledPrintersOfUser(username) for installedPrinter in installedPrinters: remainingUsers = [u for u in _getAllowedUsersOfPrinter(installedPrinter) if u != username] if len(remainingUsers) > 0: if not _setAllowedUsersOfPrinter(installedPrinter, remainingUsers): return False elif not _uninstallPrinter(installedPrinter): return False return True
[docs] def translateSambaToIpp(networkPath): """ Translates a samba url, like `\\\\server\\PRINTER-01`, to an ipp url like `ipp://server/printers/PRINTER-01`. :param networkPath: The samba url :type networkPath: str :return: An ipp url :rtype: str """ networkPath = networkPath.replace("\\", "/") # path has to be translated: \\server\EW-FARBLASER -> ipp://server/printers/EW-farblaser pattern = re.compile("\\/\\/([^/]+)\\/(.+)") result = pattern.findall(networkPath) if len(result) != 1 or len(result[0]) != 2: logging.error(f"Cannot convert printer network path from samba to ipp, as it is invalid: {networkPath}") return False, None ippNetworkPath = f"ipp://{result[0][0]}/printers/{result[0][1]}" return True, ippNetworkPath
# -------------------- # - Helper functions - # -------------------- def _installPrinter(username, networkPath, name): if not _printerNetworkPathIsValid(networkPath): logging.error(f"Refusing to install printer: invalid network path '{networkPath}'") return False if not _printerNameIsValid(name): logging.error(f"Refusing to install printer: invalid printer name '{name}'") return False allowedUsers = _getAllowedUsersOfPrinter(name) if username not in allowedUsers: allowedUsers.append(username) logging.info(f"Install Printer {name} on {networkPath}") installCommand = ["timeout", "10", "/usr/sbin/lpadmin", "-p", name, "-E", "-v", networkPath, "-m", "everywhere", "-u", f"allow:{','.join(allowedUsers)}"] logging.debug(f"* running '{' '.join(installCommand)}'") p = subprocess.call(installCommand, stdout=subprocess.PIPE, stderr=subprocess.PIPE) if p == 0: logging.debug("* Success Install Printer!") return True elif p == 124: logging.fatal(f"* Timeout error while installing printer {name} on {networkPath}") else: logging.fatal(f"* Error installing printer {name} on {networkPath}!") return False def _installPrinterWithoutRoot(networkPath, name): return subprocess.call(["sudo", "/usr/share/linuxmuster-linuxclient7/scripts/sudoTools", "install-printer", "--path", networkPath, "--name", name]) == 0 def _getInstalledPrintersOfUser(username): logging.info(f"Getting installed printers of {username}") command = ["/usr/bin/lpstat", "-U", username, "-p"] #logging.debug(f"running '{command}'") result = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True) if not result.returncode == 0: logging.info("No Printers installed.") return [] rawInstalledPrinters = list(filter(None, result.stdout.split("\n"))) installedPrinters = [] for rawInstalledPrinter in rawInstalledPrinters: rawInstalledPrinterList = list(filter(None, rawInstalledPrinter.split(" "))) if len(rawInstalledPrinterList) < 2: continue installedPrinter = rawInstalledPrinterList[1] installedPrinters.append(installedPrinter) return installedPrinters def _uninstallPrinter(name): logging.info(f"Uninstall Printer {name}") uninstallCommand = ["timeout", "10", "/usr/sbin/lpadmin", "-x", name] logging.debug(f"* running '{' '.join(uninstallCommand)}'") p = subprocess.call(uninstallCommand, stdout=subprocess.PIPE, stderr=subprocess.PIPE) if p == 0: logging.debug("* Success Uninstall Printer!") return True elif p == 124: logging.fatal(f"* Timeout error while installing printer {name}") else: logging.fatal(f"* Error Uninstalling Printer {name}!") return False def _getAllowedUsersOfPrinter(name): """ Get the users which are allowed to use a printer :param name: The name of the printer :type name: str :return: List of usernames, empty if the printer does not exist or is not restricted to specific users :rtype: list """ command = ["/usr/bin/lpstat", "-l", "-p", name] result = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True, env={**os.environ, "LC_ALL": "C"}) if not result.returncode == 0: return [] allowedUsers = [] inAllowedUsers = False for line in result.stdout.split("\n"): if line.strip() == "Users allowed:": inAllowedUsers = True elif inAllowedUsers and line.startswith("\t\t"): allowedUsers.append(line.strip()) else: inAllowedUsers = False if "(all)" in allowedUsers or "(none)" in allowedUsers: return [] return allowedUsers def _setAllowedUsersOfPrinter(name, allowedUsers): """ Restrict a printer to the given users :param name: The name of the printer :type name: str :param allowedUsers: The users which are allowed to use the printer :type allowedUsers: list :return: True on success, False otherwise :rtype: bool """ logging.info(f"Allow printer {name} only for {', '.join(allowedUsers)}") command = ["timeout", "10", "/usr/sbin/lpadmin", "-p", name, "-u", f"allow:{','.join(allowedUsers)}"] logging.debug(f"* running '{' '.join(command)}'") return subprocess.call(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) == 0 def _printerNetworkPathIsValid(networkPath): """ Checks if a printer network path is an URI with an allowed scheme (e.g. `ipp://`) :param networkPath: The network path of the printer :type networkPath: str :return: True if valid, False otherwise :rtype: bool """ if not networkPath or not networkPath.isprintable(): return False match = re.match(r"^([a-zA-Z][a-zA-Z0-9+.-]*)://", networkPath) if not match: return False return match.group(1).lower() in _allowedPrinterUriSchemes def _printerNameIsValid(name): """ Checks if a printer name is valid for CUPS (printable characters except space, tab, `/`, `\\`, `#` and quotes) :param name: The name of the printer :type name: str :return: True if valid, False otherwise :rtype: bool """ if not name or not name.isprintable() or name.startswith("-"): return False return not any(c in name for c in " \t/\\#'\"")