Here is a commit log that didn't get through.
David
-----Forwarded Message-----
From: Mail Delivery System <[EMAIL PROTECTED]>
To: [EMAIL PROTECTED]
Subject: Mail delivery failed: returning message to sender
Date: 25 Dec 2002 03:58:53 -0800
This message was created automatically by mail delivery software (Exim).
A message that you sent could not be delivered to one or more of its
recipients. This is a permanent error. The following address(es) failed:
[EMAIL PROTECTED]
retry time not reached for any host after a long failure period
------ This is a copy of the message, including all the headers. ------
Return-path: <[EMAIL PROTECTED]>
Received: from sc8-pr-cvs1-b.sourceforge.net ([10.5.1.7]
helo=sc8-pr-cvs1.sourceforge.net)
by sc8-sf-netmisc.sourceforge.net with esmtp (Exim 3.36 #1 (Debian))
id 18PhCF-0004Dx-00
for <[EMAIL PROTECTED]>; Sat, 21 Dec 2002 02:49:31 -0800
Received: from guerizec by sc8-pr-cvs1.sourceforge.net with local (Exim 3.22 #1
(Debian))
id 18PhCE-0003Fe-00
for <[EMAIL PROTECTED]>; Sat, 21 Dec 2002 02:49:30 -0800
To: [EMAIL PROTECTED]
Subject: CVS: tmda/bin tmda-gui,1.17,1.18 tmda-manager,1.4,1.5
Message-Id: <[EMAIL PROTECTED]>
From: David Guerizec <[EMAIL PROTECTED]>
Date: Sat, 21 Dec 2002 02:49:30 -0800
Update of /cvsroot/tmda/tmda/bin
In directory sc8-pr-cvs1:/tmp/cvs-serv10896/bin
Modified Files:
tmda-gui tmda-manager
Log Message:
New version, major changes:
- Protocol is now v0.2 between tmda-manager and tmda-gui (net. mode)
Added command line switches with getopt, this makes it more
manageable for future extensions.
- Auth now have an authenticate() function which accepts a type of
authentication (remote, prog or file).
- tmda-gui has been enhanced to have persistant settings (position of
splitters, max number of messages in the pending list, refresh
interval, default address for the moment)
- tmda-gui can now read Defaults variables (no write yet)
Enjoy!
Index: tmda-gui
===================================================================
RCS file: /cvsroot/tmda/tmda/bin/tmda-gui,v
retrieving revision 1.17
retrieving revision 1.18
diff -u -r1.17 -r1.18
--- tmda-gui 17 Dec 2002 00:16:09 -0000 1.17
+++ tmda-gui 21 Dec 2002 10:49:28 -0000 1.18
@@ -79,7 +79,22 @@
sys.path.insert(0, sitedir)
## Lib access functions
+def lib_getVars(*vars):
+ """Get a configuration variable from TMDA.Defaults."""
+ ret = {}
+ from TMDA import Defaults
+ import copy
+ if '*' in vars:
+ vars = dict(Defaults).keys()
+ for var in vars:
+ try:
+ ret[var] = copy.copy(getattr(Defaults, var))
+ except AttributeError:
+ pass
+ return ret
+
def lib_getAddress(tag, option=None, address=None):
+ """Get a tagged address."""
try:
tagged_address = Address.Factory(tag = tag).create(address, option).address
except ValueError, msg:
@@ -88,6 +103,7 @@
return tagged_address
def lib_checkAddress(address, sender_address=None):
+ """Check a tagged address."""
#FIXME: Add localtime support
localtime = None
status = []
@@ -106,11 +122,12 @@
MessageError = "Message Error"
def lib_processMessage(msgid, command, **args):
+ """Get a pending message."""
try:
msg = Pending.Message(msgid)
except Errors.MessageError:
raise MessageError
- if command not in ('terse', 'show'):
+ if command not in ('terse', 'show',):
msg.initMessage()
try:
try:
@@ -131,6 +148,7 @@
raise MessageError
def lib_processPending(command, **args):
+ """Get the pending message list."""
Q = Pending.Queue(descending=1).initQueue()
if command == 'list':
return Q.listPendingIds()
@@ -142,28 +160,34 @@
sin = None
sout = None
-ProtoError = "Protocole Error"
+protocol_version = "0.2"
+ProtoError = "Protocol Error"
AuthError = "Authentication Error"
class SSL_socket:
"""Wrapper class to socket.ssl to add readline method."""
def __init__(self, sock):
- self._sock = socket.ssl(sock)
+ self._sock = sock
+ self._ssock = socket.ssl(sock)
+
+ def close(self):
+ self._sock.close()
def __getattr__(self, attr):
- return getattr(self._sock, attr)
+ return getattr(self._ssock, attr)
def readline(self):
line = []
- c = self._sock.read(1)
+ c = self._ssock.read(1)
while c:
line.append(c)
if c == '\n':
return ''.join(line)
- c = self._sock.read(1)
+ c = self._ssock.read(1)
raise IOError, "Broken pipe"
def connectToServer(host, auth):
+ """Establish a connection to the server."""
global sock, sin, sout
if sock:
print "Already connected"
@@ -186,18 +210,35 @@
(dummy, protover) = l.split(' v', 1)
cc = sin.read(1)
- ## FIXME: check the version at some point
- print 'TMDA: %s' % tmdaver
- print 'Protocole: %s' % protover
+ print 'TMDA: %s (proto %s)' % (tmdaver, protover)
+ if protover != protocol_version:
+ msg = "Protocol %s is not supported," % protover \
+ + " current supported version is %s" % protocol_version
+ raise ProtoError, msg
sout.write('auth %s %s\n' % auth)
if sin.read(1) != '+':
raise AuthError, sin.readline()[:-1]
return 1
+def closeConnection():
+ """Close the connection to the server."""
+ if sin:
+ sin.close()
+ if sout:
+ sout.close()
+ if sock:
+ sock.close()
+
def net_command(command):
+ """Send a command to the server, and return the result."""
data = []
+# print str(command)
sout.write(str(command)+'\n')
cc = sin.read(1)
+ # '.' is the end of connection
+ if cc == '.':
+ closeConnection()
+ return ''
# ' ' is the data-transmit control char
while cc == ' ':
data.append(sin.readline()[:-1])
@@ -219,25 +260,64 @@
if r != s:
raise ProtoError, r
+def parse_pyvar(str):
+ """Parse a python variable."""
+ try:
+ result=eval('%s' % str)
+ except (NameError, SyntaxError):
+ result = str
+ return result
+
+
+def net_getVars(*vars):
+ """Get a configuration variable from TMDA.Defaults."""
+ vars = net_command('get %s' % ' '.join(vars))
+ res = {}
+ for var in vars:
+ (k, v) = var.split('=', 1)
+ res[k] = parse_pyvar(v)
+ return res
+
def net_getAddress(tag, option=None, address=None):
+ """Get a tagged address."""
try:
- tagged_address = '\n'.join(net_command('address %s %s' % (tag, option)))
+ if option:
+ option = '=' + option
+ else:
+ option = ''
+ if not address:
+ address = ''
+ tagged_address = '\n'.join(
+ net_command(
+ 'address --%s%s %s' \
+ % (tag, option, address)))
except ProtoError, msg:
print "%s: %s" % (ProtoError, msg)
return ''
return tagged_address
def net_checkAddress(address, sender_address=None):
+ """Check a tagged address."""
try:
- status = '\n'.join(net_command('checkaddress %s %s' % (address,
sender_address)))
+ status = '\n'.join(
+ net_command(
+ 'checkaddress %s %s' \
+ % (address, sender_address)))
except ProtoError, msg:
print "%s: %s" % (ProtoError, msg)
return ''
return status
def net_processMessage(msgid, command, **args):
+ """Get a pending message."""
+ opts = ''
+ for a in args.keys():
+ if args[a]:
+ opts += ' --%s=%s' % (a, args[a])
+ else:
+ opts += ' --%s' % a
try:
- data = net_command('message %s %s' % (command, msgid))
+ data = net_command('message --%s%s %s' % (command, opts, msgid))
return '\n'.join(data)
except ProtoError, msg:
print "%s: %s" % (ProtoError, msg)
@@ -245,11 +325,12 @@
raise MessageError
def net_processPending(command, **args):
+ """Get the pending message list."""
if command == 'list':
try:
## FIXME: add reverse option pending command
- data = net_command('pending only')
- data.reverse()
+ data = net_command('pending --only --descending=1')
+# data.reverse()
return data
except ProtoError, msg:
print "%s: %s" % (ProtoError, msg)
@@ -265,6 +346,7 @@
from TMDA import Errors
using_network = 0
+ getVars = lib_getVars
getAddress = lib_getAddress
checkAddress = lib_checkAddress
processMessage = lib_processMessage
@@ -296,6 +378,7 @@
sys.exit()
def PasswordPrompt(pl):
+ """Prompt for a password."""
def setpw(ev=None):
pl.append(ask.get())
ask.destroy()
@@ -318,17 +401,21 @@
try:
opts, args = getopt.getopt(sys.argv[1:],
- 'H:U:spVh',
+ 'H:U:spVhab',
['host=',
'user=',
'ssl',
'pending',
+ 'address',
+ 'both',
'version',
'help'])
except getopt.error, msg:
usage(1, msg)
-pending_first = 0
+pending_only = 0
+address_only = 0
+two_in_one = 0
host = None
port = 8765
use_ssl = None
@@ -341,8 +428,12 @@
if opt == '--version':
print Version.TMDA
sys.exit()
+ if opt in ('-b', '--both'):
+ two_in_one = 1
+ if opt in ('-a', '--address'):
+ address_only = 1
if opt in ('-p', '--pending'):
- pending_first = 1
+ pending_only = 1
if opt in ('-s', '--ssl'):
use_ssl = 1
elif opt in ('-H', '--host'):
@@ -373,6 +464,7 @@
sys.exit()
# map the accessors to the net_* functions
+ getVars = net_getVars
getAddress = net_getAddress
checkAddress = net_checkAddress
processMessage = net_processMessage
@@ -383,13 +475,73 @@
## Some helper widgets ##
##############################################
+class ConfigVar:
+ def __init__(self, file='~/.tmdaguirc'):
+ self._var = {}
+ self._file = file
+
+# def __getattr__(self, attr):
+# return self._var[attr]
+
+ def get(self, attr):
+ from copy import copy
+ if self._var.has_key(attr):
+ return copy(self._var[attr])
+ else:
+ return None
+
+ def default(self, attr, value):
+ if not self.get(attr):
+ self.set(attr, value);
+
+# def __setattr__(self, attr, value):
+# return self.set(attr, value)
+
+ def set(self, attr, value):
+ from copy import copy
+ self._var[attr] = copy(value)
+
+ def save(self):
+ import os.path
+ file=open(os.path.expanduser(self._file), "w")
+ file.write("# Auto-generated by tmda-gui. Please do not edit by hand\n")
+ file.write("# unless you know what you do. Delete this file if\n")
+ file.write("# something goes wrong.\n\n")
+ keys = self._var.keys()
+ keys.sort()
+ for k in keys:
+ file.write("%s=%s\n" % (k, repr(self._var[k])))
+ file.write("\n")
+ return self
+
+ def load(self):
+ def execnamespace(__file):
+ execfile(__file)
+ del __file
+ return locals()
+
+ import os.path
+ if os.path.exists(os.path.expanduser(self._file)):
+ self._var = execnamespace(os.path.expanduser(self._file))
+ else:
+ self._var = {}
+ return self
+
+ def dict(self):
+ from copy import copy
+ return copy(self._var)
+
+
+
class ProgressBar(Frame):
+ """Progress bar widget."""
def __init__(self, master=None, **args):
Frame.__init__(self, master, args)
self.pack(fill=BOTH, expand=YES)
self.cursor = None
def Show(self, max=100, step=1):
+ """Show the widget, set the max value and the increment step."""
self.Hide()
self.cursor = Scale(self, showvalue=NO, orient=HORIZONTAL)
self.cursor.pack(fill=BOTH, expand=YES)
@@ -400,9 +552,11 @@
self.update()
def Inc(self):
+ """Increment the widget value."""
self.Update(self.value + self.step)
def Update(self, value=-1):
+ """Update the widget with the given value."""
if value < 0:
value = (self.value + self.step)
print value
@@ -416,10 +570,12 @@
self.update()
def Hide(self):
+ """Destroy the widget."""
if self.cursor:
self.cursor.destroy()
class StatusBar(Frame):
+ """Status bar widget."""
def __init__(self, master, **args):
Frame.__init__(self, master, args)
self.message = Label(self, bd=1, relief=SUNKEN)
@@ -429,22 +585,28 @@
self.progress.pack(side=RIGHT, fill=X)
def Set(self, text, **args):
+ """Set the status message."""
args['text'] = ' ' + str(text) + ' '
self.message.configure(args)
self.update()
class HMultiSplitter(Frame):
+ """Horizontaly splitted frame widget."""
def __init__(self, master, number, **args):
Frame.__init__(self, master, args)
self.frames = [ Frame(self, bd=0, relief=SUNKEN) for x in range(number) ]
max = len(self.frames)
- step = 1.0 / max
+ if not self.splitpos or len(self.splitpos) != max+1:
+ self.splitpos = [ n * (1.0 / max) for n in range(max+1) ]
+
+ step = 0
y = 0
for f in self.frames:
- f.place(rely=y, relheight=step, relwidth=1)
+ y = self.splitpos[step]
+ f.place(rely=y, relheight=(self.splitpos[step + 1] -
+self.splitpos[step]), relwidth=1)
if y > 0:
sep = Frame(self, bd=2, relief=RAISED, width=8, height=2,
cursor="sb_v_double_arrow")
@@ -452,14 +614,16 @@
sep.bind('<ButtonPress>', self.Start)
sep.bind('<ButtonRelease>', self.Stop)
sep.split = y
+ sep.step = step
sep.fprev = fprev
fprev.snext = sep
sep.fnext = f
f.sprev = sep
- y += step
+ step += 1
fprev = f
def Start(self, ev):
+ """Start to move a splitter."""
s = ev.widget
s.splitpx = int(s.split * self.winfo_height())
s.rsz = s.splitpx
@@ -467,6 +631,7 @@
s.place(relx=2) # hide the splitter during the move
def Move(self, ev):
+ """Move a splitter."""
s = ev.widget
s.splitpx = s.rsz + ev.y
s.split = (1.0 * s.splitpx) / self.winfo_height()
@@ -490,28 +655,30 @@
s.fnext.place(rely=s.split, relheight=1.0-s.split)
def Stop(self, ev):
+ """Stop to move a splitter."""
s = ev.widget
s.bind('<B1-Motion>', lambda e: "break")
s.place(relx=0, rely=s.split, anchor=W)
+ self.splitpos[s.step] = s.split
class VMultiSplitter(Frame):
+ """Verticaly splitted frame widget."""
def __init__(self, master, number, **args):
- try:
- self.split = args['split']
- del args['split']
- except KeyError:
- self.split = 0.5
-
- Frame.__init__(self, master, args)
+ Frame.__init__(self, master, args)
+
self.frames = [ Frame(self, bd=0, relief=SUNKEN) for x in range(number) ]
max = len(self.frames)
- step = 1.0 / max
+ if not self.splitpos or len(self.splitpos) != max+1:
+ self.splitpos = [ n * (1.0 / max) for n in range(max+1) ]
+
+ step = 0
x = 0
for f in self.frames:
- f.place(relx=x, relwidth=step, relheight=1)
+ x = self.splitpos[step]
+ f.place(relx=x, relwidth=(self.splitpos[step + 1] - self.splitpos[step]),
+relheight=1)
if x > 0:
sep = Frame(self, bd=2, relief=RAISED, height=8, width=2,
cursor="sb_h_double_arrow")
@@ -519,14 +686,16 @@
sep.bind('<ButtonPress>', self.Start)
sep.bind('<ButtonRelease>', self.Stop)
sep.split = x
+ sep.step = step
sep.fprev = fprev
fprev.snext = sep
sep.fnext = f
f.sprev = sep
- x += step
+ step += 1
fprev = f
def Start(self, ev):
+ """Start to move a splitter."""
s = ev.widget
s.splitpx = int(s.split * self.winfo_width())
s.rsz = s.splitpx
@@ -534,6 +703,7 @@
s.place(rely=2) # hide the splitter during the move
def Move(self, ev):
+ """Move a splitter."""
s = ev.widget
s.splitpx = s.rsz + ev.x
s.split = (1.0 * s.splitpx) / self.winfo_width()
@@ -557,35 +727,92 @@
s.fnext.place(relx=s.split, relwidth=1.0-s.split)
def Stop(self, ev):
+ """Stop to move a splitter."""
s = ev.widget
s.bind('<B1-Motion>', lambda e: "break")
s.place(rely=0, relx=s.split, anchor=N)
+ self.splitpos[s.step] = s.split
+class TMDAHSplitter(HMultiSplitter):
+ def __init__(self, master, number, **args):
+ try:
+ self.splitpos = args['splitpos']
+ del args['splitpos']
+ except KeyError:
+ self.splitpos = cfg.get('DO_NOT_TOUCH_hmultisplitter_splitpos')
+ HMultiSplitter.__init__(self, master, number, **args)
+ cfg.set('DO_NOT_TOUCH_hmultisplitter_splitpos', self.splitpos)
-class MessageList(Frame):
+ def Stop(self, ev):
+ HMultiSplitter.Stop(self, ev)
+ cfg.set('DO_NOT_TOUCH_hmultisplitter_splitpos', self.splitpos)
+
+class TMDAVSplitter(VMultiSplitter):
+ def __init__(self, master, number, **args):
+ try:
+ self.splitpos = args['splitpos']
+ del args['splitpos']
+ except KeyError:
+ self.splitpos = cfg.get('DO_NOT_TOUCH_vmultisplitter_splitpos')
+ VMultiSplitter.__init__(self, master, number, **args)
+ cfg.set('DO_NOT_TOUCH_vmultisplitter_splitpos', self.splitpos)
+
+ def Stop(self, ev):
+ VMultiSplitter.Stop(self, ev)
+ cfg.set('DO_NOT_TOUCH_vmultisplitter_splitpos', self.splitpos)
+
+
+
+class TMDAMessageList(Frame):
+ """Message list widget."""
def __init__(self, master, statusbar=None, **args):
Frame.__init__(self, master, args)
self.statusbar = statusbar
self._sb = Scrollbar(self, orient=VERTICAL)
self._sb.config(command=self._yview)
- self._colnames = [ 'msgid', 'from_name', 'subject' ]
- self._collabels = { 'msgid': 'Date', 'from_name': 'From', 'subject':
'Subject', }
+ vars = getVars('TERSE_SUMMARY_HEADERS', 'TERSE_LABEL_HEADERS')
+ try:
+ self._colnames = vars['TERSE_SUMMARY_HEADERS']
+ # FIXME: test if the user wants the msgid (config)
+ self._colnames.insert(0, 'msgid')
+ try:
+ self._collabels = vars['TERSE_LABEL_HEADERS']
+ # FIXME: test if the user wants the msgid (config)
+ self._collabels.insert(0, 'msgid')
+ except KeyError:
+ # set some reasonable default
+ self._collabels = self._colnames
+
+ except KeyError:
+ # set some reasonable default
+ self._colnames = [ 'date', 'from_name', 'subject' ]
+ self._collabels = [ 'Date', 'From', 'Subject' ]
+ # FIXME: test if the user wants the msgid (config)
+ self._colnames.insert(0, 'msgid')
+ self._collabels.insert(0, 'msgid')
self._cols = []
- f = VMultiSplitter(self, len(self._colnames))
+# f = VMultiSplitter(self, len(self._colnames))
+ f = TMDAVSplitter(self, len(self._colnames))
f.pack(side=LEFT, fill=BOTH, expand=YES)
for i in range(len(self._colnames)):
- Label(f.frames[i], text=self._collabels[self._colnames[i]],
+ Label(f.frames[i], text=self._collabels[i],
bd=1, relief=RAISED).pack(side=TOP, fill=X)
l = Listbox(f.frames[i], yscrollcommand=self._set, bd=0)
l.pack(side=LEFT, fill=BOTH, expand=YES)
self._cols.append(l)
self._sb.pack(side=RIGHT, fill=Y)
+
+ self.maxmsg = cfg.get('messagelist_maxmsg')
+ if not self.maxmsg:
+ self.maxmsg = -1
+ cfg.set('messagelist_maxmsg', self.maxmsg)
def curselection(self):
+ """Get selected index."""
for col in self._cols:
selindex = col.curselection()
if selindex:
@@ -593,6 +820,7 @@
return selindex
def bind(self, key, action):
+ """Bind a key to each subframe."""
for col in self._cols:
col.bind(key, action)
return None
@@ -654,11 +882,12 @@
return ('', '')
def Refresh(self):
+ """Refresh the pending message list."""
try:
for col in self._cols:
col.delete(0, END)
self.msgs = []
- lst = processPending('list')
+ lst = processPending('list')[:self.maxmsg]
self.statusbar.Set('Please wait, loading message list...')
self.statusbar.progress.Show(len(lst))
x = 0
@@ -671,6 +900,7 @@
continue
self.msgs.append(item)
i = 0
+ #print repr(msg)
for col in self._cols:
col.insert(END, msg[i])
i = i + 1
@@ -678,9 +908,9 @@
except TclError: # Refresh is probably aborted by user
pass
-class PendingGUI(Frame):
+class TMDAPendingGUI(Frame):
+ """Pending message viewer widget."""
AppName = "tmda-gui"
- refresh_interval = 300
def __init__(self, master=None, statusbar=None, **args):
if 0 and master:
master.title(self.AppName)
@@ -689,50 +919,15 @@
Frame.__init__(self, master, args)
self.statusbar = statusbar
- self.menudef = [
- [
- { 'text': 'File', },
- { 'label': 'Open...',
- 'command': self.FileOpen, 'state': DISABLED, },
- { 'label': 'Save',
- 'command': self.FileSave, 'state': DISABLED, },
- { 'label': 'Save as...',
- 'command': self.FileSaveAs, 'state': DISABLED, },
- { 'label': 'Quit',
- 'command': self.FileQuit, },
- ],
- [
- { 'text': 'Edit', },
- { 'label': 'Undo',
- 'command': self.EditUndo, 'state': DISABLED, },
- { 'label': 'Settings...',
- 'command': self.EditSettings, },
- ],
- [
- { 'text': 'Message', },
- { 'label': 'Refresh',
- 'command': self.MessageRefresh, },
- { 'label': 'Show',
- 'command': self.MessageShow, },
- { 'label': 'Whitelist',
- 'command': self.MessageWhitelist, },
- { 'label': 'Release',
- 'command': self.MessageRelease, },
- { 'label': 'Blacklist',
- 'command': self.MessageBlacklist, },
- { 'label': 'Delete',
- 'command': self.MessageDelete, },
- ],
- [
- { 'text': 'Help', },
- { 'label': 'Help',
- 'command': self.HelpHelp, 'state': DISABLED, },
- { 'label': 'About',
- 'command': self.HelpAbout, },
- ],
- ]
+ self.refresh_interval = cfg.get('pending_refresh_interval')
+ if self.refresh_interval is None:
+ # default refresh interval is 10 minutes
+ self.refresh_interval = 600
+ cfg.set('pending_refresh_interval', self.refresh_interval)
self.master=master
self.createWidgets()
+ # let's wait 1 second, otherwise the message list doesn't
+ # show during the first refresh
self.counter = self.refresh_interval - 1
self.poll()
@@ -762,24 +957,6 @@
def EditUndo(self):
print "undoing stuff"
- def EditSettings(self):
- self.ws = Toplevel(self)
- Label(self.ws, text="Refresh interval (sec)").grid()
- self.ws.ri = Entry(self.ws)
- self.ws.ri.insert(END, self.refresh_interval)
- self.ws.ri.grid(row=0, column=1)
- Button(self.ws, text="OK", command=self.UpdateSettings,
- relief=GROOVE).grid(columnspan=2)
- self.ws.transient(self)
-
- def UpdateSettings(self):
- try:
- self.refresh_interval = int(self.ws.ri.get())
- except:
- pass
- self.ws.destroy()
- del self.ws
-
def HelpHelp(self):
print "Help: blah blah blah..."
@@ -798,19 +975,6 @@
about.ok = Button(f, text="OK", command=about.destroy, relief=GROOVE)
about.ok.pack(side=TOP)
- def createMenu(self):
- self.menu = Frame(self, relief=RAISED, bd=1)
- self.menu.pack(side=TOP, fill=X)
- self.menu.buttons = []
- for button in self.menudef:
- m = Menubutton(self.menu, button[0])
- m.pack(side=LEFT, padx="2m")
- m.menu = Menu(m)
- for cmd in button[1:]:
- m.menu.add_command(cmd)
- m['menu'] = m.menu
- self.menu.buttons.append(m)
-
def MessageRefresh(self, ev=None):
try:
self.message.text.delete(1.0, END)
@@ -847,8 +1011,6 @@
self.updateStatus()
def createWidgets(self):
- #self.createMenu()
-
self.toolbar = Frame(self, relief=GROOVE)
b = Button(self.toolbar, text="Refresh", bd=1,
@@ -869,12 +1031,10 @@
b = Button(self.toolbar, text="Delete", bd=1,
command=self.MessageDelete)
b.pack(side=LEFT, padx=0, pady=0)
-# b = Button(self.toolbar, text="Quit", bd=1,
-# command=self.FileQuit)
-# b.pack(side=RIGHT, padx=0, pady=0)
+
self.toolbar.pack(side=TOP, fill=X)
- self.split = HMultiSplitter(self, 2, width=600, height=400,
+ self.split = TMDAHSplitter(self, 2, width=600, height=400,
relief=GROOVE)
self.split.one = self.split.frames[0]
@@ -886,7 +1046,7 @@
self.statusbar = StatusBar(self)
self.statusbar.pack(side=BOTTOM, fill=X)
- self.listbox = MessageList(self.split.one, statusbar=self.statusbar)
+ self.listbox = TMDAMessageList(self.split.one, statusbar=self.statusbar)
self.listbox.bind("<Double-Button-1>", self.MessageShow)
self.listbox.pack(fill=BOTH, expand=YES)
@@ -913,7 +1073,8 @@
self.master.after(1000, self.poll)
-class AddressGUI(Frame):
+class TMDAAddressGUI(Frame):
+ """Address generator/checker widget."""
def __init__(self, master=None, **args):
R = 0
Frame.__init__(self, master, args)
@@ -988,25 +1149,26 @@
self.m_du.configure(text=self.units[self.uidx][0])
def Calc(self, ev=None):
+ address = cfg.get('address_main')
self.r_dated['state'] = NORMAL
self.r_dated.delete(0, END)
date = self.e_dated.get().strip()
if date:
- self.r_dated.insert(END, getAddress('dated', date +
self.units[self.uidx][1]))
+ self.r_dated.insert(END, getAddress('dated', date +
+self.units[self.uidx][1], address=address))
self.r_dated['state'] = DISABLED
self.r_keyword['state'] = NORMAL
self.r_keyword.delete(0, END)
keyword = self.e_keyword.get().strip()
if keyword:
- self.r_keyword.insert(END, getAddress('keyword', keyword))
+ self.r_keyword.insert(END, getAddress('keyword', keyword,
+address=address))
self.r_keyword['state'] = DISABLED
self.r_sender['state'] = NORMAL
self.r_sender.delete(0, END)
sender = self.e_sender.get().strip()
if sender:
- self.r_sender.insert(END, getAddress('sender', sender))
+ self.r_sender.insert(END, getAddress('sender', sender, address=address))
self.r_sender['state'] = DISABLED
tagged_addr = self.e_check.get().strip()
@@ -1020,6 +1182,7 @@
self.r_check.configure(text=status)
class About(Frame):
+ """About widget."""
def __init__(self, master, AppName, **args):
if not master:
master = Toplevel()
@@ -1041,8 +1204,51 @@
f = Frame(self, bd=10, relief=FLAT)
f.pack(side=TOP, fill=BOTH, expand=1)
+class TMDASettings(Frame):
+ def __init__(self, master, AppName, **args):
+ if not master:
+ master = Toplevel()
+ Frame.__init__(self, master, args)
+
+ try:
+ self.title("Configure %s" % AppName)
+ except AttributeError:
+ pass
+
+ self.vars = [
+ # Format is: variable name, label, default, type
+ ('messagelist_maxmsg', "Max messages in pending list", -1, int),
+ ('pending_refresh_interval', "Refresh interval (sec)", 600, int),
+ ('address_main', 'Main address', getAddress('base'), str)
+ ]
+
+ r=0
+ self.ent = {}
+ for (var, text, dft, typ) in self.vars:
+ Label(self, text=text).grid(row=r, column=0)
+ self.ent[var] = Entry(self)
+ cfg.default(var, dft)
+ self.ent[var].insert(END, str(cfg.get(var)))
+ self.ent[var].grid(row=r, column=1)
+ r += 1
+
+ Button(self, text="Apply", command=self.ApplySettings,
+ bd=2, relief=GROOVE).grid(row=r, column=0)
+
+ Button(self, text="Save", command=self.SaveSettings,
+ bd=2, relief=GROOVE).grid(row=r, column=1)
+
+ def ApplySettings(self):
+ for (var, text, dft, typ) in self.vars:
+ cfg.set(var, typ(self.ent[var].get()))
+
+ def SaveSettings(self):
+ self.ApplySettings()
+ cfg.save()
+
class TMDAGUI(Frame):
+ """The main application frame."""
AppName = "tmda-gui"
def __init__(self, master=None, **args):
if master:
@@ -1050,16 +1256,18 @@
master.protocol("WM_DELETE_WINDOW", self.Quit)
self.master = master
Frame.__init__(self, master, args)
- self.tabs = Frame(master=self)
+ self.tabs = Frame(master=self, bd=5, relief=GROOVE)
self.tabs.pack(side=TOP, fill=X)
- self.baddress = Button(self.tabs, text='Address', command=self.displayAddress)
+ self.baddress = Button(self.tabs, bd=1, text='Address',
+command=self.displayAddress)
self.baddress.pack(side=LEFT)
- self.bpending = Button(self.tabs, text='Pending', command=self.displayPending)
+ self.bpending = Button(self.tabs, bd=1, text='Pending',
+command=self.displayPending)
self.bpending.pack(side=LEFT)
- self.bquit = Button(self.tabs, text='Quit', command=self.Quit)
+ self.bquit = Button(self.tabs, bd=1, text='Quit', command=self.Quit)
self.bquit.pack(side=RIGHT)
- self.babout = Button(self.tabs, text='About', command=self.displayAbout)
+ self.babout = Button(self.tabs, bd=1, text='About', command=self.displayAbout)
self.babout.pack(side=RIGHT)
+ self.bconfig = Button(self.tabs, bd=1, text='Settings',
+command=self.displaySettings)
+ self.bconfig.pack(side=RIGHT)
self.statusbar = StatusBar(self)
self.statusbar.pack(side=BOTTOM, fill=X)
self.displayAddress()
@@ -1070,7 +1278,7 @@
except AttributeError:
pass
self.statusbar.Set('Tagged address center')
- self.panel = AddressGUI(master=self)
+ self.panel = TMDAAddressGUI(master=self)
self.panel.pack(fill=BOTH, expand=YES)
self.statusbar.progress.Hide()
@@ -1081,7 +1289,7 @@
pass
self.bpending.update()
self.statusbar.Set('Pending messages center')
- self.panel = PendingGUI(master=self, statusbar=self.statusbar)
+ self.panel = TMDAPendingGUI(master=self, statusbar=self.statusbar)
self.panel.pack(fill=BOTH, expand=YES)
self.statusbar.progress.Hide()
@@ -1095,6 +1303,16 @@
self.panel.pack(fill=BOTH, expand=YES)
self.statusbar.progress.Hide()
+ def displaySettings(self):
+ try:
+ self.panel.destroy()
+ except AttributeError:
+ pass
+ self.statusbar.Set('Local configuration', anchor=CENTER)
+ self.panel = TMDASettings(master=self, AppName=self.AppName)
+ self.panel.pack(fill=BOTH, expand=YES)
+ self.statusbar.progress.Hide()
+
def Quit(self):
self.master.destroy()
@@ -1103,15 +1321,41 @@
if using_network:
try:
connectToServer(host=(host, port), auth=(user, passwd))
+ except ProtoError, msg:
+ print msg
+ # try to exit cleanly
+ net_command("exit")
+ sys.exit(1)
except AuthError, msg:
print "Couldn't connect to server %s:%s (reason: %s)" % (host, port, msg)
- net_command("exit")
sys.exit(1)
- if pending_first:
- PendingGUI(root).pack(fill=BOTH, expand=YES)
+ if pending_only:
+ P = TMDAPendingGUI(root)
+ P.pack(fill=BOTH, expand=YES)
+ P.refresh_interval = cfg.get('pending_refresh_interval')
+ elif address_only:
+ TMDAAddressGUI(root).pack(fill=BOTH, expand=YES)
+ elif two_in_one:
+ TMDAAddressGUI(root).pack(fill=BOTH, expand=YES)
+ P = TMDAPendingGUI(root)
+ P.pack(fill=BOTH, expand=YES)
+ P.refresh_interval = cfg.get('pending_refresh_interval')
else:
- TMDAGUI(root, width=800, height=600).pack(fill=BOTH, expand=YES)
+ TMDAGUI(root).pack(fill=BOTH, expand=YES)
+
root.mainloop()
+ if using_network:
+ net_command('exit')
+# sys.exit(0)
+
+cfg = ConfigVar().load()
if __name__ == '__main__':
main()
+
+cfg.save()
+
+
+
+
+
Index: tmda-manager
===================================================================
RCS file: /cvsroot/tmda/tmda/bin/tmda-manager,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- tmda-manager 17 Dec 2002 00:16:09 -0000 1.4
+++ tmda-manager 21 Dec 2002 10:49:28 -0000 1.5
@@ -155,8 +155,11 @@
username = arg
elif opt in ('-R', '--remoteauth'):
Auth.parse_auth_uri(arg)
+ Auth.authtype = 'remote'
elif opt in ('-A', '--authprog'):
Auth.authprog = arg
+ if Auth.authtype != 'remote':
+ Auth.authtype = 'prog'
elif opt in ('-a', '--authfile'):
Auth.authfile = arg
@@ -182,14 +185,16 @@
TMDAShellExit = ''
class TMDAShell(Cmd):
- ProtoVer = '0.1'
- def __init__(self, prompt = '+', stdin = sys.stdin, stdout = sys.stdout, stderr =
sys.stderr):
-# self.use_raw_input = 1
+ ProtoVer = '0.2'
+ def __init__(self, prompt = '+',
+ stdin = sys.stdin,
+ stdout = sys.stdout,
+ stderr = sys.stderr):
sys.stdin = stdin
sys.stdout = stdout
sys.stderr = stderr
self.prompt = prompt
- self.authenticated = 0
+ self.authenticated = not Auth.running_as_root
Cmd.__init__(self)
def Print(self, *strings):
@@ -203,6 +208,7 @@
return self.stdin.readline()
def outputData(self, data):
+ """Output data."""
if type(data) == str:
data = data.split('\n')
d = []
@@ -211,17 +217,28 @@
d.append(subline)
sys.stdout.write(' ' + '\n '.join(d) + '\n')
- def parseArgs(self, args):
+ def parseArgs(self, args, shortopts=[], longopts=[]):
+ """Parse command line arguments."""
pargs = []
+ import getopt
for arg in args.split(' '):
if not arg:
continue
pargs.append(arg)
+ try:
+ opts, args = getopt.getopt(pargs,
+ shortopts,
+ longopts)
+ except getopt.error, msg:
+ self.error(0, "ARG", str(msg))
+ return ([], [])
+ return (opts, args)
+
return pargs
def mainLoop(self):
try:
- self.cmdloop('TMDA Manager v%s\nProtocole v%s' % (Version.TMDA,
self.ProtoVer))
+ self.cmdloop('TMDA Manager v%s\nProtocol v%s' % (Version.TMDA,
+self.ProtoVer))
except KeyboardInterrupt, msg:
raise KeyboardInterrupt, msg
@@ -231,20 +248,26 @@
sys.stderr.write('\n')
def error(self, ret, code, str):
- print "-%s: %s" % (code, str)
+ """Output an error message."""
+ print "-%s: %s" % (code, str.replace('\n', ' '))
return ret
## Cmd functions
- def help_auth(self):
- print "auth userid password"
+ def do_help(self, args):
+ print "Write me!"
def do_nop(self, args):
- self.outputData("%s" % args)
+ """No-OPeration, do nothing but echo args."""
+ self.outputData(args)
+
+ def help_auth(self):
+ print "Write me!"
def do_auth(self, args):
+ """Authenticate."""
if self.authenticated:
return self.error(0, "AUTH", "Already authenticated.")
- args = self.parseArgs(args)
+ (opts, args) = self.parseArgs(args)
try:
self.userid = args[0]
self.password = args[1]
@@ -252,27 +275,32 @@
self.userid = None
self.password = None
return self.error(0, "ARG", "Missing argument.")
- if Auth.run_remoteauth(self.userid, self.password):
+ if Auth.authenticate_plain(self.userid, self.password):
self.authenticated = 1
else:
self.authenticated = 0
return self.error(0, "AUTH", "Invalid credentials.")
if Auth.auth_fork(self.userid):
- return 1
+ sys.exit(0)
return 0
- def help_address(self):
- print "help address"
+ def help_checkaddress(self):
+ print "Write me!"
def do_checkaddress(self, args):
+ """Check a tagged address."""
if not self.authenticated:
return self.error(0, "AUTH", "Please authenticate first.")
- args = self.parseArgs(args)
+ (opts, args) = self.parseArgs(args, 'l', [ 'localtime' ] )
+
from TMDA import Address
- ## FIXME: add support for localtime, eventually
- localtime = None
+ try:
+ opts[0][0]
+ localtime = 1
+ except IndexError:
+ localtime = None
try:
address = args[0]
except IndexError:
@@ -285,6 +313,8 @@
try:
addr = Address.Factory(address)
+ if type(addr) == Address.Address:
+ raise
addr.verify(sender)
self.outputData("STATUS: VALID")
try:
@@ -294,93 +324,184 @@
pass
except Address.AddressError, msg:
self.outputData("STATUS:" + str(msg))
+ except:
+ self.outputData("STATUS: couldn't check the address")
+
+ def help_address(self):
+ print "Write me!"
def do_address(self, args):
+ """Generate a tagged address."""
if not self.authenticated:
return self.error(0, "AUTH", "Please authenticate first.")
- args = self.parseArgs(args)
+ (opts, args) = self.parseArgs(args, 'd:k:s:b',
+ [ 'dated=',
+ 'keyword=',
+ 'sender=',
+ 'base',
+ ] )
from TMDA import Address
- try:
- tag = args[0]
- except IndexError:
- tag = 'dated'
-
- if tag not in ('dated', 'keyword', 'sender'):
- return self.error(0, "ARG", "first argument must be one of 'dated',
'keyword' or 'sender'.")
+ tag = 'dated'
+ date = '5d'
+ param = None
+ for (opt, arg) in opts:
+ if opt in ('-b', '--base'):
+ self.outputData(Address.Address().base())
+ return 0
+ elif opt in ('-d', '--dated'):
+ tag = 'dated'
+ param = arg
+ elif opt in ('-k', '--keyword'):
+ tag = 'keyword'
+ param = arg
+ elif opt in ('-s', '--sender'):
+ tag = 'sender'
+ param = arg
+ elif opt in ('-a', '--address'):
+ address = arg
try:
- arg = args[1]
+ address = args[0]
except IndexError:
- if tag in ('keyword', 'sender'):
- return self.error(0, "ARG", "You must provide a second argument.")
- arg = None
+ address = None
- address = None
+ if param is None:
+ if tag != 'dated':
+ return self.error(0, "ARG", "Missing or malformed parameter.")
+ else:
+ param = date
try:
- tagged_address = Address.Factory(tag = tag).create(address, arg).address
+ tagged_address = Address.Factory(tag = tag).create(address, param).address
except ValueError, msg:
- self.help_address()
- return 0
+ return self.error(0, "UNK", "Unknown error (Address.Factory).")
if not tagged_address:
- self.help_address()
- return 0
+ return self.error(0, "UNK", "Unknown error (Address.Factory).")
self.outputData(tagged_address)
return 0
+ def help_pending(self):
+ print "Write me!"
+
def do_pending(self, args):
+ """List pending message ids."""
if not self.authenticated:
return self.error(0, "AUTH", "Please authenticate first.")
- args = self.parseArgs(args)
+ (opts, args) = self.parseArgs(args, 'qacrdoD:',
+ [ 'queue',
+ 'all',
+ 'confirmed',
+ 'released',
+ 'delivered',
+ 'only',
+ 'descending=',
+ ] )
+ try:
+ (opt, arg) = opts[0]
+ except IndexError:
+ (opt, arg) = ('-o', '')
+ descending = None
+ for (o, a) in opts:
+ if o == '-D' or o == '--descending':
+ if a:
+ descending = 1
+ break
+ descending = 1
from TMDA import Pending
- if not args:
- args = [ 'all' ]
- if args[0] == 'queue':
+ if opt == '-q' or opt == '--queue':
Pending.InteractiveQueue().initQueue().mainLoop()
return 0
- if args[0] == 'all':
- args = Pending.Queue().initQueue().listIds()
- elif args[0] == 'confirmed':
- args = Pending.Queue().initQueue().listConfirmedIds()
- elif args[0] == 'released':
- args = Pending.Queue().initQueue().listReleasedIds()
- elif args[0] == 'delivered':
- args = Pending.Queue().initQueue().listDeliveredIds()
- elif args[0] == 'only':
- args = Pending.Queue().initQueue().listPendingIds()
- self.outputData(args)
+ ids = ''
+ if opt == '-a' or opt == '--all':
+ ids = Pending.Queue(descending=descending).initQueue().listIds()
+ elif opt == '-c' or opt == '--confirmed':
+ ids = Pending.Queue(descending=descending).initQueue().listConfirmedIds()
+ elif opt == '-r' or opt == '--released':
+ ids = Pending.Queue(descending=descending).initQueue().listReleasedIds()
+ elif opt == '-d' or opt == '--delivered':
+ ids = Pending.Queue(descending=descending).initQueue().listDeliveredIds()
+ elif opt == '-o' or opt == '--only':
+ ids = Pending.Queue(descending=descending).initQueue().listPendingIds()
+ if ids:
+ self.outputData(ids)
+ else:
+ self.outputData('nothing'+opt)
return 0
+ def help_message(self):
+ print "Write me!"
+
def do_message(self, args):
+ """Do action on message."""
if not self.authenticated:
return self.error(0, "AUTH", "Please authenticate first.")
- args = self.parseArgs(args)
+ (opts, args) = self.parseArgs(args, 'tsSrdwbD:',
+ [ 'terse',
+ 'summary',
+ 'show',
+ 'release',
+ 'delete',
+ 'whitelist',
+ 'blacklist',
+ 'date=',
+ ] )
+ try:
+ (opt, arg) = opts[0]
+ except IndexError:
+ (opt, arg) = ('-t', '')
+ date = 0
+ for (o, a) in opts:
+ if o == '-D' or o == '--date':
+ if a:
+ date = 1
+ break
from TMDA import Pending
- if args[0] == 'terse' and args[1]:
- for l in Pending.Message(args[1]).initMessage().terse(tsv=0):
+ if not len(args):
+ return self.error(0, 'ARG', 'Missing message id.')
+ if opt == '-t' or opt == '--terse':
+ for l in Pending.Message(args[0]).initMessage().terse(tsv=0, date=date):
self.outputData(l.replace('\n', r'\n'))
- elif args[0] == 'summary' and args[1]:
- self.outputData(Pending.Message(args[1]).initMessage().summary())
- elif args[0] == 'show' and args[1]:
- self.outputData(Pending.Message(args[1]).initMessage().show())
- elif args[0] == 'release' and args[1]:
- Pending.Message(args[1]).initMessage().release()
- elif args[0] == 'delete' and args[1]:
- Pending.Message(args[1]).initMessage().delete()
+ elif opt == '-s' or opt == '--summary':
+ self.outputData(Pending.Message(args[0]).initMessage().summary())
+ elif opt == '-S' or opt == '--show':
+ self.outputData(Pending.Message(args[0]).initMessage().show())
+ elif opt == '-r' or opt == '--release':
+ Pending.Message(args[0]).initMessage().release()
+ elif opt == '-d' or opt == '--delete':
+ Pending.Message(args[0]).initMessage().delete()
+ elif opt == '-w' or opt == '--whitelist':
+ Pending.Message(args[0]).initMessage().whitelist()
+ elif opt == '-b' or opt == '--blacklist':
+ Pending.Message(args[0]).initMessage().blacklist()
return 0
-
+ def do_get(self, args):
+ if not self.authenticated:
+ return self.error(0, "AUTH", "Please authenticate first.")
+ (opts, args) = self.parseArgs(args)
+
+ from TMDA import Defaults
+ res = []
+ if '*' in args:
+ args = dict(Defaults).keys()
+ for a in args:
+ try:
+ res.append('%s=%s' % (a, getattr(Defaults, a)))
+ except AttributeError, msg:
+ pass
+ #self.error(0, 'VAR', '%s: %s' % (a, msg))
+ self.outputData('\n'.join(res))
+ return 0
+
def do_exit(self, args):
- print ' bye.'
+ """Exit the shell."""
+ print '.bye.'
return 1
- def help_EOF(self):
- print "Control-D or exit to quit"
-
- def do_EOF(self, args):
- print 'exit'
- return self.do_exit(args)
+ # aliases on exit
+ do_quit = do_exit
+ do_EOF = do_exit
def connection(hostport):
stdin = sys.stdin
_________________________________________________
tmda-workers mailing list ([EMAIL PROTECTED])
http://tmda.net/lists/listinfo/tmda-workers