[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[minion-cvs] Documentation cleanups throughout the code; remove some...



Update of /home/minion/cvsroot/src/minion/lib/mixminion
In directory moria.mit.edu:/tmp/cvs-serv30050/lib/mixminion

Modified Files:
	BuildMessage.py ClientDirectory.py ClientMain.py 
	ClientUtils.py Config.py Fragments.py MMTPClient.py Main.py 
	NetUtils.py Packet.py ServerInfo.py TLSConnection.py 
	ThreadUtils.py test.py 
Log Message:
Documentation cleanups throughout the code; remove some obsolete stuff; kill bad whitespace; update copyright dates

Index: BuildMessage.py
===================================================================
RCS file: /home/minion/cvsroot/src/minion/lib/mixminion/BuildMessage.py,v
retrieving revision 1.71
retrieving revision 1.72
diff -u -d -r1.71 -r1.72
--- BuildMessage.py	21 Feb 2004 00:02:09 -0000	1.71
+++ BuildMessage.py	6 Mar 2004 00:04:37 -0000	1.72
@@ -99,10 +99,10 @@
             path2: Sequence of ServerInfo objects for the 2nd leg of the path
             paddingPRNG: random number generator used to generate padding.
                   If None, a new PRNG is initialized.
+            suppressTag: if true, do not include a decodind handle in the
+                  routingInfo for this packet.
 
         Neither path1 nor path2 may be empty.  If one is, MixError is raised.
-
-        suppressTag DOCDOC
     """
     if paddingPRNG is None:
         paddingPRNG = Crypto.getCommonPRNG()
@@ -257,6 +257,7 @@
 
     # XXXX007 switch to Host info.  We need to use IPV4 for reply blocks
     # XXXX007 for now, since we don't know which servers will support HOST.
+    # XXXX007    (Do this after all hosts have upgraded to 0.0.6 or later.)
     return ReplyBlock(header, expiryTime,
                       SWAP_FWD_IPV4_TYPE,
                       path[0].getIPV4Info().pack(), sharedKey), secrets, tag
@@ -301,11 +302,11 @@
 def checkPathLength(path1, path2, exitType, exitInfo, explicitSwap=0,
                     suppressTag=0):
     """Given two path legs, an exit type and an exitInfo, raise an error
-       if we can't build a hop with the provided legs.
+       if we can't build a hop with the provided legs.  If suppressTag is
+       true, no decoding handle will be included.
 
        The leg "path1" may be null.
-
-       DOCDOC suppressTag"""
+    """
     err = 0 # 0: no error. 1: 1st leg too big. 2: 1st leg okay, 2nd too big.
     if path1 is not None:
         try:

Index: ClientDirectory.py
===================================================================
RCS file: /home/minion/cvsroot/src/minion/lib/mixminion/ClientDirectory.py,v
retrieving revision 1.33
retrieving revision 1.34
diff -u -d -r1.33 -r1.34
--- ClientDirectory.py	2 Mar 2004 05:40:14 -0000	1.33
+++ ClientDirectory.py	6 Mar 2004 00:04:37 -0000	1.34
@@ -1376,7 +1376,8 @@
         nickname = desc.getNickname()
 
         if self.headers:
-            #XXXX008 remove this eventually.
+            #XXXX007 remove this eventually, once all servers have upgraded
+            #XXXX007 to 0.0.6 or later.
             sware = desc['Server'].get("Software","")
             if (sware.startswith("Mixminion 0.0.4") or
                 sware.startswith("Mixminion 0.0.5alpha1")):
@@ -1473,7 +1474,9 @@
         return rt, ri, self.lastHop
 
     def suppressTag(self):
-        """DOCDOC"""
+        """Return true iff we should suppress the decoding handle when
+           generating packets for this address.
+        """
         if self.isSSFragmented:
             return 1
         elif self.exitType == 'drop':
@@ -1683,22 +1686,15 @@
             return "%s:%s"%(",".join(p1s), ",".join(p2s))
 
 #----------------------------------------------------------------------
-WARN_STAR = 1 #XXXX007 remove
-
-def parsePath(config, path, nHops=None, isReply=0, isSURB=0,
-              defaultNHops=None):
+def parsePath(config, path, isReply=0, isSURB=0):
     """Resolve a path as specified on the command line.  Returns a
        PathSpecifier object.
 
        config -- unused for now.
-       path -- the path, in a format described below.  If the path is
-          None, all servers are chosen as if the path were '*<nHops>'.
-       nHops -- the number of hops to use.  Defaults to defaultNHops.
+       path -- the path, in a format described below.
        startAt/endAt -- A time range during which all servers must be valid.
-       isSURB -- Boolean: is this a path for a reply block?
        isReply -- Boolean: is this a path for a reply?
-       defaultNHops -- The default path length to use when we encounter a
-          wildcard in the path.  Defaults to 6.
+       isSURB -- Boolean: is this a path for a reply block?
 
        Paths are ordinarily comma-separated lists of server nicknames or
        server descriptor filenames, as in:
@@ -1730,8 +1726,6 @@
        star on the path, nHops must be >= the path length.
     """
     halfPath = isReply or isSURB
-    if not path:
-        path = "*%d"%(nHops or defaultNHops or 6)
     # Break path into a list of entries of the form:
     #        string
     #     or "<swap>"
@@ -1776,7 +1770,9 @@
         elif re.match(r'\~(\d+)', ent):
             pathEntries.append(RandomServersPathElement(approx=int(ent[1:])))
         elif ent == '*':
-            pathEntries.append("*")
+            #XXXX008 remove entirely; we gave a warning in 0.0.6 and
+            #XXXX008 stopped supporting it in 0.0.7.
+            raise UIError("* without a number is no longer supported.")
         elif ent == '<swap>':
             pathEntries.append("<swap>")
         elif ent == '?':
@@ -1784,25 +1780,6 @@
         else:
             pathEntries.append(ServerPathElement(ent))
 
-    # If there's a variable-length wildcard...
-    if "*" in pathEntries:
-        # Find out where it is...
-        starPos = pathEntries.index("*")
-        if "*" in pathEntries[starPos+1:]:
-            raise UIError("Only one '*' is permitted in a single path")
-        # Figure out how many hops we expect to have...
-        approxHops = reduce(operator.add,
-                            [ ent.getAvgLength() for ent in pathEntries
-                              if ent not in ("*", "<swap>") ], 0)
-        # Replace the '*' with the number of additional hops we want.
-        myNHops = nHops or defaultNHops or 6
-        extraHops = max(myNHops-approxHops, 0)
-        pathEntries[starPos:starPos+1] =[RandomServersPathElement(n=extraHops)]
-
-        if WARN_STAR:
-            LOG.warn("'*' without a number is deprecated.  Try '*%d' instead.",
-                     extraHops)
-
     # Figure out how long the first leg should be.
     lateSplit = 0
     if "<swap>" in pathEntries:

Index: ClientMain.py
===================================================================
RCS file: /home/minion/cvsroot/src/minion/lib/mixminion/ClientMain.py,v
retrieving revision 1.163
retrieving revision 1.164
diff -u -d -r1.163 -r1.164
--- ClientMain.py	2 Mar 2004 18:55:32 -0000	1.163
+++ ClientMain.py	6 Mar 2004 00:04:37 -0000	1.164
@@ -77,7 +77,8 @@
             passwordManager = mixminion.ClientUtils.CLIPasswordManager()
         createPrivateDir(keyDir)
 
-        # XXXX008 remove this.
+        # XXXX008 remove this; we haven't used the old format since 0.0.5.
+
         # We used to store our keys in a different format.  At this point,
         # it's easier to change the filename.
         obsoleteFn = os.path.join(keyDir, "keyring")
@@ -180,6 +181,15 @@
 ## For reply blocks
 #SURBPath: ?,?,?,FavoriteExit
 
+### If there are servers that you never want to include in automatically
+### generated paths, you can list them here.
+## These servers will never begin a path:
+#BlockEntries: example1,example2
+## These servers will never end a path:
+#BlockExits: example3,example4
+## These servers will never appear in a path at all:
+#BlockServers: example5,example6,example7
+
 [Network]
 ConnectionTimeout: 60 seconds
 """ % fields)
@@ -538,10 +548,9 @@
 
     def flushQueue(self, maxPackets=None, handles=None):
         """Try to send packets in the queue to their destinations.  Do not try
-           to send more than maxPackets packets.  If not all packets will be
-           sent, choose the ones to try at random.
-
-           DOCDOC nicknames
+           to send more than maxPackets packets.  If 'handles' is provided,
+           try only to send the packets whose handles are listed in 'handles;
+           otherwise, choose the ones to try at random.
         """
         #XXXX write unit tests
         class PacketProxy:
@@ -658,6 +667,7 @@
 
             if not msg.isEncrypted():
                 if msg.isFragment():
+                    foundAFragment = 1
                     self.pool.addFragment(msg.getContents(), "---")
                 else:
                     results.append(msg.getContents())
@@ -677,6 +687,7 @@
                     if p.isSingleton():
                         results.append(p.getUncompressedContents())
                     else:
+                        foundAFragment = 1
                         self.pool.addFragment(p,nym)
                 else:
                     raise UIError("Unable to decode message")
@@ -684,6 +695,8 @@
             for p in results:
                 if not isPrintingAscii(p,allowISO=1):
                     raise UIError("Not writing binary message to terminal: Use -F to do it anyway.")
+        if foundAFragment:
+            self.pool.process()
         return results
 
 def readConfigFile(configFile):
@@ -766,7 +779,7 @@
     #  nHops: number of hops, or None.
     #  address: exit address, or None.
     #  lifetime: SURB lifetime, or None.
-    #  replyBlockFiles: list of SURB filenames. DOCDOC
+    #  replyBlockSources: list of SURB filenames (string), or SURB fds (int).
     #  configFile: Filename of configuration file, or None.
     #  forceQueue: true if "--queue" is set.
     #  forceNoQueue: true if "--no-queue" is set.
@@ -827,7 +840,7 @@
         self.nHops = None
         self.exitAddress = None
         self.lifetime = None
-        self.replyBlockSources = [] #DOCDOC int is fd, str is filename
+        self.replyBlockSources = []
 
         self.forceQueue = None
         self.forceNoQueue = None
@@ -897,7 +910,6 @@
                 except ValueError:
                     raise UsageError("%s expects an integer"%o)
             elif o in ('--passphrase-fd',):
-                #DOCDOC
                 try:
                     self.password_fileno = int(v)
                 except ValueError:
@@ -1024,15 +1036,12 @@
         isSURB = isReply = 0
         if self.wantReplyPath:
             p = 'SURBPath'; isSURB = 1
-            defHops = self.config['Security'].get("SURBPathLength", 4)
         elif useRB:
             p = 'ReplyPath'; isReply = 1
-            defHops = self.config['Security'].get("PathLength", 6)
         else:
             p = 'ForwardPath'
-            defHops = self.config['Security'].get("PathLength", 6)
         if self.path is None:
-            self.path = self.config['Security'].get(p, "*")
+            self.path = self.config['Security'].get(p, "*5")
 
         if isSURB:
             if self.lifetime is not None:
@@ -1046,8 +1055,7 @@
         self.endAt = previousMidnight(self.startAt+duration)
 
         self.pathSpec = mixminion.ClientDirectory.parsePath(
-            self.config, self.path, self.nHops, isReply=isReply, isSURB=isSURB,
-            defaultNHops=defHops)
+            self.config, self.path, isReply=isReply, isSURB=isSURB)
         self.directory.validatePath(self.pathSpec, self.exitAddress,
                                     self.startAt, self.endAt)
 
@@ -1078,7 +1086,7 @@
                              packet, then deliver multiple fragmented packets
                              to the recipient instead of having the server
                              reassemble the message.
-  --reply-block-fd=<N>       DOCDOC
+  --reply-block-fd=<N>       Read reply blcoks from file descriptor <N>.
 %(extra)s
 
 EXAMPLES:
@@ -1775,7 +1783,7 @@
         surblog.close()
 
 _FLUSH_QUEUE_USAGE = """\
-Usage: %(cmd)s [options]
+Usage: %(cmd)s [options] [servername] ...
   -h, --help                 Print this usage message and exit.
   -v, --verbose              Display extra debugging messages.
   -f <file>, --config=<file> Use a configuration file other than ~.mixminionrc
@@ -1785,7 +1793,12 @@
 EXAMPLES:
   Try to send all currently queued packets.
       %(cmd)s
-DOCDOC
+  Try to send at most 10 currently queued packets, chosen at random.
+      %(cmd)s -n 10
+  Try to send all currently queued packets for the server named 'Example1', or
+  for the server whose hostname is 'minion.example.com'.
+      %(cmd)s Example1 minion.example.com
+
 """.strip()
 
 def flushQueue(cmd, args):
@@ -1830,7 +1843,8 @@
 EXAMPLES:
   Remove all pending packets older than one week.
       %(cmd)s -d 7
-DOCDODC
+  Remove all pending packets for the server 'Example1'.
+      %(cmd)s Example1
 """.strip()
 
 def cleanQueue(cmd, args):

Index: ClientUtils.py
===================================================================
RCS file: /home/minion/cvsroot/src/minion/lib/mixminion/ClientUtils.py,v
retrieving revision 1.23
retrieving revision 1.24
diff -u -d -r1.23 -r1.24
--- ClientUtils.py	2 Mar 2004 07:06:14 -0000	1.23
+++ ClientUtils.py	6 Mar 2004 00:04:37 -0000	1.24
@@ -129,7 +129,7 @@
         if not chunk:
             break
         pw += chunk
-    # Strip trailing endline from password, if any.  
+    # Strip trailing endline from password, if any.
     if pw.endswith("\n"): pw = pw[:-1]
     return pw
 
@@ -725,6 +725,8 @@
             mixminion.ClientMain.clientUnlock()
 
     def getHandlesByAge(self, notAfter):
+        """Return a list of all handles for messages that were inserted into
+           the queue before 'notAfter'."""
         self.loadMetadata()
         result = []
         for h in self.store.getAllMessages():
@@ -734,7 +736,18 @@
 
     def getHandlesByDestAndAge(self, destList, directory, notAfter=None,
                                warnUnused=1):
-        """DOCDOC destset: set of hostnames, ips, or keyids"""
+        """Return a list of handles for all messages queued for servers in a
+           given list before a given date.
+
+              destList -- A list of hostnames, ips, keyids, or nicknames
+                for servers whose messages should be included in the result.
+              directory -- An instance of ClientDirectory used to resolve
+                nicknames.  This may be None if no nicknames are included.
+              notAfter -- If provided, a time such that no messages queued
+                later should be included
+              warnUnused -- If true, we log a message for every element in
+                destList that has no matching messages in the queue.
+        """
         destSet = {}
         reverse = {}
         for d in destList:
@@ -860,26 +873,34 @@
 # ----------------------------------------------------------------------
 
 class ClientFragmentPool:
-    """DOCDOC"""
+    """Wrapper around FragmentPool to provide a good interface for client-side
+       fragment reassembly."""
     def __init__(self, directory):
+        """Create a new FragmentPool storing its messages in 'directory'."""
         createPrivateDir(directory)
         self.dir = directory
         self.pool = None
 
     def __getPool(self):
+        """Helper: initialize self.pool and return it."""
         if self.pool is None:
             import mixminion.Fragments
             self.pool = mixminion.Fragments.FragmentPool(self.dir)
         return self.pool
 
     def close(self):
+        """Finalize self.pool."""
         if self.pool is not None:
             self.pool.close()
             self.pool = None
 
     def addFragment(self, fragment, nym=None):
-        """fragment is instance of fragmentPayload or is a string payload
-           DOCDOC"""
+        """Add a fragment to the pool, logging appropriate messages.  Return
+           the messageID which was updated, if any.
+
+             fragment -- an instance of FragmentPayload or a string payload.
+             nym -- the identity which received this message.
+        """
         pool = self.__getPool()
         if isinstance(fragment, types.StringType):
             try:
@@ -892,20 +913,24 @@
         assert isinstance(fragment, mixminion.Packet.FragmentPayload)
 
         r = pool.addFragment(fragment, nym=nym, verbose=1)
-        pool.unchunkMessages(); print "UNCHUNK"
         return r
 
     def process(self):
+        """Unchunk any messages that are ready for reassembly."""
         pool = self.__getPool()
         pool.unchunkMessages()
         pool.cleanQueue()
 
     def expireMessages(self, cutoff):
+        """Clean up any stale fragments from the pool that have been there
+           since before 'cutoff'."""
         pool = self.__getPool()
         pool.expireMessages(cutoff)
         self.cleanQueue()
 
     def getMessage(self, msgid):
+        """Return the string value of the reassembled message with ID 'msgid',
+           or raise an error explaining why we can't."""
         pool = self.__getPool()
         state = pool.getStateByMsgID(msgid)
         msg = pool.getReadyMessage(state.messageid)
@@ -921,10 +946,13 @@
                                 %msgid)
 
     def removeMessages(self, msgids):
