Tizen 2.1 base
[platform/upstream/hplip.git] / fax / backend / hpfax.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 #
4 # (c) Copyright 2003-2009 Hewlett-Packard Development Company, L.P.
5 #
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
10 #
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 # GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 #
20 # Author: Don Welch
21 #
22
23 __version__ = '4.1'
24 __title__ = 'CUPS Fax Backend (hpfax:)'
25 __doc__ = "CUPS backend for PC send fax. Generally this backend is run by CUPS, not directly by a user. To send a fax as a user, run hp-sendfax or print to the device's CUPS fax queue."
26
27 # StdLib
28 import sys
29 import getopt
30 import ConfigParser
31 import os.path, os
32 import syslog
33 import time
34 import operator
35 import tempfile
36
37
38 CUPS_BACKEND_OK = 0 # Job completed successfully
39 CUPS_BACKEND_FAILED = 1 # Job failed, use error-policy
40 CUPS_BACKEND_AUTH_REQUIRED = 2 # Job failed, authentication required
41 CUPS_BACKEND_HOLD = 3 # Job failed, hold job
42 CUPS_BACKEND_STOP = 4 #  Job failed, stop queue
43 CUPS_BACKEND_CANCEL = 5 # Job failed, cancel job
44
45 PIPE_BUF = 4096
46
47 job_id = 0
48 pid = os.getpid()
49 config_file = '/etc/hp/hplip.conf'
50 home_dir = ''
51
52
53 def bug(msg):
54     syslog.syslog("hpfax[%d]: error: %s\n" % (pid, msg))
55     log.stderr("ERROR: %s\n" % msg)
56
57
58 if os.path.exists(config_file):
59     config = ConfigParser.ConfigParser()
60     config.read(config_file)
61
62     try:
63         home_dir = config.get('dirs', 'home')
64     except:
65         bug("Error setting home directory: home= under [dirs] not found.")
66         sys.exit(1)
67 else:
68     bug("Error setting home directory: /etc/hp/hplip.conf not found")
69     sys.exit(1)
70
71 if not home_dir or not os.path.exists(home_dir):
72     bug("Error setting home directory: Home directory %s not found." % home_dir)
73     sys.exit(1)
74
75 sys.path.insert(0, home_dir)
76 os.chdir(home_dir)
77
78 # HPLIP
79 try:
80     from base.g import *
81     from base.codes import *
82     from base import device
83     from base import utils
84     from prnt import cups
85 except ImportError, e:
86     bug("Error importing HPLIP modules: %s\n" % (pid, e))
87     sys.exit(1)
88
89 def handle_sigpipe():
90     syslog.syslog("SIGPIPE!")
91
92
93 USAGE = [(__doc__, "", "para", True),
94          ("Usage: hpfax [job_id] [username] [title] [copies] [options]", "", "summary", True),
95          utils.USAGE_OPTIONS,
96          utils.USAGE_LOGGING1, utils.USAGE_LOGGING2, utils.USAGE_LOGGING3,
97          utils.USAGE_HELP,
98         ]
99
100 def usage(typ='text'):
101     if typ == 'text':
102         utils.log_title(__title__, __version__)
103
104     utils.format_text(USAGE, typ, title=__title__, crumb='hpfax:')
105     sys.exit(CUPS_BACKEND_OK)
106
107 # Send dbus event to hpssd on dbus system bus
108 def send_message(device_uri, printer_name, event_code, username, job_id, title, pipe_name=''):
109     args = [device_uri, printer_name, event_code, username, job_id, title, pipe_name]
110     msg = lowlevel.SignalMessage('/', 'com.hplip.StatusService', 'Event')
111     msg.append(signature='ssisiss', *args)
112
113     SystemBus().send_message(msg)
114
115
116 try:
117     opts, args = getopt.getopt(sys.argv[1:], 'l:hg', ['level=', 'help', 'help-rest', 'help-man'])
118
119 except getopt.GetoptError:
120     usage()
121
122 for o, a in opts:
123
124     if o in ('-l', '--logging'):
125         log_level = a.lower().strip()
126         log.set_level(log_level)
127
128     elif o == '-g':
129         log.set_level('debug')
130
131     elif o in ('-h', '--help'):
132         usage()
133
134     elif o == '--help-rest':
135         usage('rest')
136
137     elif o == '--help-man':
138         usage('man')
139
140
141 if len( args ) == 0:
142     cups11 = utils.to_bool(sys_conf.get('configure', 'cups11', '0'))
143
144     try:
145         probed_devices = device.probeDevices(['usb', 'par'], filter={'fax-type': (operator.gt, 0)})
146     except Error:
147         sys.exit(CUPS_BACKEND_FAILED)
148
149     good_devices = 0
150     for uri in probed_devices:
151         try:
152             back_end, is_hp, bus, model, serial, dev_file, host, zc, port = \
153                 device.parseDeviceURI(uri)
154         except Error:
155             continue
156
157         mq = device.queryModelByModel(model)
158
159         if mq.get('fax-type', FAX_TYPE_NONE) in (FAX_TYPE_MARVELL,):
160             # HP Fax 3
161             if bus == 'usb':
162                 print 'direct %s "HP Fax 3" "%s USB %s HP Fax HPLIP" "MFG:HP;MDL:Fax 3;DES:HP Fax 3;"' % \
163                     (uri.replace("hp:", "hpfax:"), model.replace('_', ' '), serial)
164
165             else: # par
166                 print 'direct %s "HP Fax 3" "%s LPT HP Fax HPLIP" "MFG:HP;MDL:Fax 3;DES:HP Fax 3;"' % \
167                     (uri.replace("hp:", "hpfax:"), model.replace('_', ' '))
168
169         elif mq.get('fax-type', FAX_TYPE_NONE) in (FAX_TYPE_SOAP,) or mq.get('fax-type', FAX_TYPE_NONE) in (FAX_TYPE_LEDMSOAP,):
170             # HP Fax 2
171             if bus == 'usb':
172                 print 'direct %s "HP Fax 2" "%s USB %s HP Fax HPLIP" "MFG:HP;MDL:Fax 2;DES:HP Fax 2;"' % \
173                     (uri.replace("hp:", "hpfax:"), model.replace('_', ' '), serial)
174
175             else: # par
176                 print 'direct %s "HP Fax 2" "%s LPT HP Fax HPLIP" "MFG:HP;MDL:Fax 2;DES:HP Fax 2;"' % \
177                     (uri.replace("hp:", "hpfax:"), model.replace('_', ' '))
178         elif mq.get('fax-type', FAX_TYPE_NONE) in (FAX_TYPE_LEDM,):
179             # HP Fax 4
180             if bus == 'usb':
181                 print 'direct %s "HP Fax 4" "%s USB %s HP Fax HPLIP" "MFG:HP;MDL:Fax 4;DES:HP Fax 4;"' % \
182                     (uri.replace("hp:", "hpfax:"), model.replace('_', ' '), serial)
183
184             else: # par
185                 print 'direct %s "HP Fax 4" "%s LPT HP Fax HPLIP" "MFG:HP;MDL:Fax 4;DES:HP Fax 4;"' % \
186                     (uri.replace("hp:", "hpfax:"), model.replace('_', ' '))
187
188         else:
189             # HP Fax
190             if bus == 'usb':
191                 print 'direct %s "HP Fax" "%s USB %s HP Fax HPLIP" "MFG:HP;MDL:Fax;DES:HP Fax;"' % \
192                     (uri.replace("hp:", "hpfax:"),  model.replace('_', ' '), serial)
193
194             else: # par
195                 print 'direct %s "HP Fax" "%s LPT HP Fax HPLIP" "MFG:HP;MDL:Fax;DES:HP Fax;"' % \
196                     (uri.replace("hp:", "hpfax:"),  model.replace('_', ' '))
197
198         good_devices += 1
199
200     if good_devices == 0:
201         if cups11:
202             print 'direct hpfax:/no_device_found "HP Fax" "no_device_found" ""'
203         else:
204             print 'direct hpfax "Unknown" "HP Fax (HPLIP)" ""'
205
206     sys.exit(CUPS_BACKEND_OK)
207
208 else:
209     try:
210         # dBus
211         import dbus
212         from dbus import SystemBus, lowlevel
213     except ImportError:
214         bug("HPLIP pc send fax requires dbus and python-dbus")
215         sys.exit(CUPS_BACKEND_FAILED)
216
217     import warnings
218     # Ignore: .../dbus/connection.py:242: DeprecationWarning: object.__init__() takes no parameters
219     # (occurring on Python 2.6/dBus 0.83/Ubuntu 9.04)
220     warnings.simplefilter("ignore", DeprecationWarning)
221
222     # CUPS provided environment
223     try:
224         device_uri = os.environ['DEVICE_URI']
225         printer_name = os.environ['PRINTER']
226     except KeyError:
227         bug("Improper environment: Must be run by CUPS.")
228         sys.exit(CUPS_BACKEND_FAILED)
229
230     log.debug(args)
231
232     try:
233         job_id, username, title, copies, options = args[0:5]
234         job_id = int(job_id)
235     except IndexError:
236         bug("Invalid command line: invalid arguments.")
237         sys.exit(CUPS_BACKEND_FAILED)
238
239     send_message(device_uri, printer_name, EVENT_START_FAX_PRINT_JOB, username, job_id, title)
240
241     try:
242         input_fd = file(args[5], 'r')
243     except IndexError:
244         input_fd = 0
245
246     # REVISIT:
247     tmp_dir = '/tmp'
248     pipe_name = os.path.join(tmp_dir, "hpfax-pipe-%d" % job_id)
249
250     # Create the named pipe. Make sure it exists before sending
251     # message to hppsd.
252     os.umask(0111)
253     try:
254         os.mkfifo(pipe_name)
255     except OSError:
256         os.unlink(pipe_name)
257         os.mkfifo(pipe_name)
258
259     # Send dbus event to hpssd
260     send_message(device_uri, printer_name, EVENT_FAX_RENDER_COMPLETE, username, job_id, title, pipe_name)
261
262     # REVISIT:
263     pipe = os.open(pipe_name, os.O_WRONLY)
264
265     bytes_read = 0
266     while True:
267         data = os.read(input_fd, PIPE_BUF)
268
269         if not data:
270             break
271
272         os.write(pipe, data)
273         #syslog.syslog("Writing %d to pipe..." % len(data))
274         bytes_read += len(data)
275
276     if not bytes_read:
277         bug("No data on input file descriptor.")
278         sys.exit(CUPS_BACKEND_FAILED)
279
280     os.close(input_fd)
281     os.close(pipe)
282     os.unlink(pipe_name)
283
284     send_message(device_uri, printer_name, EVENT_END_FAX_PRINT_JOB, username, job_id, title)
285
286     sys.exit(CUPS_BACKEND_OK)