diff options
-rwxr-xr-x | standardskriver | 185 |
1 files changed, 185 insertions, 0 deletions
diff --git a/standardskriver b/standardskriver new file mode 100755 index 0000000..60f9f59 --- /dev/null +++ b/standardskriver @@ -0,0 +1,185 @@ +#!/usr/bin/python + +# Copyright (C) 2013, John Sigurd Skogtvedt <jss@linuxavdelingen.no> +# +# 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 of the License, 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., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +# /etc/xdg/autostart/standardskriver.desktop eksempel: +# [Desktop Entry] +# Type=Application +# Exec=standardskriver +# Name=standardskriver +# StartupNotify=false + +CUSTOMER_ID_FILE = '/etc/debian-edu/itzks.school' +CFG_FILE = '/etc/standardskriver.cfg' +CFG_FILE_EXAMPLE = '''[settings] +enable = yes +order = machine groups +delete lpoptions = yes + +# MAC address or IP = printer +# hostname = printer +# hostname.domain = printer +# LTSP client IP = printer +# 10.1.0.0/16 = printer +# (globbing works) + +[machine] +00:01:02:03:04:05 = printer01 +172.16.34.64 = printer02 +hostname = printer01 +hostname.domain = printer02 + +# group name = printer +# (globbing works) + +[groups] +group1 = printer01 +group2 = printer02 +''' +from glob import glob +from fnmatch import fnmatchcase + +import sys +import os +import subprocess +import re +from socket import gethostname, getfqdn +import netaddr +from optparse import OptionParser +import ConfigParser + +# check whose customer system we are on... +customer_id = None +if os.access(CUSTOMER_ID_FILE, os.R_OK): + with open(CUSTOMER_ID_FILE, 'r') as c_id_f: + # only read first line + customer_id = c_id_f.readline() + # sanitize input... + customer_id = re.sub(r'([A-Z0-9]+)(.*\n)', r'\1', customer_id) + +macaddrs = [open(a).read().replace(':', '').strip().lower() for a in glob('/sys/class/net/*/address')] +macaddrs = [a for a in macaddrs if a] + +parser = OptionParser() +parser.add_option('-n', '--dryrun', action='store_true', help='only show what would be done') +options, args = parser.parse_args() + +if not os.path.exists(CFG_FILE): + print >>sys.stderr, 'Configuration file %s is missing.' % CFG_FILE + print >>sys.stderr, 'To create it, redirect the following example to %s and edit the file.' % CFG_FILE + print CFG_FILE_EXAMPLE + sys.exit(1) + +cfg = ConfigParser.RawConfigParser() +# hack: mac addrs contain :, which clashes with cfg syntax +cfg.OPTCRE = re.compile( + r'(?P<option>[^=\s][^=]*)' # very permissive! + r'\s*(?P<vi>[=])\s*' # any number of space/tab, + # followed by separator + # (=), followed + # by any # space/tab + r'(?P<value>.*)$' # everything up to eol + ) +cfg.readfp(open(CFG_FILE, 'rb')) + +if cfg.get('settings', 'enable') != "yes": + sys.exit(0) + +for x in cfg.get('settings', 'order').split(): + if not x in ('machine', 'groups'): + print 'invalid value {val} in settings/order'.format(val=x) + sys.exit(1) + +hostnames = [] +hostnames.append(gethostname()) +hostnames.append(getfqdn()) + +re_ipaddr = re.compile(r'inet addr:(\S+)') +ipaddrs = [] +try: + ipaddrs.append(os.environ['SSH_CLIENT'].split()[0]) +except KeyError: + pass +p = subprocess.Popen(['/sbin/ifconfig'], env={'LANG': 'C'}, stdout=subprocess.PIPE) +for line in p.stdout: + m = re_ipaddr.search(line) + if m: + ipaddrs.append(m.group(1)) +p.wait() + +p = subprocess.Popen(['id', '-Gn'], stdout=subprocess.PIPE) +groups = p.stdout.read().split() +p.wait() +#print groups + +def get_group_match(): + group_sections = ['groups'] + if customer_id: + group_sections.append('groups.{customer}'.format(customer=customer_id)) + for section in group_sections: + try: + for group, printer in cfg.items(section): + if group.strip('@') in groups: return printer + except ConfigParser.NoSectionError: + pass + return None + +def get_machine_match(): + machine_sections = ['machine'] + if customer_id: + machine_sections.append('machine.{customer}'.format(customer=customer_id)) + for section in machine_sections: + try: + for machine, printer in cfg.items(section): + if any(fnmatchcase(macaddr, machine.replace('-', '').replace(':', '')) for macaddr in macaddrs): + return printer + elif any(fnmatchcase(hostname, machine) for hostname in hostnames): + return printer + else: + machines = netaddr.IPSet(machine.split(',')) + myaddrs = netaddr.IPSet(ipaddrs) + if machines & myaddrs: + return printer + except ConfigParser.NoSectionError: + pass + return None + +matches = [] +for item in cfg.get('settings', 'order').split(): + if item == 'machine': matches.append(get_machine_match()) + elif item == 'groups': matches.append(get_group_match()) + else: raise ValueError('%s is not machine or groups' % item) + +try: + printer = [x for x in matches if x][0] +except IndexError: # no match + if cfg.getboolean('settings', 'delete lpoptions'): + lpoptions_filename = os.path.expanduser('~/.cups/lpoptions') + if options.dryrun: + print 'would delete %s' % lpoptions_filename + else: + try: + os.unlink(lpoptions_filename) + except OSError: + pass + sys.exit(0) + +args = ['lpoptions', '-d', printer] +if options.dryrun: + print 'would call %s' % (' '.join(args)) +else: + subprocess.call(args) |