Tizen 2.1 base
[platform/upstream/hplip.git] / fax / soapfax.py
1 # -*- coding: utf-8 -*-
2 #
3 # (c) Copyright 2003-2007 Hewlett-Packard Development Company, L.P.
4 #
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 2 of the License, or
8 # (at your option) any later version.
9 #
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
18 #
19 # Author: Don Welch
20 #
21
22 from __future__ import division
23
24 # Std Lib
25 import sys
26 import os
27 import time
28 import cStringIO
29 import urllib # TODO: Replace with urllib2 (urllib is deprecated in Python 3.0)
30 import re
31
32 # Local
33 from base.g import *
34 from base.codes import *
35 from base import device, utils, codes, dime
36 from fax import *
37
38 #import xml.parsers.expat as expat
39
40
41 # **************************************************************************** #
42
43 http_result_pat = re.compile("""HTTP/\d.\d\s(\d+)""", re.I)
44
45
46 TIME_FORMAT_AM_PM = 1
47 TIME_FORMAT_24HR = 2
48
49 DATE_FORMAT_MM_DD_YYYY = 1
50 DATE_FORMAT_DD_MM_YYYY = 2
51 DATE_FORMAT_YYYY_MM_DD = 3
52
53 AM = 1
54 PM = 0
55
56 HTTP_OK = 200
57 HTTP_ERROR = 500
58
59 PIXELS_PER_LINE = 2528
60
61
62 # **************************************************************************** #
63 class SOAPFaxDevice(FaxDevice):
64
65     def __init__(self, device_uri=None, printer_name=None,
66                  callback=None,
67                  fax_type=FAX_TYPE_NONE,
68                  disable_dbus=False):
69
70         FaxDevice.__init__(self, device_uri,
71                            printer_name,
72                            callback, fax_type,
73                            disable_dbus)
74
75         self.send_fax_thread = None
76         self.upload_log_thread = None
77
78         if self.bus == 'net':
79             self.http_host = self.host
80         else:
81             self.http_host = 'localhost'
82
83
84     def post(self, url, post):
85         s = []
86         for k, v in post.items():
87             s.append("%s=%s" % (k, urllib.quote(str(v))))
88
89         s = '&'.join(s)
90
91         log.debug(s)
92
93         data = """POST %s HTTP/1.1
94 Connection: Keep-alive
95 User-agent: hplip/2.0
96 Host: %s
97 Content-length: %d
98 Cache-control: No-cache
99
100 %s""" % (url, self.http_host, len(s), s)
101
102         log.log_data(data)
103         self.writeEWS(data)
104         ret = cStringIO.StringIO()
105
106         while self.readEWS(4096, ret, timeout=5):
107             pass
108
109         ret = ret.getvalue()
110
111         log.log_data(ret)
112
113         self.closeEWS()
114
115         match = http_result_pat.match(ret)
116
117         try:
118             code = int(match.group(1))
119         except (ValueError, TypeError):
120             code = HTTP_ERROR
121
122         return code == HTTP_OK
123
124
125     def setPhoneNum(self, num):
126         return self.post("/hp/device/set_config.html", {"FaxNumber": str(num)})
127
128
129     def getPhoneNum(self):
130         stream = cStringIO.StringIO()
131         self.getEWSUrl("/hp/device/settings_fax_setup_wizard.xml", stream)
132         fax_setup = utils.XMLToDictParser().parseXML(stream.getvalue())
133         return fax_setup['faxsetupwizard-faxvoicenumber-faxnumber']
134
135     phone_num = property(getPhoneNum, setPhoneNum)
136
137
138     def setStationName(self, name):
139         return self.post("/hp/device/set_config.html", {"FaxCompanyName": str(name)})
140
141
142     def getStationName(self):
143         stream = cStringIO.StringIO()
144         self.getEWSUrl("/hp/device/settings_fax_setup_wizard.xml", stream)
145         fax_setup = utils.XMLToDictParser().parseXML(stream.getvalue())
146         return fax_setup['faxsetupwizard-userinformation-faxcompanyname']
147
148     station_name = property(getStationName, setStationName)
149
150
151     def setDateAndTime(self):
152         stream = cStringIO.StringIO()
153         self.getEWSUrl("/hp/device/settings_fax_setup_wizard.xml", stream)
154         fax_setup = utils.XMLToDictParser().parseXML(stream.getvalue())
155         timeformat = fax_setup['faxsetupwizard-time-timeformat']
156
157         try:
158             timeformat = int(timeformat)
159         except (ValueError, TypeError):
160             timeformat = TIME_FORMAT_AM_PM
161
162         log.debug("timeformat: %d" % timeformat)
163
164         dateformat = fax_setup['faxsetupwizard-date-dateformat']
165
166         try:
167             dateformat = int(dateformat)
168         except (ValueError, TypeError):
169             dateformat = DATE_FORMAT_DD_MM_YYYY
170
171         log.debug("dateformat: %d" % dateformat)
172
173         t = time.localtime()
174         hr = t[3]
175
176         am_pm = PM
177         if t[3] < 12:
178             am_pm = AM
179
180         if timeformat == TIME_FORMAT_AM_PM and hr > 12:
181             hr -= 12
182
183         post = {"DateFormat" : dateformat,
184                 "Year" : t[0],
185                 "Month" : t[1],
186                 "Day" : t[2],
187                 "TimeFormat" : timeformat,
188                 "Hour" : hr,
189                 "Minute" : t[4]}
190
191         if timeformat == TIME_FORMAT_AM_PM:
192             post['AM'] = am_pm
193
194         return self.post("/hp/device/set_config.html", post)
195
196
197     def sendFaxes(self, phone_num_list, fax_file_list, cover_message='', cover_re='',
198                   cover_func=None, preserve_formatting=False, printer_name='',
199                   update_queue=None, event_queue=None):
200
201         if not self.isSendFaxActive():
202
203             self.send_fax_thread = SOAPFaxSendThread(self, self.service, phone_num_list, fax_file_list,
204                                                      cover_message, cover_re, cover_func,
205                                                      preserve_formatting,
206                                                      printer_name, update_queue,
207                                                      event_queue)
208
209             self.send_fax_thread.start()
210             return True
211         else:
212             return False
213
214
215 # **************************************************************************** #
216 class SOAPFaxSendThread(FaxSendThread):
217     def __init__(self, dev, service, phone_num_list, fax_file_list,
218                  cover_message='', cover_re='', cover_func=None, preserve_formatting=False,
219                  printer_name='', update_queue=None, event_queue=None):
220
221         FaxSendThread.__init__(self, dev, service, phone_num_list, fax_file_list,
222              cover_message, cover_re, cover_func, preserve_formatting,
223              printer_name, update_queue, event_queue)
224
225         self.job_id = utils.gen_random_uuid()
226         log.debug("JobId: %s" % self.job_id)
227
228         if dev.bus == 'net':
229             self.http_host = "%s:8295" % self.dev.host
230         else:
231             self.http_host = 'localhost:8295'
232
233         #self.http_host = 'localhost'
234
235
236     def run(self):
237         #results = {} # {'file' : error_code,...}
238
239         STATE_DONE = 0
240         STATE_ABORTED = 10
241         STATE_SUCCESS = 20
242         STATE_BUSY = 25
243         STATE_READ_SENDER_INFO = 30
244         STATE_PRERENDER = 40
245         STATE_COUNT_PAGES = 50
246         STATE_NEXT_RECIPIENT = 60
247         STATE_COVER_PAGE = 70
248         STATE_SINGLE_FILE = 80
249         STATE_MERGE_FILES = 90
250         STATE_SINGLE_FILE = 100
251         STATE_SEND_FAX = 110
252         STATE_CLEANUP = 120
253         STATE_ERROR = 130
254
255         next_recipient = self.next_recipient_gen()
256
257         state = STATE_READ_SENDER_INFO
258         self.rendered_file_list = []
259
260         while state != STATE_DONE: # --------------------------------- Fax state machine
261             if self.check_for_cancel():
262                 state = STATE_ABORTED
263
264             log.debug("STATE=(%d, 0, 0)" % state)
265
266             if state == STATE_ABORTED: # --------------------------------- Aborted (10, 0, 0)
267                 log.error("Aborted by user.")
268                 self.write_queue((STATUS_IDLE, 0, ''))
269                 state = STATE_CLEANUP
270
271
272             elif state == STATE_SUCCESS: # --------------------------------- Success (20, 0, 0)
273                 log.debug("Success.")
274                 self.write_queue((STATUS_COMPLETED, 0, ''))
275                 state = STATE_CLEANUP
276
277
278             elif state == STATE_ERROR: # --------------------------------- Error (130, 0, 0)
279                 log.error("Error, aborting.")
280                 self.write_queue((STATUS_ERROR, 0, ''))
281                 state = STATE_CLEANUP
282
283
284             elif state == STATE_BUSY: # --------------------------------- Busy (25, 0, 0)
285                 log.error("Device busy, aborting.")
286                 self.write_queue((STATUS_BUSY, 0, ''))
287                 state = STATE_CLEANUP
288
289
290             elif state == STATE_READ_SENDER_INFO: # --------------------------------- Get sender info (30, 0, 0)
291                 log.debug("%s State: Get sender info" % ("*"*20))
292                 state = STATE_PRERENDER
293                 try:
294                     try:
295                         self.dev.open()
296                     except Error, e:
297                         log.error("Unable to open device (%s)." % e.msg)
298                         state = STATE_ERROR
299                     else:
300                         try:
301                             self.sender_name = self.dev.station_name
302                             log.debug("Sender name=%s" % self.sender_name)
303                             self.sender_fax = self.dev.phone_num
304                             log.debug("Sender fax=%s" % self.sender_fax)
305                         except Error:
306                             log.error("HTTP GET failed!")
307                             state = STATE_ERROR
308
309                 finally:
310                     self.dev.close()
311
312
313             elif state == STATE_PRERENDER: # --------------------------------- Pre-render non-G4 files (40, 0, 0)
314                 log.debug("%s State: Pre-render non-G4 files" % ("*"*20))
315                 state = self.pre_render(STATE_COUNT_PAGES)
316
317             elif state == STATE_COUNT_PAGES: # --------------------------------- Get total page count (50, 0, 0)
318                 log.debug("%s State: Get total page count" % ("*"*20))
319                 state = self.count_pages(STATE_NEXT_RECIPIENT)
320
321             elif state == STATE_NEXT_RECIPIENT: # --------------------------------- Loop for multiple recipients (60, 0, 0)
322                 log.debug("%s State: Next recipient" % ("*"*20))
323                 state = STATE_COVER_PAGE
324
325                 try:
326                     recipient = next_recipient.next()
327                     log.debug("Processing for recipient %s" % recipient['name'])
328                     self.write_queue((STATUS_SENDING_TO_RECIPIENT, 0, recipient['name']))
329                 except StopIteration:
330                     state = STATE_SUCCESS
331                     log.debug("Last recipient.")
332                     continue
333
334                 recipient_file_list = self.rendered_file_list[:]
335
336
337             elif state == STATE_COVER_PAGE: # --------------------------------- Create cover page (70, 0, 0)
338                 log.debug("%s State: Render cover page" % ("*"*20))
339                 state = self.cover_page(recipient)
340
341
342             elif state == STATE_SINGLE_FILE: # --------------------------------- Special case for single file (no merge) (80, 0, 0)
343                 log.debug("%s State: Handle single file" % ("*"*20))
344                 state = self.single_file(STATE_SEND_FAX)
345
346             elif state == STATE_MERGE_FILES: # --------------------------------- Merge multiple G4 files (90, 0, 0)
347                 log.debug("%s State: Merge multiple files" % ("*"*20))
348                 state = self.merge_files(STATE_SEND_FAX)
349
350             elif state == STATE_SEND_FAX: # --------------------------------- Send fax state machine (110, 0, 0)
351                 log.debug("%s State: Send fax" % ("*"*20))
352                 state = STATE_NEXT_RECIPIENT
353
354                 FAX_SEND_STATE_DONE = 0
355                 FAX_SEND_STATE_ABORT = 10
356                 FAX_SEND_STATE_ERROR = 20
357                 FAX_SEND_STATE_BUSY = 25
358                 FAX_SEND_STATE_SUCCESS = 30
359                 FAX_SEND_STATE_DEVICE_OPEN = 40
360                 FAX_SEND_STATE_BEGINJOB = 50
361                 FAX_SEND_STATE_DOWNLOADPAGES = 60
362                 FAX_SEND_STATE_ENDJOB = 70
363                 FAX_SEND_STATE_CANCELJOB = 80
364                 FAX_SEND_STATE_CLOSE_SESSION = 170
365
366                 monitor_state = False
367                 fax_send_state = FAX_SEND_STATE_DEVICE_OPEN
368
369                 while fax_send_state != FAX_SEND_STATE_DONE:
370
371                     if self.check_for_cancel():
372                         log.error("Fax send aborted.")
373                         fax_send_state = FAX_SEND_STATE_ABORT
374
375                     if monitor_state:
376                         fax_state = self.getFaxDownloadState()
377                         if not fax_state in (pml.UPDN_STATE_XFERACTIVE, pml.UPDN_STATE_XFERDONE):
378                             log.error("D/L error state=%d" % fax_state)
379                             fax_send_state = FAX_SEND_STATE_ERROR
380                             state = STATE_ERROR
381
382                     log.debug("STATE=(%d, %d, 0)" % (STATE_SEND_FAX, fax_send_state))
383
384                     if fax_send_state == FAX_SEND_STATE_ABORT: # -------------- Abort (110, 10, 0)
385                         monitor_state = False
386                         fax_send_state = FAX_SEND_STATE_CANCELJOB
387                         state = STATE_ABORTED
388
389                     elif fax_send_state == FAX_SEND_STATE_ERROR: # -------------- Error (110, 20, 0)
390                         log.error("Fax send error.")
391                         monitor_state = False
392                         fax_send_state = FAX_SEND_STATE_CLOSE_SESSION
393                         state = STATE_ERROR
394
395                     elif fax_send_state == FAX_SEND_STATE_BUSY: # -------------- Busy (110, 25, 0)
396                         log.error("Fax device busy.")
397                         monitor_state = False
398                         fax_send_state = FAX_SEND_STATE_CLOSE_SESSION
399                         state = STATE_BUSY
400
401                     elif fax_send_state == FAX_SEND_STATE_SUCCESS: # -------------- Success (110, 30, 0)
402                         log.debug("Fax send success.")
403                         monitor_state = False
404                         fax_send_state = FAX_SEND_STATE_CLOSE_SESSION
405                         state = STATE_NEXT_RECIPIENT
406
407                     elif fax_send_state == FAX_SEND_STATE_DEVICE_OPEN: # -------------- Device open (110, 40, 0)
408                         log.debug("%s State: Open device" % ("*"*20))
409                         fax_send_state = FAX_SEND_STATE_BEGINJOB
410                         try:
411                             self.dev.open()
412                         except Error, e:
413                             log.error("Unable to open device (%s)." % e.msg)
414                             fax_send_state = FAX_SEND_STATE_ERROR
415                         else:
416                             if self.dev.device_state == DEVICE_STATE_NOT_FOUND:
417                                 fax_send_state = FAX_SEND_STATE_ERROR
418
419                     elif fax_send_state == FAX_SEND_STATE_BEGINJOB: # -------------- BeginJob (110, 50, 0)
420                         log.debug("%s State: BeginJob" % ("*"*20))
421
422                         try:
423                             ff = file(self.f, 'r')
424                         except IOError:
425                             log.error("Unable to read fax file.")
426                             fax_send_state = FAX_SEND_STATE_ERROR
427                             continue
428
429                         try:
430                             header = ff.read(FILE_HEADER_SIZE)
431                         except IOError:
432                             log.error("Unable to read fax file.")
433                             fax_send_state = FAX_SEND_STATE_ERROR
434                             continue
435
436                         magic, version, total_pages, hort_dpi, vert_dpi, page_size, \
437                             resolution, encoding, reserved1, reserved2 = self.decode_fax_header(header)
438
439                         if magic != 'hplip_g3':
440                             log.error("Invalid file header. Bad magic.")
441                             fax_send_state = FAX_SEND_STATE_ERROR
442                         else:
443                             log.debug("Magic=%s Ver=%d Pages=%d hDPI=%d vDPI=%d Size=%d Res=%d Enc=%d" %
444                                       (magic, version, total_pages, hort_dpi, vert_dpi, page_size,
445                                        resolution, encoding))
446
447                         job_id = self.job_id
448                         delay = 0
449                         faxnum = recipient['fax'].encode('ascii')
450                         speeddial = 0
451
452                         if resolution == RESOLUTION_STD:
453                             res = "STANDARD"
454                         elif resolution == RESOLUTION_FINE:
455                             res = "FINE"
456                         elif resolution == RESOLUTION_300DPI:
457                             res = "SUPERFINE"
458
459                         soap = utils.cat(
460 """<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Body><Fax:BeginJob xmlns:Fax="urn:Fax"><ticket xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Fax:Ticket"><jobId xmlns:xsd="http://www.w3.org/2001/XMLSchema" xsi:type="xsd:string">$job_id</jobId><resolution xsi:type="Fax:Resolution">$res</resolution><delay xmlns:xsd="http://www.w3.org/2001/XMLSchema" xsi:type="xsd:positiveInteger">$delay</delay><phoneNumber xmlns:xsd="http://www.w3.org/2001/XMLSchema" xsi:type="xsd:string">$faxnum</phoneNumber><speedDial xmlns:xsd="http://www.w3.org/2001/XMLSchema" xsi:type="xsd:positiveInteger">$speeddial</speedDial></ticket></Fax:BeginJob></SOAP-ENV:Body></SOAP-ENV:Envelope>""")
461
462                         data = self.format_http(soap)
463                         log.log_data(data)
464
465                         if log.is_debug():
466                             file('beginjob.log', 'w').write(data)
467
468                         self.dev.openSoapFax()
469                         self.dev.writeSoapFax(data)
470                         ret = cStringIO.StringIO()
471
472                         while self.dev.readSoapFax(8192, ret, timeout=5):
473                             pass
474
475                         ret = ret.getvalue()
476
477                         if log.is_debug():
478                             file('beginjob_ret.log', 'w').write(ret)
479
480                         log.log_data(ret)
481                         self.dev.closeSoapFax()
482
483                         if self.get_error_code(ret) == HTTP_OK:
484                             fax_send_state = FAX_SEND_STATE_DOWNLOADPAGES
485                         else:
486                             fax_send_state = FAX_SEND_STATE_ERROR
487
488
489                     elif fax_send_state == FAX_SEND_STATE_DOWNLOADPAGES: # -------------- DownloadPages (110, 60, 0)
490                         log.debug("%s State: DownloadPages" % ("*"*20))
491                         page = StringIO()
492                         for p in range(total_pages):
493
494                             if self.check_for_cancel():
495                                 fax_send_state = FAX_SEND_STATE_ABORT
496
497                             if fax_send_state == FAX_SEND_STATE_ABORT:
498                                 break
499
500                             try:
501                                 header = ff.read(PAGE_HEADER_SIZE)
502                             except IOError:
503                                 log.error("Unable to read fax file.")
504                                 fax_send_state = FAX_SEND_STATE_ERROR
505                                 continue
506
507                             page_num, ppr, rpp, bytes_to_read, thumbnail_bytes, reserved2 = \
508                                 self.decode_page_header(header)
509
510                             log.debug("Page=%d PPR=%d RPP=%d BPP=%d Thumb=%d" %
511                                       (page_num, ppr, rpp, bytes_to_read, thumbnail_bytes))
512
513                             if ppr != PIXELS_PER_LINE:
514                                 log.error("Pixels per line (width) must be %d!" % PIXELS_PER_LINE)
515
516                             page.write(ff.read(bytes_to_read))
517                             thumbnail = ff.read(thumbnail_bytes) # thrown away for now (should be 0 read)
518                             page.seek(0)
519
520                             try:
521                                 data = page.read(bytes_to_read)
522                             except IOError:
523                                 log.error("Unable to read fax file.")
524                                 fax_send_state = FAX_SEND_STATE_ERROR
525                                 break
526
527                             if data == '':
528                                 log.error("No data!")
529                                 fax_send_state = FAX_SEND_STATE_ERROR
530                                 break
531
532                             height = rpp
533                             job_id = self.job_id
534
535                             soap = utils.cat(
536 """<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Header><jobId xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xsd:string" SOAP-ENV:mustUnderstand="1">$job_id</jobId></SOAP-ENV:Header><SOAP-ENV:Body><Fax:DownloadPage xmlns:Fax="urn:Fax"><height xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xsd:positiveInteger">$height</height></Fax:DownloadPage></SOAP-ENV:Body></SOAP-ENV:Envelope>""")
537
538                             m = dime.Message()
539                             m.add_record(dime.Record("cid:id0", "http://schemas.xmlsoap.org/soap/envelope/",
540                                 dime.TYPE_T_URI, soap))
541
542                             m.add_record(dime.Record("", "image/g4fax", dime.TYPE_T_MIME, data))
543
544                             output = cStringIO.StringIO()
545                             m.generate(output)
546                             data = self.format_http(output.getvalue(), content_type="application/dime")
547                             log.log_data(data)
548                             if log.is_debug():
549                                 file('downloadpages%d.log' % p, 'w').write(data)
550
551                             try:
552                                 self.dev.writeSoapFax(data)
553                             except Error:
554                                 fax_send_state = FAX_SEND_STATE_ERROR
555
556                             ret = cStringIO.StringIO()
557
558                             try:
559                                 while self.dev.readSoapFax(8192, ret, timeout=5):
560                                     pass
561                             except Error:
562                                 fax_send_state = FAX_SEND_STATE_ERROR
563
564                             ret = ret.getvalue()
565
566                             if log.is_debug():
567                                 file('downloadpages%d_ret.log' % p, 'w').write(ret)
568
569                             log.log_data(ret)
570                             self.dev.closeSoapFax()
571
572                             if self.get_error_code(ret) != HTTP_OK:
573                                 fax_send_state = FAX_SEND_STATE_ERROR
574                                 break
575
576                             page.truncate(0)
577                             page.seek(0)
578
579                         else:
580                             fax_send_state = FAX_SEND_STATE_ENDJOB
581
582
583                     elif fax_send_state == FAX_SEND_STATE_ENDJOB: # -------------- EndJob (110, 70, 0)
584                         log.debug("%s State: EndJob" % ("*"*20))
585
586                         job_id = self.job_id
587
588                         soap = utils.cat(
589 """<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Header><jobId xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xsd:string" SOAP-ENV:mustUnderstand="1">$job_id</jobId></SOAP-ENV:Header><SOAP-ENV:Body><Fax:EndJob xmlns:Fax="urn:Fax"><jobId xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xsd:string">$job_id</jobId></Fax:EndJob></SOAP-ENV:Body></SOAP-ENV:Envelope>""")
590
591                         data = self.format_http(soap)
592
593                         log.log_data(data)
594
595                         if log.is_debug():
596                             file('endjob.log', 'w').write(data)
597
598                         self.dev.writeSoapFax(data)
599                         ret = cStringIO.StringIO()
600
601                         while self.dev.readSoapFax(8192, ret, timeout=5):
602                             pass
603
604                         ret = ret.getvalue()
605
606                         if log.is_debug():
607                             file('endjob_ret.log', 'w').write(ret)
608
609                         log.log_data(ret)
610                         self.dev.closeSoapFax()
611
612                         if self.get_error_code(ret) == HTTP_OK:
613                             fax_send_state = FAX_SEND_STATE_SUCCESS
614                         else:
615                             fax_send_state = FAX_SEND_STATE_ERROR
616
617                     elif fax_send_state == FAX_SEND_STATE_CANCELJOB: # -------------- CancelJob (110, 80, 0)
618                         log.debug("%s State: CancelJob" % ("*"*20))
619
620                         job_id = self.job_id
621
622                         soap = utils.cat(
623 """<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Header><jobId xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xsd:string" SOAP-ENV:mustUnderstand="1">$job_id</jobId></SOAP-ENV:Header><SOAP-ENV:Body><Fax:CancelJob xmlns:Fax="urn:Fax"><jobId xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xsd:string">$job_id</jobId></Fax:CancelJob></SOAP-ENV:Body></SOAP-ENV:Envelope>""")
624
625                         data = self.format_http(soap)
626
627                         log.log_data(data)
628
629                         if log.is_debug():
630                             file('canceljob.log', 'w').write(data)
631
632                         self.dev.writeSoapFax(data)
633                         ret = cStringIO.StringIO()
634
635                         while self.dev.readSoapFax(8192, ret, timeout=5):
636                             pass
637
638                         ret = ret.getvalue()
639
640                         if log.is_debug():
641                             file('canceljob_ret.log', 'w').write(ret)
642
643                         log.log_data(ret)
644                         self.dev.closeSoapFax()
645
646                         if self.get_error_code(ret) == HTTP_OK:
647                             fax_send_state = FAX_SEND_STATE_CLOSE_SESSION
648                         else:
649                             fax_send_state = FAX_SEND_STATE_ERROR
650
651
652                     elif fax_send_state == FAX_SEND_STATE_CLOSE_SESSION: # -------------- Close session (110, 170, 0)
653                         log.debug("%s State: Close session" % ("*"*20))
654                         log.debug("Closing session...")
655
656                         try:
657                             mm.close()
658                         except NameError:
659                             pass
660
661                         try:
662                             ff.close()
663                         except NameError:
664                             pass
665
666                         time.sleep(1)
667
668                         self.dev.closeSoapFax()
669                         self.dev.close()
670
671                         fax_send_state = FAX_SEND_STATE_DONE # Exit inner state machine
672
673
674             elif state == STATE_CLEANUP: # --------------------------------- Cleanup (120, 0, 0)
675                 log.debug("%s State: Cleanup" % ("*"*20))
676
677                 if self.remove_temp_file:
678                     log.debug("Removing merged file: %s" % self.f)
679                     try:
680                         os.remove(self.f)
681                         log.debug("Removed")
682                     except OSError:
683                         log.debug("Not found")
684
685                 state = STATE_DONE # Exit outer state machine
686
687
688     def get_error_code(self, ret):
689         if not ret: return HTTP_ERROR
690
691         match = http_result_pat.match(ret)
692
693         if match is None: return HTTP_OK
694         try:
695             code = int(match.group(1))
696         except (ValueError, TypeError):
697             code = HTTP_ERROR
698
699         return code
700
701
702     def format_http(self, soap, content_type="text/xml; charset=utf-8"):
703         host = self.http_host
704         soap_len = len(soap)
705
706         return utils.cat(
707 """POST / HTTP/1.1\r
708 Host: $host\r
709 User-Agent: hplip/2.0\r
710 Content-Type: $content_type\r
711 Content-Length: $soap_len\r
712 Connection: close\r
713 SOAPAction: ""\r
714 \r
715 $soap""")
716
717
718
719