+        """Remove all the messages whose IDs are in the list 'msgIDs'.  If the
+           messages were reassembled, mark them as 'COMPLETED'; else mark them
+           as 'REJECTED'."""
         pool = self.__getPool()
         idSet = {}
         for i in msgids:
-            state = pool.getStateByMsgID(i) 
+            state = pool.getStateByMsgID(i)
             if state is None:
                 raise UIError("No such message as %s")
             idSet[state.messageid] = 1
@@ -932,10 +960,13 @@
         pool.cleanQueue()
 
     def listMessages(self):
+        """Return a list of pretty-printed IDs for the messages in the pool."""
         pool = self.__getPool()
         return pool.listMessages()
 
     def formatMessageList(self):
+        """Return a list of strings suitable for display explaining the status
+           of the messages in the pool, sorted by pretty-printed ID."""
         msgs = self.listMessages()
         result = []
         msgids = msgs.keys()

Index: Config.py
===================================================================
RCS file: /home/minion/cvsroot/src/minion/lib/mixminion/Config.py,v
retrieving revision 1.78
retrieving revision 1.79
diff -u -d -r1.78 -r1.79
--- Config.py	2 Mar 2004 05:40:14 -0000	1.78
+++ Config.py	6 Mar 2004 00:04:37 -0000	1.79
@@ -363,7 +363,8 @@
         raise ConfigError("Invalid exponent on public key")
     return key
 
