source: trunk/debathena/config/printing-config/files/usr/bin/lpr.debathena @ 24515

Revision 24515, 7.2 KB checked in by broder, 14 years ago (diff)
In printing-config: * Add a debathena.printing Python module for common logic: - Determining the print system and print server to use based on the name of a queue
  • Property svn:executable set to *
Line 
1#!/usr/bin/python
2
3# lpr.debathena
4#
5# also lp.debathena, lpq.debathena, and lprm.debathena
6#
7# Wrapper script that intelligently determines whether a command was
8# intended for should go to CUPS or LPRng and sends it off in the
9# right direction
10
11import cups
12import hesiod
13import getopt
14import os
15import shlex
16import socket
17import sys
18from subprocess import call, PIPE
19
20from debathena import printing
21
22try:
23    cupsd = cups.Connection()
24except RuntimeError: # Is this actually safer than "except:"?
25    cupsd = None
26
27def hesiod_lookup(hes_name, hes_type):
28    """A wrapper with somewhat graceful error handling."""
29    try:
30        h = hesiod.Lookup(hes_name, hes_type)
31        if len(h.results) > 0:
32            return h.results
33    except IOError:
34        return []
35
36def lpropt_transform(args):
37    if 'LPROPT' in os.environ:
38        return shlex.split(os.environ['LPROPT']) + args
39    return args
40
41def zephyr_transform(options):
42    zephyr = True
43    return_options = []
44    for o, a in options:
45        if o == '-N':
46            zephyr = False
47        else:
48            return_options.append((o, a))
49
50    if zephyr and os.environ.get('ATHENA_USER'):
51        return_options.append(('-m', 'zephyr%' + os.environ['ATHENA_USER']))
52
53    return return_options
54
55opts = {
56    'cups': {
57        'lp': ('EU:cd:h:mn:o:q:st:H:P:i:', None, '-d'),
58        'lpq': ('EU:h:P:al', None, '-P'),
59        'lpr': ('EH:U:P:#:hlmo:pqrC:J:T:',
60            (lpropt_transform, zephyr_transform), '-P'),
61        'lprm': ('EU:h:P:', None, '-P'),
62    },
63    'lprng': {
64        'lp': ('ckmprswBGYd:D:f:n:q:t:', None, '-d'),
65        'lpq': ('aAlLVcvP:st:D:', None, '-P'),
66        'lpr': ('ABblC:D:F:Ghi:kJ:K:#:m:NP:rR:sT:U:Vw:X:YZ:z1:2:3:4:',
67            (lpropt_transform, zephyr_transform), '-P'),
68        'lprm': ('aAD:P:VU:', None, '-P'),
69    }
70}
71
72def error(code, message):
73    """Exit out with an error
74    """
75    sys.stderr.write(message)
76    sys.exit(code)
77
78def execCups(command, queue, args):
79    """Pass the command and arguments on to the CUPS versions of the command
80    """
81    new_command = '/usr/bin/cups-%s' % command
82    os.execv(new_command, [command] + args)
83
84def execLprng(command, queue, args):
85    """Pass the command and arguments on to the LPRng versions of the command
86    """
87    new_command = '/usr/bin/mit-%s' % command
88    os.execv(new_command, [command] + args)
89
90def getPrintQueue(command, args):
91    """Given argv, extract the printer name, using knowledge of the possible
92    command line options for both the CUPS and LPRng versions of the command
93    that this script was called as. Also, return whether the command line
94    options imply a particular version of the command.
95    """
96
97    preference = 'cups'
98    for version in ['cups', 'lprng']:
99        try:
100            # Get the set of options that correspond to the command that this
101            # script was invoked as
102            (cmd_opts, transformers, destopt) = opts[version][command]
103            if transformers:
104                (transform_args, transform_opts) = transformers
105            else:
106                transform_args = transform_opts = lambda x: x
107        except KeyError:
108            error(1, """
109Error: this script was called as %s, when it must be called as
110one of lpr, lpq, lprm, or lp
111
112""" % command)
113
114        # Attempt to parse it with the current version of this command
115        targs = transform_args(args)
116        try:
117            options, realargs = getopt.gnu_getopt(targs, cmd_opts)
118        except getopt.GetoptError:
119            # That's the wrong version, so try the next one.
120            continue
121
122        options = transform_opts(options)
123        ttargs = [o + a for o, a in options] + realargs
124        if destopt:
125            for o, a in options:
126                if o == destopt:
127                    return (version, a, ttargs)
128        else:
129            if len(realargs) > 0:
130                return (version, realargs[0], ttargs)
131        # Since we've successfully getopt'd, don't try any other versions,
132        # but do note that we like this version.
133        preference = version
134        break
135
136    # Either we failed to getopt, or nobody told us what printer to use,
137    # so let's use the default printer
138    default = os.getenv('PRINTER')
139    if not default:
140        if cupsd:
141            default = cupsd.getDefault()
142    if not default:
143        h = hesiod_lookup(os.uname()[1], 'cluster')
144        for result in h:
145            (key, value) = result.split(None, 1)
146            if key == 'lpr':
147                default = value
148
149    if default:
150        return (preference, default, args)
151    else:
152        error(2, """
153No default printer configured. Specify a -P option, or configure a
154default printer via e.g. System | Administration | Printing.
155
156""")
157
158def translate_lprng_args_to_cups(command, args):
159    # TODO yell at user if/when we decide that these args are deprecated
160
161    # If getopt fails, something went very wrong -- _we_ generated this
162    options, realargs = getopt.gnu_getopt(args, opts['lprng'][command][0])
163    cupsargs = []
164    for (o, a) in options:
165        if o in ('-a') and command == 'lpq':
166            cupsargs += [('-a', a)]
167        elif o in ('-b', '-l') and command == 'lpr':
168            cupsargs += [('-l', a)]
169        elif o in ('-h') and command == 'lpr':
170            cupsargs += [('-h', a)]
171        elif o in ('-J') and command == 'lpr':
172            cupsargs += [('-J', a)]
173        elif o in ('-K', '-#') and command == 'lpr':
174            cupsargs += [('-#', a)]
175        elif o in ('-P'):
176            cupsargs += [('-P', a)]
177        elif o in ('-T') and command == 'lpr':
178            cupsargs += [('-T', a)]
179        elif o in ('-U') and command == 'lpr':
180            cupsargs += [('-U', a)]
181        elif o in ('-v') and command == 'lpq':
182            cupsargs += [('-l', a)]
183        elif o in ('-Z') and command == 'lpr':
184            if a == 'simplex':
185                cupsargs += [('-o', 'sides=one-sided')]
186            elif a == 'duplex':
187                cupsargs += [('-o', 'sides=two-sided-long-edge')]
188            elif a == 'duplexshort':
189                cupsargs += [('-o', 'sides=two-sided-short-edge')]
190            # TODO attempt to deal banner=staff
191        elif o in ('-m') and command == 'lpr':
192            # TODO figure out if CUPS can do mail/zephyr
193            pass # Don't warn about this, we probably generated it
194        else:
195            sys.stderr.write("Warning: option %s%s not converted to CUPS\n"
196                             % (o, a))
197    joincupsargs = [o + a for o, a in cupsargs] + realargs
198    sys.stderr.write("Using cups-%s %s\n" % (command, ' '.join(joincupsargs)))
199    return joincupsargs
200
201if __name__ == '__main__':
202    # Remove the command name from the arguments when we extract it
203    command = os.path.basename(sys.argv.pop(0))
204
205    # Determine if the arguments prefer one version of this command,
206    # For instance, "lpr -Zduplex" wants mit-lpr.
207    preference, queue, args = getPrintQueue(command, sys.argv)
208
209    system, server, queue = printing.find_queue(queue)
210
211    if system == printing.SYSTEM_CUPS:
212        if preference == 'lprng':
213            args = translate_lprng_args_to_cups(command, args)
214        if server:
215            os.environ['CUPS_SERVER'] = server
216        execCups(command, queue, args)
217    else:
218        execLprng(command, queue, args)
Note: See TracBrowser for help on using the repository browser.