home *** CD-ROM | disk | FTP | other *** search
/ PC Welt 2006 November (DVD) / PCWELT_11_2006.ISO / casper / filesystem.squashfs / usr / lib / hplip / hpssd.py < prev    next >
Encoding:
Python Source  |  2006-08-30  |  46.4 KB  |  1,456 lines

  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. #
  4. # (c) Copyright 2003-2006 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. # Authors: Don Welch, Pete Parks
  21. #
  22. # Thanks to Henrique M. Holschuh <hmh@debian.org> for various security patches
  23. #
  24. # ======================================================================
  25. # Async code is Copyright 1996 by Sam Rushing
  26. #
  27. #                         All Rights Reserved
  28. #
  29. # Permission to use, copy, modify, and distribute this software and
  30. # its documentation for any purpose and without fee is hereby
  31. # granted, provided that the above copyright notice appear in all
  32. # copies and that both that copyright notice and this permission
  33. # notice appear in supporting documentation, and that the name of Sam
  34. # Rushing not be used in advertising or publicity pertaining to
  35. # distribution of the software without specific, written prior
  36. # permission.
  37. #
  38. # SAM RUSHING DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
  39. # INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
  40. # NO EVENT SHALL SAM RUSHING BE LIABLE FOR ANY SPECIAL, INDIRECT OR
  41. # CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
  42. # OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
  43. # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  44. # CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  45. # ======================================================================
  46. #
  47.  
  48.  
  49. __version__ = '7.5'
  50. __title__ = "Services and Status Daemon"
  51. __doc__ = "Provides various services to HPLIP client applications. Maintains persistant device status."
  52.  
  53.  
  54. # Std Lib
  55. import sys, socket, os, os.path, signal, getopt, glob, time, select
  56. import popen2, threading, gettext, re, xml.parsers.expat, fcntl
  57. import cStringIO, pwd
  58.  
  59. from errno import EALREADY, EINPROGRESS, EWOULDBLOCK, ECONNRESET, \
  60.      ENOTCONN, ESHUTDOWN, EINTR, EISCONN
  61.  
  62. # Local
  63. from base.g import *
  64. from base.codes import *
  65. from base.msg import *
  66. from base import utils, slp, device
  67. from base.strings import string_table
  68.  
  69. # CUPS support
  70. from prnt import cups
  71.  
  72. # Per user alert settings
  73. alerts = {}
  74.  
  75. # Fax temp files
  76. fax_file = {}
  77.  
  78.  
  79. class ServerDevice(object):
  80.     def __init__(self, model=''):
  81.         self.history = utils.RingBuffer(prop.history_size)
  82.         self.model = device.normalizeModelName(model)
  83.         self.cache = {}
  84.        
  85.  
  86. # Active devices - to hold event history
  87. devices = {} # { 'device_uri' : ServerDevice, ... }
  88.  
  89. # Cache for model query data
  90. model_cache = {} # { 'model_name'(lower) : {mq}, ...}
  91.  
  92. inter_pat = re.compile(r"""%(.*)%""", re.IGNORECASE)
  93.  
  94. def QueryString(id, typ=0):
  95.     id = str(id)
  96.     try:
  97.         s = string_table[id][typ]
  98.     except KeyError:
  99.         log.debug("String %s not found" % id)
  100.         raise Error(ERROR_STRING_QUERY_FAILED)
  101.  
  102.     if type(s) == type(''):
  103.         return s
  104.  
  105.     try:
  106.         return s()
  107.     except:
  108.         raise Error(ERROR_STRING_QUERY_FAILED)
  109.  
  110.  
  111.  
  112. def initStrings():
  113.     cycles = 0
  114.  
  115.     while True:
  116.  
  117.         found = False
  118.  
  119.         for s in string_table:
  120.             short_string, long_string = string_table[s]
  121.             short_replace, long_replace = short_string, long_string
  122.  
  123.             try:
  124.                 short_match = inter_pat.match(short_string).group(1)
  125.             except (AttributeError, TypeError):
  126.                 short_match = None
  127.  
  128.             if short_match is not None:
  129.                 found = True
  130.  
  131.                 try:
  132.                     short_replace, dummy = string_table[short_match]
  133.                 except KeyError:
  134.                     log.error("String interpolation error: %s" % short_match)
  135.  
  136.             try:
  137.                 long_match = inter_pat.match(long_string).group(1)
  138.             except (AttributeError, TypeError):
  139.                 long_match = None
  140.  
  141.             if long_match is not None:
  142.                 found = True
  143.  
  144.                 try:
  145.                     dummy, long_replace = string_table[long_match]
  146.                 except KeyError:
  147.                     log.error("String interpolation error: %s" % long_match)
  148.  
  149.             if found:
  150.                 string_table[s] = (short_replace, long_replace)
  151.  
  152.         if not found:
  153.             break
  154.         else:
  155.             cycles +=1
  156.             if cycles > 1000:
  157.                 break
  158.                 
  159.  
  160. class ModelParser:
  161.     def __init__(self):
  162.         self.model = {}
  163.         self.cur_model = None
  164.         self.stack = []
  165.         self.model_found = False
  166.  
  167.     def startElement(self, name, attrs):
  168.         global models
  169.  
  170.         if name in ('id', 'models'):
  171.             return
  172.  
  173.         elif name == 'model':
  174.             #self.model = {}
  175.             self.cur_model = str(attrs['name']).lower()
  176.             if self.cur_model == self.model_name:
  177.                 #log.debug( "Model found." )
  178.                 self.model_found = True
  179.                 self.stack = []
  180.             else:
  181.                 self.cur_model = None
  182.  
  183.         elif self.cur_model is not None:
  184.             self.stack.append(str(name).lower())
  185.  
  186.             if len(attrs):
  187.                 for a in attrs:
  188.                     self.stack.append(str(a).lower())
  189.  
  190.                     try:
  191.                         i = int(attrs[a])
  192.                     except ValueError:
  193.                         i = str(attrs[a])
  194.  
  195.                     self.model[str('-'.join(self.stack))] = i
  196.                     self.stack.pop()
  197.  
  198.     def endElement(self, name):
  199.         global models
  200.         if name == 'model':
  201.             pass
  202.         elif name in ('id', 'models'):
  203.             return
  204.         else:
  205.             if self.cur_model is not None:
  206.                 self.stack.pop()
  207.  
  208.  
  209.     def charData(self, data):
  210.         data = str(data).strip()
  211.  
  212.         if data and self.model is not None and \
  213.             self.cur_model is not None and \
  214.             self.stack:
  215.  
  216.             try:
  217.                 i = int(data)
  218.             except ValueError:
  219.                 i = str(data)
  220.  
  221.             self.model[str('-'.join(self.stack))] = i
  222.  
  223.     def parseModels(self, model_name):
  224.         self.model_name = model_name
  225.  
  226.         for g in [prop.xml_dir, os.path.join(prop.xml_dir, 'unreleased')]:
  227.  
  228.             if os.path.exists(g):
  229.                 log.debug("Searching directory: %s" % g)
  230.  
  231.                 for f in glob.glob(g + "/*.xml"):
  232.                     log.debug("Searching file: %s" % f)
  233.                     parser = xml.parsers.expat.ParserCreate()
  234.                     parser.StartElementHandler = self.startElement
  235.                     parser.EndElementHandler = self.endElement
  236.                     parser.CharacterDataHandler = self.charData
  237.                     parser.Parse(open(f).read(), True)
  238.  
  239.                     if self.model_found:
  240.                         log.debug("Found")
  241.                         return self.model
  242.  
  243.         log.error("Not found")
  244.         raise Error(ERROR_UNSUPPORTED_MODEL)
  245.  
  246.  
  247.  
  248. def QueryModel(model_name):
  249.     model_name = device.normalizeModelName(model_name).lower()
  250.     log.debug("Query model: %s" % model_name)
  251.  
  252.     if model_name in model_cache and \
  253.         model_cache[model_name]:
  254.             log.debug("Found")
  255.             return model_cache[model_name]
  256.  
  257.     mq = ModelParser().parseModels(model_name)
  258.     
  259.     if mq:
  260.         model_cache[model_name] = mq
  261.     
  262.     return mq or {}
  263.     
  264.  
  265. socket_map = {}
  266. loopback_trigger = None
  267.  
  268. def loop( timeout=1.0, sleep_time=0.1 ):
  269.     while socket_map:
  270.         r = []; w = []; e = []
  271.         for fd, obj in socket_map.items():
  272.             if obj.readable():
  273.                 r.append( fd )
  274.             if obj.writable():
  275.                 w.append( fd )
  276.         if [] == r == w == e:
  277.             time.sleep( timeout )
  278.         else:
  279.             try:
  280.                 r,w,e = select.select( r, w, e, timeout )
  281.             except select.error, err:
  282.                 if err[0] != EINTR:
  283.                     raise Error( ERROR_INTERNAL )
  284.                 r = []; w = []; e = []
  285.  
  286.         for fd in r:
  287.             try:
  288.                 obj = socket_map[ fd ]
  289.             except KeyError:
  290.                 continue
  291.  
  292.             try:
  293.                 obj.handle_read_event()
  294.             except Error, e:
  295.                 obj.handle_error( e )
  296.  
  297.         for fd in w:
  298.             try:
  299.                 obj = socket_map[ fd ]
  300.             except KeyError:
  301.                 continue
  302.  
  303.             try:
  304.                 obj.handle_write_event()
  305.             except Error, e:
  306.                 obj.handle_error( e )
  307.  
  308.             time.sleep( sleep_time )
  309.  
  310.  
  311. class dispatcher:
  312.     connected = False
  313.     accepting = False
  314.     closing = False
  315.     addr = None
  316.  
  317.     def __init__ (self, sock=None ):
  318.         self.typ = ''
  319.         self.send_events = False
  320.         self.username = ''
  321.         
  322.         if sock:
  323.             self.set_socket( sock ) 
  324.             self.socket.setblocking( 0 )
  325.             self.connected = True
  326.             try:
  327.                 self.addr = sock.getpeername()
  328.             except socket.error:
  329.                 # The addr isn't crucial
  330.                 pass
  331.         else:
  332.             self.socket = None
  333.  
  334.     def add_channel ( self ): 
  335.         global socket_map
  336.         socket_map[ self._fileno ] = self
  337.  
  338.     def del_channel( self ): 
  339.         global socket_map
  340.         fd = self._fileno
  341.         if socket_map.has_key( fd ):
  342.             del socket_map[ fd ]
  343.  
  344.     def create_socket( self, family, type ):
  345.         self.family_and_type = family, type
  346.         self.socket = socket.socket (family, type)
  347.         self.socket.setblocking( 0 )
  348.         self._fileno = self.socket.fileno()
  349.         self.add_channel()
  350.  
  351.     def set_socket( self, sock ): 
  352.         self.socket = sock
  353.         self._fileno = sock.fileno()
  354.         self.add_channel()
  355.  
  356.     def set_reuse_addr( self ):
  357.         try:
  358.             self.socket.setsockopt (
  359.                 socket.SOL_SOCKET, socket.SO_REUSEADDR,
  360.                 self.socket.getsockopt (socket.SOL_SOCKET,
  361.                                         socket.SO_REUSEADDR) | 1
  362.                 )
  363.         except socket.error:
  364.             pass
  365.  
  366.     def readable (self):
  367.         return True
  368.  
  369.     def writable (self):
  370.         return True
  371.  
  372.     def listen (self, num):
  373.         self.accepting = True
  374.         return self.socket.listen( num )
  375.  
  376.     def bind( self, addr ):
  377.         self.addr = addr
  378.         return self.socket.bind( addr )
  379.  
  380.     def connect( self, address ):
  381.         self.connected = False
  382.         err = self.socket.connect_ex( address )
  383.         if err in ( EINPROGRESS, EALREADY, EWOULDBLOCK ):
  384.             return
  385.         if err in (0, EISCONN):
  386.             self.addr = address
  387.             self.connected = True
  388.             self.handle_connect()
  389.         else:
  390.             raise socket.error, err
  391.  
  392.     def accept (self):
  393.         try:
  394.             conn, addr = self.socket.accept()
  395.             return conn, addr
  396.         except socket.error, why:
  397.             if why[0] == EWOULDBLOCK:
  398.                 pass
  399.             else:
  400.                 raise socket.error, why
  401.  
  402.     def send (self, data):
  403.         try:
  404.             result = self.socket.send( data )
  405.             return result
  406.         except socket.error, why:
  407.             if why[0] == EWOULDBLOCK:
  408.                 return 0
  409.             else:
  410.                 raise socket.error, why
  411.             return 0
  412.  
  413.     def recv( self, buffer_size ):
  414.         try:
  415.             data = self.socket.recv (buffer_size)
  416.             if not data:
  417.                 self.handle_close()
  418.                 return ''
  419.             else:
  420.                 return data
  421.         except socket.error, why:
  422.             if why[0] in [ECONNRESET, ENOTCONN, ESHUTDOWN]:
  423.                 self.handle_close()
  424.                 return ''
  425.             else:
  426.                 raise socket.error, why
  427.  
  428.     def close (self):
  429.         self.del_channel()
  430.         self.socket.close()
  431.  
  432.     # cheap inheritance, used to pass all other attribute
  433.     # references to the underlying socket object.
  434.     #def __getattr__ (self, attr):
  435.     #    return getattr (self.socket, attr)
  436.  
  437.     def handle_read_event( self ):
  438.         if self.accepting:
  439.             if not self.connected:
  440.                 self.connected = True
  441.             self.handle_accept()
  442.         elif not self.connected:
  443.             self.handle_connect()
  444.             self.connected = True
  445.             self.handle_read()
  446.         else:
  447.             self.handle_read()
  448.  
  449.     def handle_write_event( self ):
  450.         if not self.connected:
  451.             self.handle_connect()
  452.             self.connected = True
  453.         self.handle_write()
  454.  
  455.     def handle_expt_event( self ):
  456.         self.handle_expt()
  457.  
  458.     def handle_error( self, e ):
  459.         log.error( "Error processing request." )
  460.         raise Error(ERROR_INTERNAL)
  461.  
  462.     def handle_expt( self ):
  463.         raise Error
  464.  
  465.     def handle_read( self ):
  466.         raise Error
  467.  
  468.     def handle_write( self ):
  469.         raise Error
  470.  
  471.     def handle_connect( self ):
  472.         raise Error
  473.  
  474.     def handle_accept( self ):
  475.         raise Error
  476.  
  477.     def handle_close( self ):
  478.         self.close()
  479.  
  480.  
  481. class file_wrapper:
  482.     def __init__(self, fd):
  483.         self.fd = fd
  484.  
  485.     def recv(self, *args):
  486.         return os.read(self.fd, *args)
  487.  
  488.     def send(self, *args):
  489.         return os.write(self.fd, *args)
  490.  
  491.     read = recv
  492.     write = send
  493.  
  494.     def close(self):
  495.         os.close(self.fd)
  496.  
  497.     def fileno(self):
  498.         return self.fd
  499.  
  500.  
  501. class file_dispatcher(dispatcher):
  502.  
  503.     def __init__(self, fd):
  504.         dispatcher.__init__(self, None)
  505.         self.connected = True
  506.         self.set_file(fd)
  507.         flags = fcntl.fcntl(fd, fcntl.F_GETFL, 0)
  508.         flags = flags | os.O_NONBLOCK
  509.         fcntl.fcntl(fd, fcntl.F_SETFL, flags)
  510.  
  511.     def set_file(self, fd):
  512.         self._fileno = fd
  513.         self.socket = file_wrapper(fd)
  514.         self.add_channel()    
  515.  
  516.  
  517. class trigger(file_dispatcher):
  518.         def __init__(self):
  519.             r, w = os.pipe()
  520.             self.trigger = w
  521.             file_dispatcher.__init__(self, r)
  522.             self.send_events = False
  523.             self.typ = 'trigger'
  524.  
  525.         def readable(self):
  526.             return True
  527.  
  528.         def writable(self):
  529.             return False
  530.  
  531.         def handle_connect(self):
  532.             pass
  533.  
  534.         def pull_trigger(self):
  535.             os.write(self.trigger, '.')
  536.  
  537.         def handle_read (self):
  538.             self.recv(8192)
  539.  
  540.  
  541. class hpssd_server(dispatcher):
  542.     def __init__(self, ip, port):
  543.         self.ip = ip
  544.         self.send_events = False
  545.         
  546.  
  547.         if port != 0:
  548.             self.port = port
  549.         else:
  550.             self.port = socket.htons(0)
  551.  
  552.         dispatcher.__init__(self)
  553.         self.typ = 'server'
  554.         self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
  555.         self.set_reuse_addr()
  556.  
  557.         try:
  558.             self.bind((ip, port))
  559.         except socket.error:
  560.             raise Error(ERROR_UNABLE_TO_BIND_SOCKET)
  561.  
  562.         prop.hpssd_port = self.port = self.socket.getsockname()[1]
  563.         self.listen(5)
  564.  
  565.  
  566.     def writable(self):
  567.         return False
  568.  
  569.     def readable(self):
  570.         return self.accepting
  571.  
  572.     def handle_accept(self):
  573.         try:
  574.             conn, addr = self.accept()
  575.             log.debug("Connected to client: %s:%d (%d)" % (addr[0], addr[1], self._fileno))
  576.         except socket.error:
  577.             log.error("Socket error on accept()")
  578.             return
  579.         except TypeError:
  580.             log.error("EWOULDBLOCK exception on accept()")
  581.             return
  582.         handler = hpssd_handler(conn, addr, self)
  583.  
  584.     def handle_close(self):
  585.         dispatcher.handle_close(self)
  586.  
  587.  
  588. class hpssd_handler(dispatcher):
  589.     def __init__(self, conn, addr, server):
  590.         dispatcher.__init__(self, sock=conn)
  591.         self.addr = addr
  592.         self.in_buffer = ''
  593.         self.out_buffer = ''
  594.         self.server = server
  595.         self.fields = {}
  596.         self.payload = ''
  597.         self.signal_exit = False
  598.         self.typ = ''
  599.         self.send_events = False 
  600.         self.username = ''
  601.         
  602.         # handlers for all the messages we expect to receive
  603.         self.handlers = {
  604.             # Request/Reply Messages
  605.             'probedevicesfiltered' : self.handle_probedevicesfiltered,
  606.             'setalerts'            : self.handle_setalerts,
  607.             'testemail'            : self.handle_test_email,
  608.             'querymodel'           : self.handle_querymodel, # By device URI
  609.             'modelquery'           : self.handle_modelquery, # By model (backwards compatibility)
  610.             'queryhistory'         : self.handle_queryhistory,
  611.             'querystring'          : self.handle_querystring,
  612.             'setvalue'             : self.handle_setvalue,
  613.             'getvalue'             : self.handle_getvalue,
  614.  
  615.             # Event Messages (no reply message)
  616.             'event'                : self.handle_event,
  617.             'registerguievent'     : self.handle_registerguievent, # register for events
  618.             'unregisterguievent'   : self.handle_unregisterguievent,
  619.             'exitevent'            : self.handle_exit,
  620.  
  621.             # Fax
  622.             'hpfaxbegin'           : self.handle_hpfaxbegin,
  623.             'hpfaxdata'            : self.handle_hpfaxdata,
  624.             'hpfaxend'             : self.handle_hpfaxend,
  625.             'faxgetdata'           : self.handle_faxgetdata,
  626.             
  627.             # Misc
  628.             'unknown'              : self.handle_unknown,
  629.         }
  630.  
  631.  
  632.     def handle_read(self):
  633.         log.debug("Reading data on channel (%d)" % self._fileno)
  634.         self.in_buffer = self.recv(prop.max_message_read)
  635.  
  636.         log.debug(repr(self.in_buffer))
  637.  
  638.         if not self.in_buffer:
  639.             return False
  640.  
  641.         remaining_msg = self.in_buffer
  642.  
  643.         while True:
  644.             try:
  645.                 self.fields, self.payload, remaining_msg = parseMessage(remaining_msg)
  646.             except Error, e:
  647.                 err = e.opt
  648.                 log.warn("Message parsing error: %s (%d)" % (e.msg, err))
  649.                 self.out_buffer = self.handle_unknown(err)
  650.                 log.debug(self.out_buffer)
  651.                 return True
  652.  
  653.             msg_type = self.fields.get('msg', 'unknown').lower()
  654.             log.debug("Handling: %s %s %s" % ("*"*20, msg_type, "*"*20))
  655.             log.debug(repr(self.in_buffer))
  656.  
  657.             try:
  658.                 self.handlers.get(msg_type, self.handle_unknown)()
  659.             except Error:
  660.                 log.error("Unhandled exception during processing:")
  661.                 log.exception()
  662.  
  663.             self.handle_write()
  664.             
  665.             if not remaining_msg:
  666.                 break
  667.  
  668.         return True
  669.  
  670.     def handle_unknown(self, err=ERROR_INVALID_MSG_TYPE):
  671.         pass
  672.  
  673.  
  674.     def handle_write(self):
  675.         if not self.out_buffer:
  676.             return
  677.  
  678.         log.debug("Sending data on channel (%d)" % self._fileno)
  679.         log.debug(repr(self.out_buffer))
  680.         
  681.         while self.out_buffer:
  682.             sent = self.send(self.out_buffer)
  683.             self.out_buffer = self.out_buffer[sent:]
  684.  
  685.         if self.signal_exit:
  686.             self.handle_close()
  687.  
  688.  
  689.     def __checkdevice(self, device_uri):
  690.         try:
  691.             devices[device_uri]
  692.         except KeyError:
  693.             log.debug("New device: %s" % device_uri)
  694.             try:
  695.                 back_end, is_hp, bus, model, serial, dev_file, host, port = \
  696.                     device.parseDeviceURI(device_uri)
  697.             except Error:
  698.                 log.error("Invalid device URI")
  699.                 return ERROR_INVALID_DEVICE_URI
  700.  
  701.             devices[device_uri] = ServerDevice(model)
  702.         
  703.         return ERROR_SUCCESS
  704.             
  705.  
  706.     def handle_getvalue(self):
  707.         device_uri = self.fields.get('device-uri', '').replace('hpfax:', 'hp:')
  708.         value = ''
  709.         key = self.fields.get('key', '')
  710.         result_code = self.__checkdevice(device_uri)
  711.         
  712.         if result_code == ERROR_SUCCESS:
  713.             try:
  714.                 value = devices[device_uri].cache[key]
  715.             except KeyError:
  716.                 value, result_code = '', ERROR_INTERNAL
  717.             
  718.         self.out_buffer = buildResultMessage('GetValueResult', value, result_code)
  719.         
  720.     def handle_setvalue(self):
  721.         device_uri = self.fields.get('device-uri', '').replace('hpfax:', 'hp:')
  722.         key = self.fields.get('key', '')
  723.         value = self.fields.get('value', '')
  724.         result_code = self.__checkdevice(device_uri)
  725.         if result_code == ERROR_SUCCESS:    
  726.             devices[device_uri].cache[key] = value
  727.         self.out_buffer = buildResultMessage('SetValueResult', None, ERROR_SUCCESS)
  728.         
  729.     def handle_queryhistory(self):
  730.         device_uri = self.fields.get('device-uri', '').replace('hpfax:', 'hp:')
  731.         payload = ''
  732.         result_code = self.__checkdevice(device_uri)
  733.  
  734.         if result_code == ERROR_SUCCESS:    
  735.             for h in devices[device_uri].history.get():
  736.                 payload = '\n'.join([payload, ','.join([str(x) for x in h])])
  737.  
  738.         self.out_buffer = buildResultMessage('QueryHistoryResult', payload, result_code)
  739.  
  740.     def handle_querymodel(self): # By device URI (used by toolbox, info, etc)
  741.         device_uri = self.fields.get('device-uri', '').replace('hpfax:', 'hp:')
  742.         result_code = self.__checkdevice(device_uri)
  743.         mq = {}
  744.         
  745.         if result_code == ERROR_SUCCESS:    
  746.             try:
  747.                 back_end, is_hp, bus, model, \
  748.                     serial, dev_file, host, port = \
  749.                     device.parseDeviceURI(device_uri)
  750.             except Error:
  751.                 result_code = e.opt
  752.             else:
  753.                 try:
  754.                     mq = QueryModel(model)
  755.                 except Error, e:
  756.                     mq = {}
  757.                     result_code = e.opt
  758.     
  759.         self.out_buffer = buildResultMessage('QueryModelResult', None, result_code, mq)
  760.  
  761.  
  762.     def handle_modelquery(self): # By model (used by hp: backend)
  763.         model = self.fields.get('model', '')
  764.         result_code = ERROR_SUCCESS
  765.  
  766.         try:
  767.             mq = QueryModel(model)
  768.         except Error, e:
  769.             mq = {}
  770.             result_code = e.opt
  771.  
  772.         self.out_buffer = buildResultMessage('ModelQueryResult', None, result_code, mq)
  773.  
  774.  
  775.     # TODO: Need to load alerts at start-up
  776.     def handle_setalerts(self):
  777.         result_code = ERROR_SUCCESS
  778.         username = self.fields.get('username', '')
  779.  
  780.         alerts[username] = {'email-alerts'       : utils.to_bool(self.fields.get('email-alerts', '0')),
  781.                             'email-from-address' : self.fields.get('email-from-address', ''),
  782.                             'email-to-addresses' : self.fields.get('email-to-addresses', ''),
  783.                            }
  784.  
  785.         self.out_buffer = buildResultMessage('SetAlertsResult', None, result_code)
  786.  
  787.  
  788.     # EVENT
  789.     def handle_registerguievent(self):
  790.         username = self.fields.get('username', '')
  791.         typ = self.fields.get('type', 'unknown')
  792.         self.typ = typ
  793.         self.username = username
  794.         self.send_events = True
  795.         log.debug("Registering GUI for events: (%s, %s, %d)" % (username, typ, self._fileno))
  796.  
  797.     # EVENT
  798.     def handle_unregisterguievent(self):
  799.         username = self.fields.get('username', '')
  800.         self.send_events = False
  801.  
  802.  
  803.     def handle_test_email(self):
  804.         result_code = ERROR_SUCCESS
  805.         username = self.fields.get('username', prop.username)
  806.  
  807.         try:
  808.             message = QueryString('email_test_message')
  809.         except Error:
  810.             message = ''
  811.             
  812.         try:
  813.             subject = QueryString('email_test_subject')
  814.         except Error:
  815.             subject = ''
  816.  
  817.         result_code = self.sendEmail(username, subject, message, True)
  818.         self.out_buffer = buildResultMessage('TestEmailResult', None, result_code)
  819.  
  820.  
  821.     def handle_querystring(self):
  822.         payload, result_code = '', ERROR_SUCCESS
  823.         string_id = self.fields['string-id']
  824.         try:
  825.             payload = QueryString(string_id)
  826.         except Error:
  827.             log.error("String query failed for id %s" % string_id)
  828.             payload = None
  829.             result_code = ERROR_STRING_QUERY_FAILED
  830.  
  831.         self.out_buffer = buildResultMessage('QueryStringResult', payload, result_code)
  832.  
  833.         
  834.     def createHistory(self, device_uri, code, jobid=0, username=prop.username):
  835.         result_code = self.__checkdevice(device_uri)
  836.         
  837.         if result_code == ERROR_SUCCESS:    
  838.             try:
  839.                 short_string = QueryString(code, 0)
  840.             except Error:
  841.                 short_string, long_string = '', ''
  842.             else:
  843.                 try:
  844.                     long_string = QueryString(code, 1)
  845.                 except Error:
  846.                     pass
  847.  
  848.             devices[device_uri].history.append(tuple(time.localtime()) +
  849.                                                 (jobid, username, code,
  850.                                                  short_string, long_string))
  851.                                                  
  852.             # return True if added code is the same 
  853.             # as the previous code (dup_event)
  854.             try:
  855.                 prev_code = devices[device_uri].history.get()[-2][11]
  856.             except IndexError:
  857.                 return False
  858.             else:
  859.                 return code == prev_code
  860.                 
  861.         
  862.     # sent by hpfax: to indicate the start of a complete fax rendering job
  863.     def handle_hpfaxbegin(self):      
  864.         global fax_file
  865.         username = self.fields.get('username', prop.username)
  866.         job_id = self.fields.get('job-id', 0)
  867.         printer_name = self.fields.get('printer', '')
  868.         device_uri = self.fields.get('device-uri', '').replace('hp:', 'hpfax:')
  869.         title = self.fields.get('title', '')
  870.         
  871.         log.debug("Creating data store for %s:%d" % (username, job_id))
  872.         fax_file[(username, job_id)] = cStringIO.StringIO()
  873.         
  874.         # Send an early warning to the hp-sendfax UI so that
  875.         # the response time to something happening is as short as possible
  876.         result_code = ERROR_GUI_NOT_AVAILABLE
  877.         for handler in socket_map:
  878.             handler_obj = socket_map[handler]        
  879.             
  880.             if handler_obj.send_events and \
  881.                 handler_obj.typ == 'fax' and \
  882.                 handler_obj.username == username:
  883.                 
  884.                 # send event to already running hp-sendfax
  885.                 handler_obj.out_buffer = \
  886.                     buildMessage('EventGUI', 
  887.                                 '\n\n',
  888.                                 {'job-id' : job_id,
  889.                                  'event-code' : EVENT_FAX_RENDER_DISTANT_EARLY_WARNING,
  890.                                  'event-type' : 'event',
  891.                                  'retry-timeout' : 0,
  892.                                  'device-uri' : device_uri,
  893.                                  'printer' : printer_name,
  894.                                  'title' : title,
  895.                                 })
  896.                 
  897.                 loopback_trigger.pull_trigger()        
  898.                 result_code = ERROR_SUCCESS
  899.         
  900.         self.out_buffer = buildResultMessage('HPFaxBeginResult', None, result_code)
  901.         
  902.         
  903.     # sent by hpfax: to transfer completed fax rendering data
  904.     def handle_hpfaxdata(self):
  905.         global fax_file
  906.         username = self.fields.get('username', prop.username)
  907.         job_id = self.fields.get('job-id', 0)
  908.         
  909.         if self.payload and (username, job_id) in fax_file:
  910.             fax_file[(username, job_id)].write(self.payload)
  911.             
  912.         self.out_buffer = buildResultMessage('HPFaxDataResult', None, ERROR_SUCCESS)
  913.         
  914.             
  915.     # sent by hpfax: to indicate the end of a complete fax rendering job
  916.     def handle_hpfaxend(self):
  917.         global fax_file
  918.         
  919.         username = self.fields.get('username', '')
  920.         job_id = self.fields.get('job-id', 0)
  921.         printer_name = self.fields.get('printer', '')
  922.         device_uri = self.fields.get('device-uri', '').replace('hp:', 'hpfax:')
  923.         title = self.fields.get('title', '')
  924.         job_size = self.fields.get('job-size', 0)
  925.         
  926.         fax_file[(username, job_id)].seek(0)
  927.         
  928.         for handler in socket_map:
  929.             handler_obj = socket_map[handler]        
  930.             
  931.             if handler_obj.send_events and \
  932.                 handler_obj.typ == 'fax' and \
  933.                 handler_obj.username == username:
  934.                 
  935.                 # send event to already running hp-sendfax
  936.                 handler_obj.out_buffer = \
  937.                     buildMessage('EventGUI', 
  938.                                 '\n\n',
  939.                                 {'job-id' : job_id,
  940.                                  'event-code' : EVENT_FAX_RENDER_COMPLETE,
  941.                                  'event-type' : 'event',
  942.                                  'retry-timeout' : 0,
  943.                                  'device-uri' : device_uri,
  944.                                  'printer' : printer_name,
  945.                                  'title' : title,
  946.                                  'job-size': job_size,
  947.                                 })        
  948.                 
  949.                 loopback_trigger.pull_trigger()
  950.                 break
  951.  
  952.         self.out_buffer = buildResultMessage('HPFaxEndResult', None, ERROR_SUCCESS)
  953.  
  954.         
  955.     # sent by hp-sendfax to retrieve a complete fax rendering job
  956.     # sent in response to the EVENT_FAX_RENDER_COMPLETE event or
  957.     # after being run with --job param, both after a hpfaxend message
  958.     def handle_faxgetdata(self):
  959.         global fax_file
  960.         result_code = ERROR_SUCCESS
  961.         username = self.fields.get('username', '')
  962.         job_id = self.fields.get('job-id', 0)
  963.         
  964.         try:
  965.             fax_file[(username, job_id)]
  966.         except KeyError:
  967.             result_code, data = ERROR_NO_DATA_AVAILABLE, ''
  968.         else:
  969.             data = fax_file[(username, job_id)].read(prop.max_message_len)
  970.         
  971.         if not data:
  972.             result_code = ERROR_NO_DATA_AVAILABLE
  973.             log.debug("Deleting data store for %s:%d" % (username, job_id))
  974.             del fax_file[(username, job_id)]
  975.         
  976.         self.out_buffer = buildResultMessage('FaxGetDataResult', data, result_code)
  977.         
  978.     
  979.     # EVENT
  980.     def handle_event(self):
  981.         gui_port, gui_host = None, None
  982.         event_type = self.fields.get('event-type', 'event')
  983.         event_code = self.fields.get('event-code', 0)
  984.         device_uri = self.fields.get('device-uri', '').replace('hpfax:', 'hp:')
  985.         log.debug("Device URI: %s" % device_uri)
  986.  
  987.         try:
  988.             error_string_short = QueryString(str(event_code), 0)
  989.         except Error:
  990.             error_string_short, error_string_long = '', ''
  991.         else:
  992.             try:
  993.                 error_string_long = QueryString(str(event_code), 1)
  994.             except Error:
  995.                 pass
  996.  
  997.         log.debug("Short/Long: %s/%s" % (error_string_short, error_string_long))
  998.  
  999.         job_id = self.fields.get('job-id', 0)
  1000.  
  1001.         try:
  1002.             username = self.fields['username']
  1003.         except KeyError:
  1004.             if job_id == 0:
  1005.                 username = prop.username
  1006.             else:
  1007.                 jobs = cups.getAllJobs()
  1008.                 for j in jobs:
  1009.                     if j.id == job_id:
  1010.                         username = j.user
  1011.                         break
  1012.                 else:
  1013.                     username = prop.username
  1014.  
  1015.  
  1016.         no_fwd = self.fields.get('no-fwd', False)
  1017.         log.debug("Username (jobid): %s (%d)" % (username, job_id))
  1018.         retry_timeout = self.fields.get('retry-timeout', 0)
  1019.         user_alerts = alerts.get(username, {})        
  1020.  
  1021.         dup_event = False
  1022.         if event_code <= EVENT_MAX_USER_EVENT:
  1023.             dup_event = self.createHistory(device_uri, event_code, job_id, username)
  1024.  
  1025.         pull = False
  1026.         if not no_fwd:
  1027.             for handler in socket_map:
  1028.                 handler_obj = socket_map[handler]
  1029.                 
  1030.                 if handler_obj.send_events:
  1031.                     log.debug("Sending event to client: (%s, %s, %d)" % (handler_obj.username, handler_obj.typ, handler_obj._fileno))
  1032.                     pull = True
  1033.  
  1034.                     if handler_obj.typ == 'fax':
  1035.                         t = device_uri.replace('hp:', 'hpfax:')
  1036.                     else:
  1037.                         t = device_uri.replace('hpfax:', 'hp:')
  1038.                     
  1039.                     handler_obj.out_buffer = \
  1040.                         buildMessage('EventGUI', 
  1041.                             '%s\n%s\n' % (error_string_short, error_string_long),
  1042.                             {'job-id' : job_id,
  1043.                              'event-code' : event_code,
  1044.                              'event-type' : event_type,
  1045.                              'retry-timeout' : retry_timeout,
  1046.                              'device-uri' : t,
  1047.                             })
  1048.  
  1049.             if pull:
  1050.                 loopback_trigger.pull_trigger()
  1051.  
  1052.             if event_code <= EVENT_MAX_USER_EVENT and \
  1053.                 user_alerts.get('email-alerts', False) and \
  1054.                 event_type == 'error' and \
  1055.                 not dup_event:
  1056.  
  1057.                 try:
  1058.                     subject = QueryString('email_alert_subject') + device_uri
  1059.                 except Error:
  1060.                     subject = device_uri
  1061.                 
  1062.                 message = '\n'.join([device_uri, 
  1063.                                      time.strftime("%a, %d %b %Y %H:%M:%S", time.localtime()),
  1064.                                      error_string_short, 
  1065.                                      error_string_long,
  1066.                                      str(event_code)])
  1067.                                      
  1068.                 self.sendEmail(username, subject, message, False)
  1069.                 
  1070.                 
  1071.     def sendEmail(self, username, subject, message, wait):
  1072.         msg = cStringIO.StringIO()
  1073.         result_code = ERROR_SUCCESS
  1074.         
  1075.         user_alerts = alerts.get(username, {}) 
  1076.         from_address = user_alerts.get('email-from-address', '')
  1077.         to_addresses = user_alerts.get('email-to-addresses', from_address)
  1078.         
  1079.         t = time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.gmtime())
  1080.         UUID = file("/proc/sys/kernel/random/uuid").readline().rstrip("\n")
  1081.         
  1082.         msg.write("Date: %s\n" % t)
  1083.         msg.write("From: <%s>\n" % from_address)
  1084.         msg.write("To: %s\n" % to_addresses)
  1085.         msg.write("Message-Id: <%s %s>\n" % (UUID, t))
  1086.         msg.write('Content-Type: text/plain\n')
  1087.         msg.write("Content-Transfer-Encoding: 7bit\n")
  1088.         msg.write('Mime-Version: 1.0\n')
  1089.         msg.write("Subject: %s\n" % subject)
  1090.         msg.write('\n')
  1091.         msg.write(message)
  1092.         #msg.write('\n')
  1093.         email_message = msg.getvalue()
  1094.         log.debug(repr(email_message))
  1095.  
  1096.         mt = MailThread(email_message, from_address)
  1097.         mt.start()
  1098.         
  1099.         if wait:
  1100.             mt.join() # wait for thread to finish
  1101.             result_code = mt.result
  1102.             
  1103.         return result_code
  1104.  
  1105.  
  1106.     def handle_probedevicesfiltered(self):
  1107.         payload, result_code = '', ERROR_SUCCESS
  1108.         num_devices, ret_devices = 0, {}
  1109.  
  1110.         buses = self.fields.get('bus', 'cups,usb,par').split(',')
  1111.         format = self.fields.get('format', 'default')
  1112.  
  1113.         for b in buses:
  1114.             bus = b.lower().strip()
  1115.             
  1116.             if bus == 'net':
  1117.                 ttl = int(self.fields.get('ttl', 4))
  1118.                 timeout = int(self.fields.get('timeout', 5))
  1119.  
  1120.                 try:
  1121.                     detected_devices = slp.detectNetworkDevices('224.0.1.60', 427, ttl, timeout)
  1122.                 except Error:
  1123.                     log.error("An error occured during network probe.")
  1124.                 else:
  1125.                     for ip in detected_devices:
  1126.                         hn = detected_devices[ip].get('hn', '?UNKNOWN?')
  1127.                         num_devices_on_jd = detected_devices[ip].get('num_devices', 0)
  1128.                         num_ports_on_jd = detected_devices[ip].get('num_ports', 1)
  1129.  
  1130.                         if num_devices_on_jd > 0:
  1131.                             for port in range(num_ports_on_jd):
  1132.                                 dev = detected_devices[ip].get('device%d' % (port+1), '0')
  1133.  
  1134.                                 if dev is not None and dev != '0':
  1135.                                     device_id = device.parseDeviceID(dev)
  1136.                                     model = device.normalizeModelName(device_id.get('MDL', '?UNKNOWN?'))
  1137.  
  1138.                                     if num_ports_on_jd == 1:
  1139.                                         device_uri = 'hp:/net/%s?ip=%s' % (model, ip)
  1140.                                     else:
  1141.                                         device_uri = 'hp:/net/%s?ip=%s&port=%d' % (model, ip, (port+1))
  1142.  
  1143.                                     device_filter = self.fields.get('filter', 'none')
  1144.  
  1145.                                     if device_filter in ('none', 'print'):
  1146.                                         include = True
  1147.                                     else:
  1148.                                         include = True
  1149.  
  1150.                                         try:
  1151.  
  1152.                                             fields = QueryModel(model)
  1153.                                         except Error:
  1154.                                             continue
  1155.  
  1156.                                         for f in device_filter.split(','):
  1157.                                             filter_type = int(fields.get('%s-type' % f.lower().strip(), 0))
  1158.                                             if filter_type == 0:
  1159.                                                 include = False
  1160.                                                 break
  1161.  
  1162.                                     if include:
  1163.                                         ret_devices[device_uri] = (model, hn)
  1164.  
  1165.             elif bus in ('usb', 'par'):
  1166.                 try:
  1167.                     prop.hpiod_port = int(file(os.path.join(prop.run_dir, 'hpiod.port'), 'r').read())
  1168.                 except:
  1169.                     prop.hpiod_port = 0
  1170.                 
  1171.                 log.debug("Connecting to hpiod (%s:%d)..." % (prop.hpiod_host, prop.hpiod_port))
  1172.                 hpiod_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  1173.                 hpiod_sock.connect((prop.hpiod_host, prop.hpiod_port))
  1174.             
  1175.                 fields, data, result_code = \
  1176.                     xmitMessage(hpiod_sock, "ProbeDevices", None, {'bus' : bus,})
  1177.                 
  1178.                 log.debug("Closing connection.")
  1179.                 hpiod_sock.close()
  1180.  
  1181.                 if result_code != ERROR_SUCCESS:
  1182.                     detected_devices = []
  1183.                 else:
  1184.                     detected_devices = [x.split(' ')[1] for x in data.splitlines()]
  1185.  
  1186.                 for d in detected_devices:
  1187.                     try:
  1188.                         back_end, is_hp, bus, model, serial, dev_file, host, port = \
  1189.                             device.parseDeviceURI(d)
  1190.                     except Error:
  1191.                         continue
  1192.  
  1193.                     if is_hp:
  1194.  
  1195.                         device_filter = self.fields.get('filter', 'none')
  1196.                         include = True
  1197.                         
  1198.                         if device_filter not in ('none', 'print'):
  1199.                             try:
  1200.                                 fields = QueryModel(model)
  1201.                             except Error:
  1202.                                 continue
  1203.  
  1204.                             for f in device_filter.split(','):
  1205.                                 filter_type = int(fields.get('%s-type' % f.lower().strip(), 0))
  1206.                                 if filter_type == 0:
  1207.                                     include = False
  1208.                                     break
  1209.  
  1210.                         if include:
  1211.                             ret_devices[d] = (model, '')
  1212.  
  1213.             elif bus == 'cups':
  1214.                 cups_printers = cups.getPrinters()
  1215.                 x = len(cups_printers)
  1216.  
  1217.                 for p in cups_printers:
  1218.                     device_uri = p.device_uri
  1219.  
  1220.                     if p.device_uri != '':
  1221.                         device_filter = self.fields.get('filter', 'none')
  1222.  
  1223.                         try:
  1224.                             back_end, is_hp, bs, model, serial, dev_file, host, port = \
  1225.                                 device.parseDeviceURI(device_uri)
  1226.                         except Error:
  1227.                             log.warning("Inrecognized URI: %s" % device_uri)
  1228.                             continue
  1229.  
  1230.                         if not is_hp:
  1231.                             continue
  1232.                             
  1233.                         include = True
  1234.                         if device_filter not in ('none', 'print'):
  1235.                             try:
  1236.                                 fields = QueryModel(model)
  1237.                             except Error:
  1238.                                 continue
  1239.  
  1240.                             for f in device_filter.split(','):
  1241.                                 filter_type = int(fields.get('%s-type' % f.lower().strip(), 0))
  1242.                                 if filter_type == 0:
  1243.                                     include = False
  1244.                                     break
  1245.  
  1246.                         if include:
  1247.                             ret_devices[device_uri] = (model, '')
  1248.  
  1249.  
  1250.         for d in ret_devices:
  1251.             num_devices += 1
  1252.  
  1253.             if format == 'default':
  1254.                 payload = ''.join([payload, d, ',', ret_devices[d][0], '\n'])
  1255.             else:
  1256.                 if ret_devices[d][1] != '':
  1257.                     payload = ''.join([payload, 'direct ', d, ' "HP ', ret_devices[d][0], '" "', ret_devices[d][1], '"\n'])
  1258.                 else:
  1259.                     payload = ''.join([payload, 'direct ', d, ' "HP ', ret_devices[d][0], '" "', d, '"\n'])
  1260.  
  1261.  
  1262.         self.out_buffer = buildResultMessage('ProbeDevicesFilteredResult', payload,
  1263.                                              result_code, {'num-devices' : num_devices})
  1264.  
  1265.     # EVENT
  1266.     def handle_exit(self):
  1267.         self.signal_exit = True
  1268.  
  1269.     def handle_messageerror(self):
  1270.         pass
  1271.  
  1272.     def writable(self):
  1273.         return not (not self.out_buffer and self.connected)
  1274.  
  1275.  
  1276.     def handle_close(self):
  1277.         log.debug("Closing channel (%d)" % self._fileno)
  1278.         self.connected = False
  1279.         self.close()
  1280.  
  1281.  
  1282. class MailThread(threading.Thread):
  1283.     def __init__(self, message, from_address):
  1284.         threading.Thread.__init__(self)
  1285.         self.message = message
  1286.         self.from_address = from_address
  1287.         self.result = ERROR_SUCCESS
  1288.  
  1289.     def run(self):
  1290.         log.debug("Starting Mail Thread...")
  1291.         sendmail = utils.which('sendmail')
  1292.         
  1293.         if sendmail:
  1294.             sendmail = os.path.join(sendmail, 'sendmail')
  1295.             sendmail += ' -t -r %s' % self.from_address
  1296.             
  1297.             log.debug(sendmail)
  1298.             std_out, std_in, std_err = popen2.popen3(sendmail) 
  1299.             log.debug(repr(self.message))
  1300.             std_in.write(self.message)
  1301.             std_in.close()
  1302.             
  1303.             r, w, e = select.select([std_err], [], [], 2.0)
  1304.             
  1305.             if r:
  1306.                 err = std_err.read()
  1307.                 if err:
  1308.                     log.error(repr(err))
  1309.                     self.result = ERROR_TEST_EMAIL_FAILED
  1310.             
  1311.         else:
  1312.             log.error("Mail send failed. sendmail not found.")
  1313.             self.result = ERROR_TEST_EMAIL_FAILED
  1314.             
  1315.         log.debug("Exiting mail thread")
  1316.  
  1317.  
  1318. def reInit():
  1319.     initStrings()
  1320.  
  1321.  
  1322. def handleSIGHUP(signo, frame):
  1323.     log.info("SIGHUP")
  1324.     reInit()
  1325.  
  1326.  
  1327. def exitAllGUIs():
  1328.     pass
  1329.  
  1330.     
  1331. USAGE = [(__doc__, "", "name", True),
  1332.          ("Usage: hpssd.py [OPTIONS]", "", "summary", True),
  1333.          utils.USAGE_OPTIONS,
  1334.          ("Do not daemonize:", "-x", "option", False),
  1335.          ("Port to listen on:", "-p<port> or --port=<port> (overrides value in /etc/hp/hplip.conf)", "option", False),
  1336.          utils.USAGE_LOGGING1, utils.USAGE_LOGGING2,
  1337.          ("Run in debug mode:", "-g (same as options: -ldebug -x)", "option", False),
  1338.          utils.USAGE_HELP,
  1339.         ]
  1340.         
  1341.  
  1342. def usage(typ='text'):
  1343.     if typ == 'text':
  1344.         utils.log_title(__title__, __version__)
  1345.         
  1346.     utils.format_text(USAGE, typ, __title__, 'hpssd.py', __version__)
  1347.     sys.exit(0)
  1348.  
  1349.  
  1350.  
  1351. def main(args):
  1352.     prop.prog = sys.argv[0]
  1353.     prop.daemonize = True
  1354.  
  1355.     try:
  1356.         opts, args = getopt.getopt(sys.argv[1:], 'l:xhp:g', 
  1357.             ['level=', 'help', 'help-man', 'help-rest', 'port='])
  1358.  
  1359.     except getopt.GetoptError:
  1360.         usage()
  1361.  
  1362.     if os.getenv("HPLIP_DEBUG"):
  1363.         log.set_level('debug')
  1364.     
  1365.     for o, a in opts:
  1366.         if o in ('-l', '--logging'):
  1367.             log_level = a.lower().strip()
  1368.             if not log.set_level(log_level):
  1369.                 usage()
  1370.                 
  1371.         elif o == '-g':
  1372.             log.set_level('debug')
  1373.             prop.daemonize = False
  1374.  
  1375.         elif o in ('-x',):
  1376.             prop.daemonize = False
  1377.  
  1378.         elif o in ('-h', '--help'):
  1379.             usage()
  1380.             
  1381.         elif o == '--help-rest':
  1382.             usage('rest')
  1383.             
  1384.         elif o == '--help-man':
  1385.             usage('man')
  1386.             
  1387.         elif o in ('-p', '--port'):
  1388.             try:
  1389.                 prop.hpssd_cfg_port = int(a)
  1390.             except ValueError:
  1391.                 log.error('Port must be a numeric value')
  1392.                 usage()
  1393.  
  1394.  
  1395.     utils.log_title(__title__, __version__)
  1396.  
  1397.     prop.history_size = 32
  1398.  
  1399.     # Lock pidfile before we muck around with system state
  1400.     # Patch by Henrique M. Holschuh <hmh@debian.org>
  1401.     utils.get_pidfile_lock(os.path.join(prop.run_dir, 'hpssd.pid'))
  1402.  
  1403.     # Spawn child right away so that boot up sequence
  1404.     # is as fast as possible
  1405.     if prop.daemonize:
  1406.         utils.daemonize()
  1407.  
  1408.     log.set_module('hpssd')
  1409.  
  1410.     # configure the various data stores
  1411.     gettext.install('hplip')
  1412.     reInit()
  1413.  
  1414.     # hpssd server dispatcher object
  1415.     try:
  1416.         server = hpssd_server(prop.hpssd_host, prop.hpssd_cfg_port)
  1417.     except Error, e:
  1418.         log.error("Server exited with error: %s" % e.msg)
  1419.         sys.exit(1)
  1420.  
  1421.     global loopback_trigger
  1422.     try:
  1423.         loopback_trigger = trigger()
  1424.     except Error, e:
  1425.         log.error("Server exited with error: %s" % e.msg)
  1426.         sys.exit(1)
  1427.  
  1428.     os.umask(0133)
  1429.     file(os.path.join(prop.run_dir, 'hpssd.port'), 'w').write('%d\n' % prop.hpssd_port)
  1430.     os.umask (0077)
  1431.     log.debug('port=%d' % prop.hpssd_port)
  1432.     log.info("Listening on %s:%d" % (prop.hpssd_host, prop.hpssd_port))
  1433.  
  1434.     signal.signal(signal.SIGHUP, handleSIGHUP)
  1435.  
  1436.     try:
  1437.         log.debug("Starting async loop...")
  1438.         try:
  1439.             loop(timeout=0.5)
  1440.         except KeyboardInterrupt:
  1441.             log.warn("Ctrl-C hit, exiting...")
  1442.         except Exception:
  1443.             log.exception()
  1444.  
  1445.         log.debug("Cleaning up...")
  1446.     finally:
  1447.         os.remove(os.path.join(prop.run_dir, 'hpssd.pid'))
  1448.         os.remove(os.path.join(prop.run_dir, 'hpssd.port'))
  1449.         server.close()
  1450.         return 0
  1451.  
  1452. if __name__ == "__main__":
  1453.     sys.exit(main(sys.argv[1:]))
  1454.  
  1455.  
  1456.