-# FFFF007/8 stop accepting YYYY/MM/DD
+# FFFF008 stop accepting YYYY/MM/DD.  We've generated the right thing
+# FFFF008 since 0.0.6.
 # Regular expression to match YYYY/MM/DD or YYYY-MM-DD
 _date_re = re.compile(r"^(\d\d\d\d)([/-])(\d\d)([/-])(\d\d)$")
 def _parseDate(s):
@@ -383,7 +384,7 @@
         raise ConfigError("Invalid date %r"%s)
     return calendar.timegm((yyyy,MM,dd,0,0,0,0,0,0))
 
-# FFFF007/8 stop accepting YYYY/MM/DD
+# FFFF008 stop accepting YYYY/MM/DD
 # Regular expression to match YYYY/MM/DD HH:MM:SS
 _time_re = re.compile(r"^(\d\d\d\d)([/-])(\d\d)([/-])(\d\d)\s+"
                       r"(\d\d):(\d\d):(\d\d)((?:\.\d\d\d)?)$")
@@ -978,14 +979,11 @@
                      'MaxSkew' : ('ALLOW', "interval", "10 minutes"),
                      'DirectoryTimeout' : ('ALLOW', "interval", "1 minute") },
         'User' : { 'UserDir' : ('ALLOW', "filename", DEFAULT_USER_DIR) },
