--- lib/pyzor/client.py	Sun Sep  8 22:37:15 2002
+++ lib/pyzor/client.py	Wed Apr 13 17:08:42 2005
@@ -8,6 +8,7 @@
 import getopt
 import tempfile
 import mimetools
+import multifile
 import sha
 
 import pyzor
@@ -58,11 +57,6 @@
         self.send(msg, address)
         return self.read_response(msg.get_thread())
 
-    def shutdown(self, address):
-        msg = ShutdownRequest()
-        self.send(msg, address)
-        return self.read_response(msg.get_thread())
-
     def build_socket(self):
         self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
 
@@ -132,39 +126,50 @@
 
     def run(self):
         debug = 0
-        (options, args) = getopt.getopt(sys.argv[1:], 'dh:', ['homedir='])
-        if len(args) < 1:
-           self.usage()
-
         specified_homedir = None
+        options = None
+        log = None
+        
+        try:
+            (options, args) = getopt.getopt(sys.argv[1:], 'd', ['homedir=', 'log'])
+        except getopt.GetoptError:
+            self.usage()    
+
+        if len(args) < 1:
+            self.usage()
 
         for (o, v) in options:
             if o == '-d':
                 debug = 1
-            elif o == '-h':
-               self.usage()
             elif o == '--homedir':
                 specified_homedir = v
+            elif o == '--log':
+                log = 1
         
         self.output = Output(debug=debug)
-
         homedir = pyzor.get_homedir(specified_homedir)
-
+        
+        if log:
+            sys.stderr = open(homedir + "/pyzor.log", 'a')
+            sys.stderr.write("\npyzor[" + repr (os.getpid()) + "]:\n")
+        
         config = pyzor.Config(homedir)
         config.add_section('client')
 
