rewritten out of frustration (not yet finished)
diff --git a/Demo/pdist/rcvs.py b/Demo/pdist/rcvs.py
index f4795a4..9f9d8bd 100755
--- a/Demo/pdist/rcvs.py
+++ b/Demo/pdist/rcvs.py
@@ -1,272 +1,86 @@
 #! /usr/local/bin/python
 
-"Remote CVS -- command line interface"
+"""Remote CVS -- command line interface"""
 
-from cvslib import CVS, Entry
+from cvslib import CVS, File
 import md5
 import os
 import string
 import sys
-import time
-import fnmatch
+from cmdfw import CommandFrameWork
 
 
-ignored_patterns = ['*.pyc', '.*', '*~', '@*']
-def ignored(file):
-	if os.path.isdir(file): return 1
-	for pat in ignored_patterns:
-		if fnmatch.fnmatch(file, pat): return 1
-	return 0
-def not_ignored(file):
-	return not ignored(file)
+class MyFile(File):
 
-
-class PCVS(CVS):
-	
-	def __init__(self, proxy):
-		CVS.__init__(self)
-		self.proxy = proxy
-		self.readsums()
-		self.calcsums()
-	
-	def calcsums(self):
-		for file in self.keys():
-			e = self.entries[file]
-			if not e.new and e.sum is None:
-				sum = self.proxy.sum((file, e.rev))
-				e.setsum(sum)
-	
-	def prepare(self):
-		self.localfiles = filter(not_ignored, os.listdir(os.curdir))
-		self.localfiles.sort()
-
-		self.entryfiles = self.keys()
-
-		self.remotefiles = self.proxy.listfiles()
-
-		self.rcsfiles = self.entryfiles[:]
-		for file in self.remotefiles:
-			if file not in self.rcsfiles:
-				self.rcsfiles.append(file)
-		self.rcsfiles.sort()
-
-		self.localonlyfiles = []
-		for file in self.localfiles:
-			if file not in self.rcsfiles:
-				self.localonlyfiles.append(file)
-		self.localonlyfiles.sort()
-
-		self.allfiles = self.rcsfiles + self.localonlyfiles
-		self.allfiles.sort()
-	
-	def preparedetails(self, file):
-		entry = file in self.entryfiles
-		if entry:
-			e = self.entries[file]
-		else:
-			e = Entry('/%s/0///' % file)
-		e.entry = entry
-		e.local = file in self.localfiles
-		e.remote = file in self.remotefiles
-		if e.local:
-			e.lsum = sumfile(file)
-		else:
-			e.lsum = None
-		if e.remote:
-			e.rrev = self.proxy.head(file)
-			if e.rrev == e.rev:
-				e.rsum = e.sum
-			else:
-				e.rsum = self.proxy.sum(file)
-		else:
-			e.rrev = '0'
-			e.rsum = None
-		return e
-	
-	def report(self):
-		self.prepare()
-		for file in self.allfiles:
-			e = self.preparedetails(file)
-			if e.lsum == e.sum == e.rsum:
-				# All three exist and are equal
-				print '=', file
-			elif e.lsum == e.sum:
-				# Not modified locally, remote update pending
-				if e.lsum is None:
-					print 'N', file, '(new remote)'
-				else:
-					print 'U', file
-			elif e.sum == e.rsum:
-				# No remote update, modified locally
-				if e.rsum is None:
-					if e.new:
-						print 'A', file
-					else:
-						print '?', file
-				else:
-					if e.lsum is None:
-						print 'LOST', file
-					else:
-						print 'M', file
-			else:
-				# Conflict: remote update and locally modified
-				if e.lsum == e.rsum:
-					# Local and remote match!
-					print 'c', file
-				else:
-					print 'C', file
-
-	def fullcheck(self):
-		self.prepare()
-		ok = 1
-		for file in self.allfiles:
-			if file not in self.entryfiles \
-			   and file not in self.remotefiles:
-				continue
-			e = self.preparedetails(file)
-			if e.new:
-				if e.rrev:
-					print "%s: created by someone else"%file
-					ok = 0
-				continue
-			if e.rrev != e.rev:
-				print "%s: out of date (%s vs. %s)" % \
-				      (file, e.rev, rrev)
-				ok = 0
-		return ok
-	
 	def update(self):
