infocalypse

(djk)
2009-05-01: Modified parse() to handle multiple updates on same line. Added

Modified parse() to handle multiple updates on same line. Added gensig.py script.

diff --git a/infocalypse/fms.py b/infocalypse/fms.py
--- a/infocalypse/fms.py
+++ b/infocalypse/fms.py
@@ -52,7 +52,6 @@ def send_msgs(fms_host, fms_port, msg_tu
             #print raw_msg
             try:
                 server.post(in_file)
-                pass
             finally:
                 in_file.close()
     finally:
@@ -120,7 +119,8 @@ def clean_nym(fms_id):
 
     return fms_id[pos + 1:]
 
-def to_msg_string(updates, announcements=None):
+def to_msg_string(updates, announcements=None,
+                  separator='\n'):
     """ Dump updates and announcements in a format which can
         be read by parse. """
     if updates is None:
@@ -135,21 +135,43 @@ def to_msg_string(updates, announcements
     announcements = list(announcements)
     announcements.sort()
 
-    text = ''
+    # Hmmm... extra loops for assert paranoia.
     for value in announcements:
         assert is_usk_file(value)
-        text += "A:%s\n" % value
 
     for update in updates:
         assert is_hex_string(update[0], 12)
         assert update[1] >= 0
-        text += "U:%s:%i\n" % (update[0], update[1])
 
-    return text
+    tmp = [separator.join(["A:%s" % value for value in announcements]),
+           separator.join(["U:%s:%i" % (update[0], update[1])
+                           for update in updates])]
+    while '' in tmp:
+        tmp.remove('')
+
+    return separator.join(tmp)
+
+def parse_updates(fields, updates):
+    """ Helper function parses updates. """
+    if fields[0] != 'U' or len(fields) < 3:
+        return False
+
+    while len(fields) > 0 and fields[0] == 'U' and len(fields) >= 3:
+        try:
+            if is_hex_string(fields[1]):
+                updates.add((fields[1], int(fields[2])))
+                fields = fields[3:]
+            else:
+                break
+        except ValueError:
+            break
+    # Doesn't imply success, just that we tried.
+    return True
 
 # A grepper, not a parser...
 def parse(text, is_lines=False):
     """ Parse updates and announcements from raw text. """
+
     if is_lines:
         lines = text
     else:
@@ -161,13 +183,10 @@ def parse(text, is_lines=False):
     for line in lines:
         line = line.strip() # Handle crlf bs on Windoze.
         fields = line.split(':')
-        if fields[0] == 'U' and len(fields) >= 3:
-            try:
-                if is_hex_string(fields[1]):
-                    updates.add((fields[1], int(fields[2])))
-            except ValueError:
-                continue
-        elif fields[0] == 'A' and len(fields) >= 2:
+        if parse_updates(fields, updates):
+            continue
+
+        if fields[0] == 'A' and len(fields) >= 2:
             try:
                 if is_usk_file(fields[1]):
                     announcements.add(fields[1])
@@ -413,12 +432,19 @@ def smoke_test():
     # Not values0 because of implicit update.
     assert values1 == values2
 
-    msg = make_update_msg('djk@isFiaD04zgAgnrEC5XJt1i4IE7AkNPqhBG5bONi6Yks'
-                          'test',
-                          'test',
-                          values0[0],
-                          values0[1])
-    send_msgs('127.0.0.1', 11119, (msg, ))
+    # Test sig style update strings.
+    text = to_msg_string(values0[0], None, ':')
+    print text
+    values3 = parse(text)
+    assert values3 == (values0[0], ())
+
+    # msg = make_update_msg('djk@isFiaD04zgAgnrEC5XJt1i4IE7AkNPqhBG5bONi6Yks'
+    #                           'infocalypse.tst',
+    #                           'infocalypse.tst',
+    #                           values0[0],
+    #                           values0[1])
+    # DOH! This goes over the wire
+    #send_msgs('127.0.0.1', 11119, (msg, ))
 
 if __name__ == "__main__":
     smoke_test()
diff --git a/infocalypse/gensig.py b/infocalypse/gensig.py
new file mode 100755
--- /dev/null
+++ b/infocalypse/gensig.py
@@ -0,0 +1,89 @@
+#!/usr/bin/env python
+
+# Need to suppress all exceptions.
+# pylint: disable-msg=W0702
+
+""" Program to print an fms/freemail signature string with embedded
+    repo update information.
+
+    Copyright (C) 2009 Darrell Karbott
+
+    This program is free software; you can redistribute it and/or
+    modify it under the terms of the GNU General Public
+    License as published by the Free Software Foundation; either
+    version 2.0 of the License, or (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    General Public License for more details.
+
+    You should have received a copy of the GNU General Public
+    License along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+    Author: djk@isFiaD04zgAgnrEC5XJt1i4IE7AkNPqhBG5bONi6Yks
+
+    This program has no command line interface.
+    You must modify the variables at the top of the file.
+"""
+import os
+
+from fcpclient import get_usk_hash
+from config import Config, DEFAULT_CFG_PATH
+from fms import to_msg_string
+
+# The maximum number of updates to include.
+MAX_UPDATES = 4 #  == 67 chars
+
+# The full path to your .infocalypse / infocalypse.ini
+# file. Should work for the default location.
+CFG_PATH = os.path.expanduser(DEFAULT_CFG_PATH)
+
+# The static part of your sig message with no trailing '\n'
+STATIC_TEXT = ('Incremental hg repos in Freenet (Not pyfreenethg!):\n'
+               + 'USK@-bk9znYylSCOEDuSWAvo5m72nUeMxKkDmH3nIqAeI-0,'
+               + 'qfu5H3FZsZ-5rfNBY-jQHS5Ke7AT2PtJWd13IrPZjcg,'
+               + 'AQACAAE/feral_codewright/8/source.html')
+
+# Your repo Request (not Insert!) URIs go here:
+#
+# The versions don't matter, they are read from your .infocalpse file.
+# Hmmm... using repo uris means you can broadcast information about
+# repos you have pulled but didn't insert.
+REPO_USKS = ('USK@kRM~jJVREwnN2qnA8R0Vt8HmpfRzBZ0j4rHC2cQ-0hw,'
+             + '2xcoQVdQLyqfTpF2DpkdUIbHFCeL4W~2X1phUYymnhM,'
+             + 'AQACAAE/fred_staging.R1/1',
+             'USK@kRM~jJVREwnN2qnA8R0Vt8HmpfRzBZ0j4rHC2cQ-0hw,'
+             + '2xcoQVdQLyqfTpF2DpkdUIbHFCeL4W~2X1phUYymnhM,'
+             + 'AQACAAE/infocalypse.hgext.R1/12',
+             )
+
+USK_HASHES = tuple([get_usk_hash(usk) for usk in REPO_USKS])
+
+def print_updates():
+    """ Print a sig message with embedded update strings or nothing
+        at all if there's an error. """
+    try:
+        stored_cfg = Config.from_file(CFG_PATH)
+        updates = []
+        for usk_hash in USK_HASHES:
+            index = stored_cfg.get_index(usk_hash)
+            if index is None:
+                # Uncomment this and run from the command line if
+                # you get no output.
+                #print "No stored index for usk hash: ", usk_hash
+                continue
+            updates.append((usk_hash, index))
+        updates.sort()
+        # Hmmm... silently truncate
+        updates = updates[:MAX_UPDATES]
+        if len(updates) > 0:
+            print STATIC_TEXT
+            print to_msg_string(updates, None, ':')
+    except:
+        # Fail silently, rather than spewing garbage into sig.
+        return
+
+if __name__ == "__main__":
+    print_updates()