-        defaults = {'ServersFile': 'servers',
+        defaults = {'ServersFile':        'servers',
                     'DiscoverServersURL': ServerList.inform_url,
-                    'AccountsFile' : 'accounts',
+                    'AccountsFile':       'accounts',
+                    'Timeout':            str(Client.timeout),
                     }
 
         for k, v in defaults.items():
             config.set('client', k, v)
-            
+        
         config.read(os.path.join(homedir, 'config'))
         
         servers_fn = config.get_filename('client', 'ServersFile')
-    
+        Client.timeout = config.getint('client', 'Timeout')
+        
         if not os.path.exists(homedir):
             os.mkdir(homedir)
 
@@ -197,10 +202,13 @@
     def usage(self, s=None):
         if s is not None:
             sys.stderr.write("%s\n" % s)
-        sys.stderr.write("""usage: %s [-d] [--homedir dir] command [cmd_opts]
+        sys.stderr.write("""
+usage: %s [-d] [--homedir dir] command [cmd_opts]
 command is one of: check, report, discover, ping, digest, predigest,
-                   genkey, shutdown
+                   genkey
+                   
 Data is read on standard input (stdin).
+
 """
                          % sys.argv[0])
         sys.exit(2)
@@ -208,9 +216,9 @@
 
 
     def ping(self, args):
-        getopt.getopt(args[1:], '')
-
-        if len(args) > 1:
+        try:
+            getopt.getopt(args[1:], '')
+        except getopt.GetoptError:
             self.usage("%s does not take any non-option arguments" % args[0])
 
         runner = ClientRunner(self.client.ping)
@@ -221,30 +229,23 @@
         return runner.all_ok
         
 
-    def shutdown(self, args):
-        (opts, args2) = getopt.getopt(args[1:], '')
-
-        if len(args2) > 1:
+    def info(self, args):
+        try:
+            (options, args2) = getopt.getopt(args[1:], '', ['mbox'])
+        except getopt.GetoptError:
             self.usage("%s does not take any non-option arguments" % args[0])
 
-        runner = ClientRunner(self.client.shutdown)
+        do_mbox = 'msg'
 
-        for arg in args2:
-            server = Address.from_str(arg)
-            runner.run(server, (server,))
-                    
-        return runner.all_ok
-
-
-    def info(self, args):
-        getopt.getopt(args[1:], '')
-        
-        if len(args) > 1:
-            self.usage("%s does not take any non-option arguments" % args[0])
+        for (o, v) in options:
+            if o == '--mbox':
+                do_mbox = 'mbox'
 
         runner = InfoClientRunner(self.client.info)
 
-        for digest in FileDigester(sys.stdin, self.digest_spec):
+        for digest in get_input_handler(sys.stdin, self.digest_spec, do_mbox):
+            if digest is None:
+                continue
             for server in self.servers:
                 response = runner.run(server, (digest, server))
 
@@ -252,34 +253,45 @@
 
 
     def check(self, args):
-        getopt.getopt(args[1:], '')
-
-        if len(args) > 1:
+        try:
+            (options, args2) = getopt.getopt(args[1:], '', ['mbox'])
+        except getopt.GetoptError:
             self.usage("%s does not take any non-option arguments" % args[0])
 
+        do_mbox = 'msg'
+
+        for (o, v) in options:
+            if o == '--mbox':
+                do_mbox = 'mbox'
+
         runner = CheckClientRunner(self.client.check)
 
-        for digest in FileDigester(sys.stdin, self.digest_spec):
+        for digest in get_input_handler(sys.stdin, self.digest_spec, do_mbox):
+            if digest is None:
+                continue
             for server in self.servers:
-                response = runner.run(server, (digest, server))
+                runner.run(server, (digest, server))
                 
         return (runner.found_hit and not runner.whitelisted)
 
 
     def report(self, args):
-        (options, args2) = getopt.getopt(args[1:], '', ['mbox'])
-        do_mbox = False
-
-        if len(args2) > 1:
+        try:
+            (options, args2) = getopt.getopt(args[1:], '', ['mbox'])
+        except getopt.GetoptError:
             self.usage("%s does not take any non-option arguments" % args[0])
 
+        do_mbox = 'msg'
+
         for (o, v) in options:
             if o == '--mbox':
-                do_mbox = True
+                do_mbox = 'mbox'
                 
         all_ok = True
 
-        for digest in FileDigester(sys.stdin, self.digest_spec, do_mbox):
+        for digest in get_input_handler(sys.stdin, self.digest_spec, do_mbox):
+            if digest is None:
+                continue
             if not self.send_digest(digest, self.digest_spec,
                                     self.client.report):
                 all_ok = False
@@ -302,20 +314,22 @@
 
 
     def whitelist(self, args):
-        (options, args2) = getopt.getopt(args[1:], '', ['mbox'])
-
-        if len(args2) > 1:
+        try:
+            (options, args2) = getopt.getopt(args[1:], '', ['mbox'])
+        except getopt.GetoptError:
             self.usage("%s does not take any non-option arguments" % args[0])
 
-        do_mbox = False
+        do_mbox = 'msg'
 
         for (o, v) in options:
             if o == '--mbox':
-                do_mbox = True
+                do_mbox = 'mbox'
                 
         all_ok = True
 
-        for digest in FileDigester(sys.stdin, self.digest_spec, do_mbox):
+        for digest in get_input_handler(sys.stdin, self.digest_spec, do_mbox):
+            if digest is None:
+                continue
             if not self.send_digest(digest, self.digest_spec,
                                     self.client.whitelist):
                 all_ok = False
@@ -324,28 +338,29 @@
 
 
     def digest(self, args):
-        (options, args2) = getopt.getopt(args[1:], '', ['mbox'])
-
-        if len(args2) > 1:
+        try:
+            (options, args2) = getopt.getopt(args[1:], '', ['mbox'])
+        except getopt.GetoptError:
             self.usage("%s does not take any non-option arguments" % args[0])
 
-
-        do_mbox = False
+        do_mbox = 'msg'
 
         for (o, v) in options:
             if o == '--mbox':
-                do_mbox = True
+                do_mbox = 'mbox'
                 
-        for digest in FileDigester(sys.stdin, self.digest_spec, do_mbox):
+        for digest in get_input_handler(sys.stdin, self.digest_spec, do_mbox):
+            if digest is None:
+                continue
             sys.stdout.write("%s\n" % digest)
 
         return True
 
 
     def print_digested(self, args):
-        getopt.getopt(args[1:], '')
-
-        if len(args) > 1:
+        try:
+            getopt.getopt(args[1:], '')
+        except getopt.GetoptError:
             self.usage("%s does not take any non-option arguments" % args[0])
 
         def loop():
@@ -358,9 +373,9 @@
         return True
 
     def genkey(self, args):
-        getopt.getopt(args[1:], '')
-
-        if len(args) > 1:
+        try:
+            getopt.getopt(args[1:], '')
+        except getopt.GetoptError:
             self.usage("%s does not take any non-option arguments" % args[0])
 
         import getpass
@@ -414,7 +429,6 @@
                   'report':    report,
                   'ping' :     ping,
                   'genkey':    genkey,
-                  'shutdown':  shutdown,
                   'info':      info,
                   'whitelist': whitelist,
                   'digest':    digest,
@@ -608,31 +622,37 @@
 
 
 
-class FileDigester(BasicIterator):
-    __slots__ = ['digester']
-
-    def __init__(self, fp, spec, mbox=False):
-        self.digester = iter(get_file_digester(fp, spec, mbox))
-        self.output = pyzor.Output()
-
-    def next(self):
-        digest = self.digester.next()
-        self.output.debug("calculated digest: %s" % digest)
-        return digest
-
-
-
-def get_file_digester(fp, spec, mbox, seekable=False):
+def get_input_handler(fp, spec, style='msg', seekable=False):
     """Return an object that can be iterated over
     to get all the digests from fp according to spec.
     mbox is a boolean"""
-    if mbox:
+    if style == 'msg':
+        return filter(lambda x: x is not None,
+                      (DataDigester(rfc822BodyCleaner(fp),
+                                    spec, seekable).get_digest(),)
+                      )
+
+    elif style =='mbox':
         return MailboxDigester(fp, spec)
 
-    return (DataDigester(rfc822BodyCleaner(fp),
-                         spec, seekable).get_digest(),)
+    elif style == 'digests':
+        return JustDigestsIterator(fp)
+
+    raise ValueError, "unknown input style"
 
 
+class JustDigestsIterator(BasicIterator):
+    __slots__ = ['fp']
+    
+    def __init__(self, fp):
+        self.fp = fp
+
+    def next(self):
+        l = fp.readline()
+        if not l:
+            raise StopIteration
+        return l.rstrip()
+
 
 class MailboxDigester(BasicIterator):
     __slots__ = ['mbox', 'digest_spec', 'seekable']
@@ -645,7 +665,12 @@
         self.seekable    = seekable
 
     def next(self):
-        next_msg = self.mbox.next()
+        try:
+            next_msg = self.mbox.next()
+        except IOError:
+            print "Error: Please feed mailbox files in on stdin, i.e."
+            print "    pyzor digest --mbox < my_mbox_file"
+            next_msg = None
         if next_msg is None:
             raise StopIteration
         return DataDigester(next_msg, self.digest_spec,