-		self.prepare()
-		for file in self.rcsfiles:
-			e = self.preparedetails(file)
-			if e.lsum == e.sum == e.rsum:
-				print '=', file
-				continue
-			if e.sum == e.rsum:
-				if e.rev != e.rrev:
-					print '%s: %s -> %s w/o change' % \
-						(file, e.rev, e.rrev)
-					e.rev = e.rrev
-				if e.lsum != e.sum:
-					if e.lsum is None:
-						print '%s: file was lost' % \
-							(file,)
-						self.get(e)
-					elif e.new:
-						print 'A', file
-					else:
-						print 'M', file
-				continue
-			if e.lsum == e.sum:
-				if e.rev == e.rrev:
-					print '%s: no new revision' % file
-				print 'U', file,
-				sys.stdout.flush()
-				self.get(e)
-				print
-				continue
-			if e.lsum == e.rsum:
-				print 'c', file
-				e.rev = e.rrev
-				e.sum = e.rsum
-				e.new = e.sum is None and e.lsum is not None
-				if e.sum:
-					e.mtime, e.ctime = os.stat(e.file)[-2:]
-				self.entries[file] = e
-				continue
-			print 'C', file, '(not resolved)'
-		self.writeentries()
-		self.writesums()
-	
-	def get(self, e):
-		data = self.proxy.get(e.file)
-		f = open(e.file, 'w')
-		f.write(data)
-		f.close()
-		nsum = md5.new(data).digest()
-		e.setsum(nsum)
-		e.mtime, e.ctime = os.stat(e.file)[-2:]
-		e.new = 0
-		e.rev = e.rrev
-	
-	def commit(self):
-		if not self.fullcheck():
-			print "correct above errors first"
+		print self.file, '...'
+		if self.lsum == self.esum == self.rsum:
+			print '=', self.file
 			return
-		needed = []
-		for file in self.keys():
-			e = self.entries[file]
-			if e.new:
-				needed.append(file)
-				continue
-			lsum = sumfile(file)
-			if lsum != e.sum:
-				needed.append(file)
-				continue
-		if not needed:
-			print "no changes need committing"
+		if self.lsum and not self.erev and not self.rrev:
+			print '?', self.file
 			return
-		message = raw_input("One-liner: ")
-		for file in needed:
-			print "%s: putting ..." % file
-			e = self.entries[file]
-			data = open(file).read()
-			self.proxy.put(file, data, message)
-			e.rev = self.proxy.head(file)
-			e.setsum(self.proxy.sum(file))
-			e.new = 0
-			# XXX get it?
-			mtime, ctime = os.stat(file)[-2:]
-			e.mtime = mtime
-			e.ctime = ctime
-		self.writeentries()
-		self.writesums()
-	
-	def add(self, file):
-		if self.entries.has_key(file):
-			print "%s: already known" % file
-		else:
-			self.entries[file] = Entry('/%s/0/Initial %s//\n' %
-						   (file, file))
+		print 'X', self.file
+		
 
 
-def sumfile(file):
-	return md5.new(open(file).read()).digest()
+class RCVS(CVS):
+
+	FileClass = MyFile
+
+	def __init__(self):
+		CVS.__init__(self)
+
+	def checkfiles(self, files):
+		if not files:
+			def ok(file, self=self):
+				e = self.entries[file]
+				return e.eseen or e.rseen
+			files[:] = filter(ok, self.entries.keys())
+			files.sort()
+
+
+class rcvs(CommandFrameWork):
+
+	GlobalFlags = 'd:h:p:qv'
+	UsageMessage = \
+  "usage: rcvs [-d directory] [-h host] [-p port] [-q] [-v] subcommand arg ..."
+
+	def __init__(self):
+		"""Constructor."""
+		CommandFrameWork.__init__(self)
+		self.proxy = None
+		self.cvs = RCVS()
+
+	def options(self, opts):
+		self.opts = opts
+
+	def ready(self):
+		import rcsclient
+		self.proxy = rcsclient.openrcsclient(self.opts)
+		self.cvs.setproxy(self.proxy)
+		self.cvs.getentries()
+		self.cvs.getlocalfiles()
+		self.cvs.getremotefiles(self.proxy)
+
+	def default(self):
+		self.cvs.report()
+
+	def do_update(self, opts, files):
+		self.cvs.checkfiles(files)
+		if not files:
+			print "no files"
+			return
+		for file in files:
+			if not self.cvs.entries.has_key(file):
+				print "%s: not found" % file
+			else:
+				self.cvs.entries[file].update()
 
 
 def main():
-	import sys
-	import getopt
-	from rcsclient import openrcsclient
+	rcvs().run()
 
-	opts, args = getopt.getopt(sys.argv[1:], 'd:h:p:vq')
-	proxy = openrcsclient(opts)
-	x = PCVS(proxy)
-
-	if args:
-		cmd = args[0]
-		files = args[1:]
-		if cmd == 'add':
-			if not files:
-				print "add needs at least one file argument"
-			else:
-				for file in files:
-					x.add(file)
-				x.writeentries()
-		elif cmd in ('update', 'up'):
-			if files:
-				print "updates wants no file arguments"
-			else:
-				x.update()
-		elif cmd in ('commit', 'com'):
-			if files:
-				print "commit wants no file arguments"
-			else:
-				x.commit()
-		else:
-			print "Unknown command", cmd
-	else:
-		x.report()
 
 if __name__ == "__main__":
 	main()