-        'Security' : { 'PathLength' : ('ALLOW', "int", "8"),
-                       'SURBAddress' : ('ALLOW', None, None),
-                       'SURBPathLength' : ('ALLOW', "int", "4"),
+        'Security' : { 'SURBAddress' : ('ALLOW', None, None),
                        'SURBLifetime' : ('ALLOW', "interval", "7 days"),
                        'ForwardPath' : ('ALLOW', None, "*6"),
                        'ReplyPath' : ('ALLOW', None, "*4"),
                        'SURBPath' : ('ALLOW', None, "*4"),
-                       #DOCDOC and add to .mixminionrc
                        'BlockServers' : ('ALLOW*', 'list', ""),
                        'BlockEntries' : ('ALLOW*', 'list', ""),
                        'BlockExits' : ('ALLOW*', 'list', ""),
@@ -1013,12 +1011,6 @@
         _validateHostSection(self['Host'])
 
         security = self['Security']
-        p = security.get('PathLength', 8)
-        if not 0 < p <= 16:
-            raise ConfigError("Path length must be between 1 and 16")
-        if p < 4:
-            LOG.warn("Your default path length is frighteningly low."
-                          "  I'll trust that you know what you're doing.")
 
         t = self['Network'].get('ConnectionTimeout')
         if t:

Index: Fragments.py
===================================================================
RCS file: /home/minion/cvsroot/src/minion/lib/mixminion/Fragments.py,v
retrieving revision 1.13
retrieving revision 1.14
diff -u -d -r1.13 -r1.14
--- Fragments.py	2 Mar 2004 07:06:14 -0000	1.13
+++ Fragments.py	6 Mar 2004 00:04:37 -0000	1.14
@@ -148,7 +148,8 @@
     def addFragment(self, fragmentPacket, nym=None, now=None, verbose=0):
         """Given an instance of mixminion.Packet.FragmentPayload, record
            the fragment if appropriate and update the state of the
-           fragment pool if necessary.
+           fragment pool if necessary.  Returns the message ID that was
+           updated, or None if the fragment was redundant or misformed.
 
               fragmentPacket -- the new fragment to add.
               nym -- a string representing the identity that received this
@@ -156,8 +157,8 @@
                   attack where we send 2 fragments to 'MarkTwain' and 2
                   fragments to 'SClemens', and see that the message is
                   reconstructed.]
-
-           DOCDOC return, verbose
+              verbose -- if true, log information at the INFO level;
+                  otherwise, log at DEBUG.
         """
         if verbose:
             say = LOG.info
@@ -183,7 +184,7 @@
                                  chunkNum=None,
                                  overhead=fragmentPacket.getOverhead(),
                                  insertedDate=today,
-                                 nym=nym, 
+                                 nym=nym,
                                  digest=sha1(fragmentPacket.data))
         # ... and allocate or find the MessageState for this message.
         state = self._getState(meta)
@@ -342,7 +343,7 @@
         for mid in messageIDSet.keys():
             if why == "?":
                 state = self.states[mid]
-                if state.isDone: 
+                if state.isDone:
                     whythis = "COMPLETED"
                 else:
                     whythis = "REJECTED"
@@ -372,7 +373,10 @@
             return state
 
     def getStateByMsgID(self, msgid):
-        """DOCDOC"""
+        """Given a message ID (either a 20-byte full ID or a 12-byte
+           pretty-printed ID prefix), return a MessageState object for
+           the corresponding message, or None if the message is not
+           recognized."""
         if len(msgid) == 20:
             return self.state.get(msgid,None)
         elif len(msgid) == 12:
@@ -383,8 +387,11 @@
         return None
 
     def listMessages(self):
-        """DOCDOC
-           pretty-id => { 'size':x, 'nym':x, 'have':x, 'need':x }
+        """Return a map from pretty-printed message ID to dicts mapping:
+               'size' to the size of the message, in bytes
+               'nym' to the pseudonym receiving the message
+               'have' to the number of packets we have so far
+               'need' to the number of additional packets we need.
         """
         result = {}
         for msgid in self.states.keys():
@@ -509,7 +516,9 @@
         return [ self.chunks[i][0] for i in xrange(self.params.nChunks) ]
 
     def getCompleteness(self):
-        """(have,need) DOCDOC"""
+        """Return a tuple of (have,need), where 'need' is the final number
+           of packets needed to reconstruct the message, and 'have' is the
+           number we have so far."""
         need = self.params.k * self.params.nChunks
         have = self.params.k * len(self.chunks)
         for d in self.fragmentsByChunk:

Index: MMTPClient.py
===================================================================
RCS file: /home/minion/cvsroot/src/minion/lib/mixminion/MMTPClient.py,v
retrieving revision 1.55
retrieving revision 1.56
diff -u -d -r1.55 -r1.56
--- MMTPClient.py	16 Feb 2004 22:50:38 -0000	1.55
+++ MMTPClient.py	6 Mar 2004 00:04:38 -0000	1.56
@@ -113,7 +113,7 @@
                 raise e
 
         tls = context.sock(sock)
-        mixminion.TLSConnection.TLSConnection.__init__(self, tls, sock, 
+        mixminion.TLSConnection.TLSConnection.__init__(self, tls, sock,
                                                        serverName)
 
         if targetKeyID != '\x00' * 20:

Index: Main.py
===================================================================
RCS file: /home/minion/cvsroot/src/minion/lib/mixminion/Main.py,v
retrieving revision 1.71
retrieving revision 1.72
diff -u -d -r1.71 -r1.72
--- Main.py	2 Mar 2004 07:06:14 -0000	1.71
+++ Main.py	6 Mar 2004 00:04:38 -0000	1.72
@@ -1,5 +1,5 @@
 #!/usr/bin/python2
-# Copyright 2002-2003 Nick Mathewson.  See LICENSE for licensing information.
+# Copyright 2002-2004 Nick Mathewson.  See LICENSE for licensing information.
 # $Id$
 
 #"""Code to correct the python path, and multiplex between the various
@@ -197,7 +197,7 @@
 def printVersion(cmd,args):
     import mixminion
     print "Mixminion version %s" % mixminion.__version__
-    print ("Copyright 2002-2003 Nick Mathewson.  "+
+    print ("Copyright 2002-2004 Nick Mathewson.  "+
            "See LICENSE for licensing information.")
     print "NOTE: This software is for testing only.  The user set is too small"
     print "      to be anonymous, and the code is too alpha to be reliable."
@@ -285,7 +285,7 @@
             print "Interrupted."
 
 def getUIError():
-    """DOCDOC"""
+    """Return the UIError class from mixminion.Common"""
     commonModule = __import__('mixminion.Common', {}, {}, ['UIError'])
     return commonModule.UIError
 

Index: NetUtils.py
===================================================================
RCS file: /home/minion/cvsroot/src/minion/lib/mixminion/NetUtils.py,v
retrieving revision 1.11
retrieving revision 1.12
diff -u -d -r1.11 -r1.12
--- NetUtils.py	2 Feb 2004 07:05:49 -0000	1.11
+++ NetUtils.py	6 Mar 2004 00:04:38 -0000	1.12
@@ -86,7 +86,7 @@
        found.
     """
     _,haveIP6 = getProtocolSupport()
-    if not haveIP6: haveIP4 = 1 
+    if not haveIP6: haveIP4 = 1
     try:
         r = getIPs(name)
         inet4 = [ addr for addr in r if addr[0] == AF_INET ]
@@ -95,7 +95,7 @@
             LOG.warn("getIP returned no inet addresses for %r",name)
             return ("NOENT", "No inet addresses returned", time.time())
         if inet6 and not inet4 and not haveIP6:
-            return ("NOENT", 
+            return ("NOENT",
                  "All addresses were IPv6, and this host has no IPv6 support",
                  time.time())
         best4=best6=None

Index: Packet.py
===================================================================
RCS file: /home/minion/cvsroot/src/minion/lib/mixminion/Packet.py,v
retrieving revision 1.74
retrieving revision 1.75
diff -u -d -r1.74 -r1.75
--- Packet.py	21 Feb 2004 00:02:09 -0000	1.74
+++ Packet.py	6 Mar 2004 00:04:38 -0000	1.75
@@ -198,9 +198,11 @@
 
     def getExitAddress(self, tagged=1):
         """Return the part of the routingInfo that contains the delivery
-           address.  (Requires that routingType is an exit type.)"""
+           address.  (Requires that routingType is an exit type.)  If
+           'tagged' is true, ignore the first TAG_LEN bytes of the
+           routingInfo.
+        """
         assert self.routingtype >= MIN_EXIT_TYPE
-        #XXXX007 This interface is completely insane.  Change it.
         if not tagged:
             return self.routinginfo
         else:
@@ -591,7 +593,7 @@
 
        Fields: ip (a dotted quad string), port (an int from 0..65535),
        and keyinfo (a digest)."""
-    #XXXX007/8 phase this out.
+    #XXXX008 phase this out: we have supported hostnames since 0.0.6.
     def __init__(self, ip, port, keyinfo):
         """Construct a new IPV4Info"""
         assert 0 <= port <= 65535
@@ -996,7 +998,7 @@
 
     _ZLIB_LIBRARY_OK = 0.5
     if ver in ("1.1.2", "1.1.3", "1.1.4", "1.2.0", "1.2.0.1", "1.2.0.2",
-               "1.2.0.3", "1.2.0.4", "1.2.0.5", "1.2.0.6", "1.2.0.7", 
+               "1.2.0.3", "1.2.0.4", "1.2.0.5", "1.2.0.6", "1.2.0.7",
                "1.2.0.8", "1.2.1"):
         _ZLIB_LIBRARY_OK = 1
         return

Index: ServerInfo.py
===================================================================
RCS file: /home/minion/cvsroot/src/minion/lib/mixminion/ServerInfo.py,v
retrieving revision 1.81
retrieving revision 1.82
diff -u -d -r1.81 -r1.82
--- ServerInfo.py	7 Feb 2004 17:52:49 -0000	1.81
+++ ServerInfo.py	6 Mar 2004 00:04:38 -0000	1.82
@@ -123,13 +123,15 @@
                      "Published": ("REQUIRE", "time", None),
                      "Valid-After": ("REQUIRE", "date", None),
                      "Valid-Until": ("REQUIRE", "date", None),
-                     #XXXX008 change this to 'require'.
+                     #XXXX008 change this to 'require': servers have all
+                     #XXXX008 had it since 007.
                      "Contact": ("ALLOW", None, None),
                      "Comments": ("ALLOW", None, None),
                      "Packet-Key": ("REQUIRE", "publicKey", None),
                      "Contact-Fingerprint": ("ALLOW", None, None),
-                     "Packet-Formats": ("ALLOW", None, None),#XXXX007 remove
-                     # XXXX008 change these next few to "REQUIRE".
+                     "Packet-Formats": ("ALLOW", None, None),#XXXX008 remove
+                     # XXXX008 change these next few to "REQUIRE"; servers
+                     # XXXX008 have had them all since 0.0.5
                      "Packet-Versions": ("ALLOW", "list", '0.3'),
                      "Software": ("ALLOW", None, None),
                      "Secure-Configuration": ("ALLOW", "boolean", None),
@@ -137,10 +139,10 @@
                      },
         "Incoming/MMTP" : {
                      "Version": ("REQUIRE", None, None),
-                     "IP": ("ALLOW", "IP", None),#XXXX007/8 remove
-                     "Hostname": ("ALLOW", "host", None),#XXXX008 require
+                     "IP": ("ALLOW", "IP", None),#XXXX008 remove
+                     "Hostname": ("ALLOW", "host", None),#XXXX008 require;since 0.0.6
                      "Port": ("REQUIRE", "int", None),
-                     "Key-Digest": ("ALLOW", "base64", None),#XXXX007/8 rmv
+                     "Key-Digest": ("ALLOW", "base64", None),#XXXX008 rmv; not used since 0.0.5
                      "Protocols": ("REQUIRE", "list", None),
                      "Allow": ("ALLOW*", "addressSet_allow", None),
                      "Deny": ("ALLOW*", "addressSet_deny", None),
@@ -153,14 +155,14 @@
                      },
         "Delivery/MBOX" : {
                      "Version": ("REQUIRE", None, None),
-                     # XXXX007 change to 'REQUIRE'
+                     # XXXX008 change to 'REQUIRE'; since 0.0.6
                      "Maximum-Size": ("ALLOW", "int", "32"),
-                     # XXXX007 change to 'REQUIRE'
+                     # XXXX008 change to 'REQUIRE'; since 0.0.6
                      "Allow-From": ("ALLOW", "boolean", "yes"),
                      },
         "Delivery/SMTP" : {
                      "Version": ("REQUIRE", None, None),
-                     # XXXX007 change to 'REQUIRE'
+                     # XXXX008 change to 'REQUIRE'; since 0.0.6
                      "Maximum-Size": ("ALLOW", "int", "32"),
                      "Allow-From": ("ALLOW", "boolean", "yes"),
                      },
@@ -321,10 +323,6 @@
     def getHostname(self):
         """Return this server's Hostname. (Returns None for servers running
            version 0.0.5 or earlier.)"""
-        #XXXX006 remove this.  0.0.6alpha1 could crash when it got hostnames.
-        #XXXX006 Sadly, some people installed it anyway.
-        if self['Server'].get("Software","").endswith("0.0.6alpha1"):
-            return None
         return self['Incoming/MMTP'].get("Hostname")
 
     def getPort(self):

Index: TLSConnection.py
===================================================================
RCS file: /home/minion/cvsroot/src/minion/lib/mixminion/TLSConnection.py,v
retrieving revision 1.13
retrieving revision 1.14
diff -u -d -r1.13 -r1.14
--- TLSConnection.py	16 Feb 2004 22:50:38 -0000	1.13
+++ TLSConnection.py	6 Mar 2004 00:04:38 -0000	1.14
@@ -401,7 +401,7 @@
                     return cap
                 else:
                     # We got some data; add it to the inbuf.
-                    LOG.trace("Read got %s bytes from %s", 
+                    LOG.trace("Read got %s bytes from %s",
                               len(s), self.address)
                     self.inbuf.append(s)
                     self.inbuflen += len(s)

Index: ThreadUtils.py
===================================================================
RCS file: /home/minion/cvsroot/src/minion/lib/mixminion/ThreadUtils.py,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- ThreadUtils.py	8 Jan 2004 22:33:31 -0000	1.1
+++ ThreadUtils.py	6 Mar 2004 00:04:38 -0000	1.2
@@ -3,7 +3,7 @@
 
 """mixminion.ThreadUtils
 
-   Helper code for threading-related operations, including queues and 
+   Helper code for threading-related operations, including queues and
    RW-locks.
    """
 
@@ -100,7 +100,7 @@
 
 class RWLock:
     """A lock that allows multiple readers at a time, but only one writer."""
-    # Changes from sync.mrsw: 
+    # Changes from sync.mrsw:
     #    *  Use threading.Condition instead of sync.condition.
     #    *  Document everything.
     #    *  Don't hold on to rwOK forever when there's an error.
@@ -119,7 +119,7 @@
         self.nw = 0  # number writers either waiting to write or writing
         self.writing = 0  # 1 iff some thread is writing
         # map from each current reader's thread_ident to recursion depth.
-        self.readers = {} 
+        self.readers = {}
 
         # conditions
         self.readOK  = threading.Condition(self.rwOK)  # OK to unblock readers

Index: test.py
===================================================================
RCS file: /home/minion/cvsroot/src/minion/lib/mixminion/test.py,v
retrieving revision 1.188
retrieving revision 1.189
diff -u -d -r1.188 -r1.189
--- test.py	2 Mar 2004 18:52:24 -0000	1.188
+++ test.py	6 Mar 2004 00:04:38 -0000	1.189
@@ -6076,7 +6076,7 @@
                          'bar'    : '18:0FFF::4:1',
                          'baz.com': '10.99.22.8'},
                         delay=DELAY)
-            # Override getProtocolSupport so we don't convert IPv6 addrs to 
+            # Override getProtocolSupport so we don't convert IPv6 addrs to
             # an error if we're running on a host with no IPv6 support.
             mixminion.NetUtils._PROTOCOL_SUPPORT = (1,1)
 
@@ -6809,13 +6809,13 @@
         self.assertEquals(3, s.count("Only one relay known"))
 
         # wrap path parsing and verification and generation.
-        def ppath(dir, cfg, path, addr, nHops=None, startAt=None, endAt=None,
-                  halfPath=0, defaultNHops=None, nPaths=1):
+        def ppath(dir, cfg, path, addr, startAt=None, endAt=None,
+                  halfPath=0, nPaths=1):
             isReply = halfPath and (addr is None)
             isSURB = halfPath and (addr is not None)
             pathSpec = mixminion.ClientDirectory.parsePath(
-                cfg, path, nHops=nHops, isReply=isReply,
-                isSURB=isSURB, defaultNHops=defaultNHops)
+                cfg, path, isReply=isReply,
+                isSURB=isSURB)
             dir.validatePath(pathSpec, addr, startAt=startAt, endAt=endAt)
             paths = dir.generatePaths(nPaths, pathSpec, addr, startAt, endAt)
             if nPaths == 1:
@@ -6824,9 +6824,6 @@
             else:
                 return paths
 
-        #XXXX008a remove
-        mixminion.ClientDirectory.WARN_STAR = 0
-
         paddr = mixminion.ClientDirectory.parseAddress
         email = paddr("smtp:lloyd@dobler.com")
         mboxWithServer = paddr("mbox:Granola@Lola")
@@ -6865,7 +6862,7 @@
         fredfile = os.path.join(impdirname, "Fred1")
         p1,p2 = ppath(ks, None, "Alice,%r,Bob,Joe"%fredfile, email)
         pathIs((p1,p2), ((alice,fred),(bob,joe)))
-        p1,p2 = ppath(ks, None, "Alice,Fred,Bob,Lola,Joe", email, nHops=5)
+        p1,p2 = ppath(ks, None, "Alice,Fred,Bob,Lola,Joe", email)
         pathIs((p1,p2), ((alice,fred,bob),(lola,joe)))
         p1,p2 = ppath(ks, None, "Alice,Fred,Bob", mboxWithServer)
         pathIs((p1,p2), ((alice,fred),(bob,lola)))
@@ -6899,83 +6896,31 @@
         p1,p2 = ppath(ks, None, "Alice,Bob,?:Joe", email)
         eq((len(p1),len(p2)), (3,1))
         pathIs((p1[:-1],p2), ((alice,bob),(joe,)))
-        p1,p2 = ppath(ks, None, "Alice,Bob,Fred:Joe", email, nHops=4)
+        p1,p2 = ppath(ks, None, "Alice,Bob,Fred:Joe", email)
         pathIs((p1,p2), ((alice,bob,fred),(joe,)))
         p1,p2 = ppath(ks, None, "Alice,Bob,Fred:Joe", mboxWithServer)
         pathIs((p1,p2), ((alice,bob,fred),(joe,lola)))
         p1,p2 = ppath(ks, None, "Alice,Bob,Fred:Lola", mboxWithoutServer)
         pathIs((p1,p2), ((alice,bob,fred),(lola,)))
 
-        # 1c. Star, no colon
-        p1,p2 = ppath(ks, None, 'Alice,*,Joe', email, nHops=5)
-        pathIs((p1[0],p2[-1]), (alice, joe))
-        eq((len(p1),len(p2)), (3,2))
-
-        p1,p2 = ppath(ks, None, 'Alice,Bob,*,Joe', email, nHops=6)
-        pathIs((p1[0],p1[1],p2[-1]), (alice, bob, joe))
-        eq((len(p1),len(p2)), (3,3))
-
-        p1,p2 = ppath(ks, None, 'Alice,Bob,*', email, nHops=6)
-        pathIs((p1[0],p1[1],p2[-1]), (alice, bob, joe))
-        eq((len(p1),len(p2)), (3,3))
-
-        p1,p2 = ppath(ks, None, '*,Bob,Joe', email) #default nHops=6
-        pathIs((p2[-2],p2[-1]), (bob, joe))
-        eq((len(p1),len(p2)), (3,3))
-
-        p1,p2 = ppath(ks, None, 'Bob,*,Alice', mboxWithServer, nHops=5)
-        pathIs((p1[0],p2[-2],p2[-1]), (bob, alice, lola))
-        eq((len(p1),len(p2)), (3,3))
-
-        p1,p2 = ppath(ks, None, 'Bob,*,Alice,Lola', mboxWithoutServer)
-        pathIs((p1[0],p2[-2],p2[-1]), (bob, alice, lola))
-        eq((len(p1),len(p2)), (3,3))
-
-        # 1d. Star and colon
-        p1,p2 = ppath(ks, None, 'Bob:*,Alice', mboxWithServer, nHops=5)
-        pathIs((p1[0],p2[-2],p2[-1]), (bob, alice, lola))
-        eq((len(p1),len(p2)), (1,5))
-
-        p1,p2 = ppath(ks, None, 'Bob,*:Alice', mboxWithServer, nHops=5)
-        pathIs((p1[0],p2[-2],p2[-1]), (bob, alice, lola))
-        eq((len(p1),len(p2)), (4,2))
-
-        p1,p2 = ppath(ks, None, 'Bob,*,Joe:Alice', mboxWithServer, nHops=5)
-        pathIs((p1[0],p1[-1],p2[-2],p2[-1]), (bob, joe, alice, lola))
-        eq((len(p1),len(p2)), (4,2))
-
-        p1,p2 = ppath(ks, None, 'Bob,*,Lola:Alice,Joe', email)
-        pathIs((p1[0],p1[-1],p2[-2],p2[-1]), (bob, lola, alice, joe))
-        eq((len(p1),len(p2)), (4,2))
-
-        p1,p2 = ppath(ks, None, '*,Lola:Alice,Joe', email)
-        pathIs((p1[-1],p2[-2],p2[-1]), (lola, alice, joe))
-        eq((len(p1),len(p2)), (4,2))
-
-        p1,p2 = ppath(ks, None, 'Lola:Alice,*', email)
-        pathIs((p1[0],p2[0],p2[-1]), (lola, alice, joe))
-        eq((len(p1),len(p2)), (1,5))
-
-        p1,p2 = ppath(ks, None, 'Bob:Alice,*', mboxWithServer, nHops=5)
-        pathIs((p1[0],p2[0],p2[-1]), (bob, alice, lola))
-        eq((len(p1),len(p2)), (1,5))
+        # 1c, 1c':  Stars, no longer used.
 
         # 1d'. Tilde
         p1,p2 = ppath(ks, None, '~2', email)
         self.assert_(p1 and p2)
-        p1,p2 = ppath(ks, None, '?,~4,Bob,Joe', email) #default nHops=6
+        p1,p2 = ppath(ks, None, '?,~4,Bob,Joe', email)
         p = p1+p2
         pathIs((p2[-1], p2[-2],), (joe, bob))
         total = 0
         for _ in xrange(1000):
-            p1,p2 = ppath(ks, None, '~2,Bob,Joe', email) #default nHops=6
+            p1,p2 = ppath(ks, None, '~2,Bob,Joe', email)
             total += len(p1+p2)
         self.assert_(3.4 <= total/1000.0 <= 4.6)
 
         # 1e. Complex.
         try:
             suspendLog()
-            p1,p2 = ppath(ks, None, '?,Bob,*:Joe,*2,Joe', email, nHops=9)
+            p1,p2 = ppath(ks, None, '?,Bob,*3:Joe,*2,Joe', email)
         finally:
             resumeLog()
         pathIs((p1[1],p2[0],p2[-1]), (bob, joe, joe))
@@ -6998,16 +6943,16 @@
         # 2. Failing cases
         raises = self.assertRaises
         # Nonexistent server
-        raises(MixError, ppath, ks, None, "Pierre:Alice,*", email)
+        raises(MixError, ppath, ks, None, "Pierre:Alice,*2", email)
         # Two swap points
         raises(MixError, ppath, ks, None, "Alice:Bob:Joe", email)
         # Last hop doesn't support exit type
         raises(MixError, ppath, ks, None, "Alice:Bob,Fred", email)
         raises(MixError, ppath, ks, None, "Alice:Bob,Fred", mboxWithoutServer)
-        # Two stars.
-        raises(MixError, ppath, ks, None, "Alice,*,Bob,*,Joe", email)
+        # Old star syntax.
+        raises(MixError, ppath, ks, None, "Alice,*,Bob,Joe", email)
         # Nonexistent file
-        raises(MixError, ppath, ks, None, "./Pierre:Alice,*", email)
+        raises(MixError, ppath, ks, None, "./Pierre:Alice,*2", email)
 
         ## Try 'expungeByNickname'.
         # Zapping 'Lisa' does nothing, since she's in the directory...