summaryrefslogtreecommitdiff
path: root/mailman/attic/bin
diff options
context:
space:
mode:
Diffstat (limited to 'mailman/attic/bin')
-rwxr-xr-xmailman/attic/bin/clone_member219
-rw-r--r--mailman/attic/bin/discard120
-rw-r--r--mailman/attic/bin/fix_url.py93
-rw-r--r--mailman/attic/bin/list_admins101
-rw-r--r--mailman/attic/bin/msgfmt.py203
-rw-r--r--mailman/attic/bin/po2templ.py90
-rw-r--r--mailman/attic/bin/pygettext.py545
-rwxr-xr-xmailman/attic/bin/remove_members186
-rw-r--r--mailman/attic/bin/reset_pw.py83
-rwxr-xr-xmailman/attic/bin/sync_members286
-rw-r--r--mailman/attic/bin/templ2pot.py120
-rwxr-xr-xmailman/attic/bin/transcheck412
12 files changed, 0 insertions, 2458 deletions
diff --git a/mailman/attic/bin/clone_member b/mailman/attic/bin/clone_member
deleted file mode 100755
index 1f2a03aca..000000000
--- a/mailman/attic/bin/clone_member
+++ /dev/null
@@ -1,219 +0,0 @@
-#! @PYTHON@
-#
-# Copyright (C) 1998,1999,2000,2001,2002 by the Free Software Foundation, Inc.
-#
-# 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
-# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
-"""Clone a member address.
-
-Cloning a member address means that a new member will be added who has all the
-same options and passwords as the original member address. Note that this
-operation is fairly trusting of the user who runs it -- it does no
-verification to the new address, it does not send out a welcome message, etc.
-
-The existing member's subscription is usually not modified in any way. If you
-want to remove the old address, use the -r flag. If you also want to change
-any list admin addresses, use the -a flag.
-
-Usage:
- clone_member [options] fromoldaddr tonewaddr
-
-Where:
-
- --listname=listname
- -l listname
- Check and modify only the named mailing lists. If -l is not given,
- then all mailing lists are scanned from the address. Multiple -l
- options can be supplied.
-
- --remove
- -r
- Remove the old address from the mailing list after it's been cloned.
-
- --admin
- -a
- Scan the list admin addresses for the old address, and clone or change
- them too.
-
- --quiet
- -q
- Do the modifications quietly.
-
- --nomodify
- -n
- Print what would be done, but don't actually do it. Inhibits the
- --quiet flag.
-
- --help
- -h
- Print this help message and exit.
-
- fromoldaddr (`from old address') is the old address of the user. tonewaddr
- (`to new address') is the new address of the user.
-
-"""
-
-import sys
-import getopt
-
-import paths
-from Mailman import MailList
-from Mailman import Utils
-from Mailman import Errors
-from Mailman.i18n import _
-
-
-
-def usage(code, msg=''):
- if code:
- fd = sys.stderr
- else:
- fd = sys.stdout
- print >> fd, _(__doc__)
- if msg:
- print >> fd, msg
- sys.exit(code)
-
-
-
-def dolist(mlist, options):
- SPACE = ' '
- if not options.quiet:
- print _('processing mailing list:'), mlist.internal_name()
-
- # scan the list owners. TBD: mlist.owner keys should be lowercase?
- oldowners = mlist.owner[:]
- oldowners.sort()
- if options.admintoo:
- if not options.quiet:
- print _(' scanning list owners:'), SPACE.join(oldowners)
- newowners = {}
- foundp = 0
- for owner in mlist.owner:
- if options.lfromaddr == owner.lower():
- foundp = 1
- if options.remove:
- continue
- newowners[owner] = 1
- if foundp:
- newowners[options.toaddr] = 1
- newowners = newowners.keys()
- newowners.sort()
- if options.modify:
- mlist.owner = newowners
- if not options.quiet:
- if newowners <> oldowners:
- print
- print _(' new list owners:'), SPACE.join(newowners)
- else:
- print _('(no change)')
-
- # see if the fromaddr is a digest member or regular member
- if options.lfromaddr in mlist.getDigestMemberKeys():
- digest = 1
- elif options.lfromaddr in mlist.getRegularMemberKeys():
- digest = 0
- else:
- if not options.quiet:
- print _(' address not found:'), options.fromaddr
- return
-
- # Now change the membership address
- try:
- if options.modify:
- mlist.changeMemberAddress(options.fromaddr, options.toaddr,
- not options.remove)
- if not options.quiet:
- print _(' clone address added:'), options.toaddr
- except Errors.MMAlreadyAMember:
- if not options.quiet:
- print _(' clone address is already a member:'), options.toaddr
-
- if options.remove:
- print _(' original address removed:'), options.fromaddr
-
-
-
-def main():
- # default options
- class Options:
- listnames = None
- remove = 0
- admintoo = 0
- quiet = 0
- modify = 1
-
- # scan sysargs
- try:
- opts, args = getopt.getopt(
- sys.argv[1:], 'arl:qnh',
- ['admin', 'remove', 'listname=', 'quiet', 'nomodify', 'help'])
- except getopt.error, msg:
- usage(1, msg)
-
- options = Options()
- for opt, arg in opts:
- if opt in ('-h', '--help'):
- usage(0)
- elif opt in ('-q', '--quiet'):
- options.quiet = 1
- elif opt in ('-n', '--nomodify'):
- options.modify = 0
- elif opt in ('-a', '--admin'):
- options.admintoo = 1
- elif opt in ('-r', '--remove'):
- options.remove = 1
- elif opt in ('-l', '--listname'):
- if options.listnames is None:
- options.listnames = []
- options.listnames.append(arg.lower())
-
- # further options and argument processing
- if not options.modify:
- options.quiet = 0
-
- if len(args) <> 2:
- usage(1)
- fromaddr = args[0]
- toaddr = args[1]
-
- # validate and normalize the target address
- try:
- Utils.ValidateEmail(toaddr)
- except Errors.EmailAddressError:
- usage(1, _('Not a valid email address: %(toaddr)s'))
- lfromaddr = fromaddr.lower()
- options.toaddr = toaddr
- options.fromaddr = fromaddr
- options.lfromaddr = lfromaddr
-
- if options.listnames is None:
- options.listnames = Utils.list_names()
-
- for listname in options.listnames:
- try:
- mlist = MailList.MailList(listname)
- except Errors.MMListError, e:
- print _('Error opening list "%(listname)s", skipping.\n%(e)s')
- continue
- try:
- dolist(mlist, options)
- finally:
- mlist.Save()
- mlist.Unlock()
-
-
-if __name__ == '__main__':
- main()
diff --git a/mailman/attic/bin/discard b/mailman/attic/bin/discard
deleted file mode 100644
index c30198441..000000000
--- a/mailman/attic/bin/discard
+++ /dev/null
@@ -1,120 +0,0 @@
-#! @PYTHON@
-#
-# Copyright (C) 2003 by the Free Software Foundation, Inc.
-#
-# 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
-# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
-"""Discard held messages.
-
-Usage:
- discard [options] file ...
-
-Options:
- --help / -h
- Print this help message and exit.
-
- --quiet / -q
- Don't print status messages.
-"""
-
-# TODO: add command line arguments for specifying other actions than DISCARD,
-# and also for specifying other __handlepost() arguments, i.e. comment,
-# preserve, forward, addr
-
-import os
-import re
-import sys
-import getopt
-
-import paths
-from Mailman import mm_cfg
-from Mailman.MailList import MailList
-from Mailman.i18n import _
-
-try:
- True, False
-except NameError:
- True = 1
- False = 0
-
-cre = re.compile(r'heldmsg-(?P<listname>.*)-(?P<id>[0-9]+)\.(pck|txt)$')
-
-
-
-def usage(code, msg=''):
- if code:
- fd = sys.stderr
- else:
- fd = sys.stdout
- print >> fd, _(__doc__)
- if msg:
- print >> fd, msg
- sys.exit(code)
-
-
-
-def main():
- try:
- opts, args = getopt.getopt(sys.argv[1:], 'hq', ['help', 'quiet'])
- except getopt.error, msg:
- usage(1, msg)
-
- quiet = False
- for opt, arg in opts:
- if opt in ('-h', '--help'):
- usage(0)
- elif opt in ('-q', '--quiet'):
- quiet = True
-
- files = args
- if not files:
- print _('Nothing to do.')
-
- # Mapping from listnames to sequence of request ids
- discards = {}
-
- # Cruise through all the named files, collating by mailing list. We'll
- # lock the list once, process all holds for that list and move on.
- for f in files:
- basename = os.path.basename(f)
- mo = cre.match(basename)
- if not mo:
- print >> sys.stderr, _('Ignoring non-held message: %(f)s')
- continue
- listname, id = mo.group('listname', 'id')
- try:
- id = int(id)
- except (ValueError, TypeError):
- print >> sys.stderr, _('Ignoring held msg w/bad id: %(f)s')
- continue
- discards.setdefault(listname, []).append(id)
-
- # Now do the discards
- for listname, ids in discards.items():
- mlist = MailList(listname)
- try:
- for id in ids:
- # No comment, no preserve, no forward, no forwarding address
- mlist.HandleRequest(id, mm_cfg.DISCARD, '', False, False, '')
- if not quiet:
- print _('Discarded held msg #%(id)s for list %(listname)s')
- mlist.Save()
- finally:
- mlist.Unlock()
-
-
-
-if __name__ == '__main__':
- main()
diff --git a/mailman/attic/bin/fix_url.py b/mailman/attic/bin/fix_url.py
deleted file mode 100644
index 30618a1a3..000000000
--- a/mailman/attic/bin/fix_url.py
+++ /dev/null
@@ -1,93 +0,0 @@
-#! @PYTHON@
-#
-# Copyright (C) 2001-2009 by the Free Software Foundation, Inc.
-#
-# 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
-# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
-# USA.
-
-"""Reset a list's web_page_url attribute to the default setting.
-
-This script is intended to be run as a bin/withlist script, i.e.
-
-% bin/withlist -l -r fix_url listname [options]
-
-Options:
- -u urlhost
- --urlhost=urlhost
- Look up urlhost in the virtual host table and set the web_page_url and
- host_name attributes of the list to the values found. This
- essentially moves the list from one virtual domain to another.
-
- Without this option, the default web_page_url and host_name values are
- used.
-
- -v / --verbose
- Print what the script is doing.
-
-If run standalone, it prints this help text and exits.
-"""
-
-import sys
-import getopt
-
-import paths
-from Mailman.configuration import config
-from Mailman.i18n import _
-
-
-
-def usage(code, msg=''):
- print _(__doc__.replace('%', '%%'))
- if msg:
- print msg
- sys.exit(code)
-
-
-
-def fix_url(mlist, *args):
- try:
- opts, args = getopt.getopt(args, 'u:v', ['urlhost=', 'verbose'])
- except getopt.error, msg:
- usage(1, msg)
-
- verbose = 0
- urlhost = mailhost = None
- for opt, arg in opts:
- if opt in ('-u', '--urlhost'):
- urlhost = arg
- elif opt in ('-v', '--verbose'):
- verbose = 1
-
- if urlhost:
- web_page_url = config.DEFAULT_URL_PATTERN % urlhost
- mailhost = config.VIRTUAL_HOSTS.get(urlhost.lower(), urlhost)
- else:
- web_page_url = config.DEFAULT_URL_PATTERN % config.DEFAULT_URL_HOST
- mailhost = config.DEFAULT_EMAIL_HOST
-
- if verbose:
- print _('Setting web_page_url to: %(web_page_url)s')
- mlist.web_page_url = web_page_url
- if verbose:
- print _('Setting host_name to: %(mailhost)s')
- mlist.host_name = mailhost
- print _('Saving list')
- mlist.Save()
- mlist.Unlock()
-
-
-
-if __name__ == '__main__':
- usage(0)
diff --git a/mailman/attic/bin/list_admins b/mailman/attic/bin/list_admins
deleted file mode 100644
index c628a42dc..000000000
--- a/mailman/attic/bin/list_admins
+++ /dev/null
@@ -1,101 +0,0 @@
-#! @PYTHON@
-#
-# Copyright (C) 2001,2002 by the Free Software Foundation, Inc.
-#
-# 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
-# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
-"""List all the owners of a mailing list.
-
-Usage: %(program)s [options] listname ...
-
-Where:
-
- --all-vhost=vhost
- -v=vhost
- List the owners of all the mailing lists for the given virtual host.
-
- --all
- -a
- List the owners of all the mailing lists on this system.
-
- --help
- -h
- Print this help message and exit.
-
-`listname' is the name of the mailing list to print the owners of. You can
-have more than one named list on the command line.
-"""
-
-import sys
-import getopt
-
-import paths
-from Mailman import MailList, Utils
-from Mailman import Errors
-from Mailman.i18n import _
-
-COMMASPACE = ', '
-
-program = sys.argv[0]
-
-
-
-def usage(code, msg=''):
- if code:
- fd = sys.stderr
- else:
- fd = sys.stdout
- print >> fd, _(__doc__)
- if msg:
- print >> fd, msg
- sys.exit(code)
-
-
-
-def main():
- try:
- opts, args = getopt.getopt(sys.argv[1:], 'hv:a',
- ['help', 'all-vhost=', 'all'])
- except getopt.error, msg:
- usage(1, msg)
-
- listnames = args
- vhost = None
- for opt, arg in opts:
- if opt in ('-h', '--help'):
- usage(0)
- elif opt in ('-a', '--all'):
- listnames = Utils.list_names()
- elif opt in ('-v', '--all-vhost'):
- listnames = Utils.list_names()
- vhost = arg
-
- for listname in listnames:
- try:
- mlist = MailList.MailList(listname, lock=0)
- except Errors.MMListError, e:
- print _('No such list: %(listname)s')
- continue
-
- if vhost and vhost <> mlist.host_name:
- continue
-
- owners = COMMASPACE.join(mlist.owner)
- print _('List: %(listname)s, \tOwners: %(owners)s')
-
-
-
-if __name__ == '__main__':
- main()
diff --git a/mailman/attic/bin/msgfmt.py b/mailman/attic/bin/msgfmt.py
deleted file mode 100644
index 8a2d4e66e..000000000
--- a/mailman/attic/bin/msgfmt.py
+++ /dev/null
@@ -1,203 +0,0 @@
-#! /usr/bin/env python
-# -*- coding: iso-8859-1 -*-
-# Written by Martin v. Löwis <loewis@informatik.hu-berlin.de>
-
-"""Generate binary message catalog from textual translation description.
-
-This program converts a textual Uniforum-style message catalog (.po file) into
-a binary GNU catalog (.mo file). This is essentially the same function as the
-GNU msgfmt program, however, it is a simpler implementation.
-
-Usage: msgfmt.py [OPTIONS] filename.po
-
-Options:
- -o file
- --output-file=file
- Specify the output file to write to. If omitted, output will go to a
- file named filename.mo (based off the input file name).
-
- -h
- --help
- Print this message and exit.
-
- -V
- --version
- Display version information and exit.
-"""
-
-import sys
-import os
-import getopt
-import struct
-import array
-
-__version__ = "1.1"
-
-MESSAGES = {}
-
-
-
-def usage(code, msg=''):
- print >> sys.stderr, __doc__
- if msg:
- print >> sys.stderr, msg
- sys.exit(code)
-
-
-
-def add(id, str, fuzzy):
- "Add a non-fuzzy translation to the dictionary."
- global MESSAGES
- if not fuzzy and str:
- MESSAGES[id] = str
-
-
-
-def generate():
- "Return the generated output."
- global MESSAGES
- keys = MESSAGES.keys()
- # the keys are sorted in the .mo file
- keys.sort()
- offsets = []
- ids = strs = ''
- for id in keys:
- # For each string, we need size and file offset. Each string is NUL
- # terminated; the NUL does not count into the size.
- offsets.append((len(ids), len(id), len(strs), len(MESSAGES[id])))
- ids += id + '\0'
- strs += MESSAGES[id] + '\0'
- output = ''
- # The header is 7 32-bit unsigned integers. We don't use hash tables, so
- # the keys start right after the index tables.
- # translated string.
- keystart = 7*4+16*len(keys)
- # and the values start after the keys
- valuestart = keystart + len(ids)
- koffsets = []
- voffsets = []
- # The string table first has the list of keys, then the list of values.
- # Each entry has first the size of the string, then the file offset.
- for o1, l1, o2, l2 in offsets:
- koffsets += [l1, o1+keystart]
- voffsets += [l2, o2+valuestart]
- offsets = koffsets + voffsets
- output = struct.pack("Iiiiiii",
- 0x950412deL, # Magic
- 0, # Version
- len(keys), # # of entries
- 7*4, # start of key index
- 7*4+len(keys)*8, # start of value index
- 0, 0) # size and offset of hash table
- output += array.array("i", offsets).tostring()
- output += ids
- output += strs
- return output
-
-
-
-def make(filename, outfile):
- ID = 1
- STR = 2
-
- # Compute .mo name from .po name and arguments
- if filename.endswith('.po'):
- infile = filename
- else:
- infile = filename + '.po'
- if outfile is None:
- outfile = os.path.splitext(infile)[0] + '.mo'
-
- try:
- lines = open(infile).readlines()
- except IOError, msg:
- print >> sys.stderr, msg
- sys.exit(1)
-
- section = None
- fuzzy = 0
-
- # Parse the catalog
- lno = 0
- for l in lines:
- lno += 1
- # If we get a comment line after a msgstr, this is a new entry
- if l[0] == '#' and section == STR:
- add(msgid, msgstr, fuzzy)
- section = None
- fuzzy = 0
- # Record a fuzzy mark
- if l[:2] == '#,' and l.find('fuzzy'):
- fuzzy = 1
- # Skip comments
- if l[0] == '#':
- continue
- # Now we are in a msgid section, output previous section
- if l.startswith('msgid'):
- if section == STR:
- add(msgid, msgstr, fuzzy)
- section = ID
- l = l[5:]
- msgid = msgstr = ''
- # Now we are in a msgstr section
- elif l.startswith('msgstr'):
- section = STR
- l = l[6:]
- # Skip empty lines
- l = l.strip()
- if not l:
- continue
- # XXX: Does this always follow Python escape semantics?
- l = eval(l)
- if section == ID:
- msgid += l
- elif section == STR:
- msgstr += l
- else:
- print >> sys.stderr, 'Syntax error on %s:%d' % (infile, lno), \
- 'before:'
- print >> sys.stderr, l
- sys.exit(1)
- # Add last entry
- if section == STR:
- add(msgid, msgstr, fuzzy)
-
- # Compute output
- output = generate()
-
- try:
- open(outfile,"wb").write(output)
- except IOError,msg:
- print >> sys.stderr, msg
-
-
-
-def main():
- try:
- opts, args = getopt.getopt(sys.argv[1:], 'hVo:',
- ['help', 'version', 'output-file='])
- except getopt.error, msg:
- usage(1, msg)
-
- outfile = None
- # parse options
- for opt, arg in opts:
- if opt in ('-h', '--help'):
- usage(0)
- elif opt in ('-V', '--version'):
- print >> sys.stderr, "msgfmt.py", __version__
- sys.exit(0)
- elif opt in ('-o', '--output-file'):
- outfile = arg
- # do it
- if not args:
- print >> sys.stderr, 'No input file given'
- print >> sys.stderr, "Try `msgfmt --help' for more information."
- return
-
- for filename in args:
- make(filename, outfile)
-
-
-if __name__ == '__main__':
- main()
diff --git a/mailman/attic/bin/po2templ.py b/mailman/attic/bin/po2templ.py
deleted file mode 100644
index 86eae96b9..000000000
--- a/mailman/attic/bin/po2templ.py
+++ /dev/null
@@ -1,90 +0,0 @@
-#! @PYTHON@
-#
-# Copyright (C) 2005-2009 by the Free Software Foundation, Inc.
-#
-# 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
-# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
-# USA.
-
-# Author: Tokio Kikuchi <tkikuchi@is.kochi-u.ac.jp>
-
-
-"""po2templ.py
-
-Extract templates from language po file.
-
-Usage: po2templ.py languages
-"""
-
-import re
-import sys
-
-cre = re.compile('^#:\s*templates/en/(?P<filename>.*?):1')
-
-
-
-def do_lang(lang):
- in_template = False
- in_msg = False
- msgstr = ''
- fp = file('messages/%s/LC_MESSAGES/mailman.po' % lang)
- try:
- for line in fp:
- m = cre.search(line)
- if m:
- in_template = True
- in_msg = False
- filename = m.group('filename')
- outfilename = 'templates/%s/%s' % (lang, filename)
- continue
- if in_template and line.startswith('#,'):
- if line.strip() == '#, fuzzy':
- in_template = False
- continue
- if in_template and line.startswith('msgstr'):
- line = line[7:]
- in_msg = True
- if in_msg:
- if not line.strip():
- in_template = False
- in_msg = False
- if len(msgstr) > 1 and outfilename:
- # exclude no translation ... 1 is for LF only
- outfile = file(outfilename, 'w')
- try:
- outfile.write(msgstr)
- outfile.write('\n')
- finally:
- outfile.close()
- outfilename = ''
- msgstr = ''
- continue
- msgstr += eval(line)
- finally:
- fp.close()
- if len(msgstr) > 1 and outfilename:
- # flush remaining msgstr (last template file)
- outfile = file(outfilename, 'w')
- try:
- outfile.write(msgstr)
- outfile.write('\n')
- finally:
- outfile.close()
-
-
-
-if __name__ == '__main__':
- langs = sys.argv[1:]
- for lang in langs:
- do_lang(lang)
diff --git a/mailman/attic/bin/pygettext.py b/mailman/attic/bin/pygettext.py
deleted file mode 100644
index 84421ee8c..000000000
--- a/mailman/attic/bin/pygettext.py
+++ /dev/null
@@ -1,545 +0,0 @@
-#! @PYTHON@
-# Originally written by Barry Warsaw <barry@zope.com>
-#
-# Minimally patched to make it even more xgettext compatible
-# by Peter Funk <pf@artcom-gmbh.de>
-
-"""pygettext -- Python equivalent of xgettext(1)
-
-Many systems (Solaris, Linux, Gnu) provide extensive tools that ease the
-internationalization of C programs. Most of these tools are independent of
-the programming language and can be used from within Python programs. Martin
-von Loewis' work[1] helps considerably in this regard.
-
-There's one problem though; xgettext is the program that scans source code
-looking for message strings, but it groks only C (or C++). Python introduces
-a few wrinkles, such as dual quoting characters, triple quoted strings, and
-raw strings. xgettext understands none of this.
-
-Enter pygettext, which uses Python's standard tokenize module to scan Python
-source code, generating .pot files identical to what GNU xgettext[2] generates
-for C and C++ code. From there, the standard GNU tools can be used.
-
-A word about marking Python strings as candidates for translation. GNU
-xgettext recognizes the following keywords: gettext, dgettext, dcgettext, and
-gettext_noop. But those can be a lot of text to include all over your code.
-C and C++ have a trick: they use the C preprocessor. Most internationalized C
-source includes a #define for gettext() to _() so that what has to be written
-in the source is much less. Thus these are both translatable strings:
-
- gettext("Translatable String")
- _("Translatable String")
-
-Python of course has no preprocessor so this doesn't work so well. Thus,
-pygettext searches only for _() by default, but see the -k/--keyword flag
-below for how to augment this.
-
- [1] http://www.python.org/workshops/1997-10/proceedings/loewis.html
- [2] http://www.gnu.org/software/gettext/gettext.html
-
-NOTE: pygettext attempts to be option and feature compatible with GNU xgettext
-where ever possible. However some options are still missing or are not fully
-implemented. Also, xgettext's use of command line switches with option
-arguments is broken, and in these cases, pygettext just defines additional
-switches.
-
-Usage: pygettext [options] inputfile ...
-
-Options:
-
- -a
- --extract-all
- Extract all strings.
-
- -d name
- --default-domain=name
- Rename the default output file from messages.pot to name.pot.
-
- -E
- --escape
- Replace non-ASCII characters with octal escape sequences.
-
- -D
- --docstrings
- Extract module, class, method, and function docstrings. These do not
- need to be wrapped in _() markers, and in fact cannot be for Python to
- consider them docstrings. (See also the -X option).
-
- -h
- --help
- Print this help message and exit.
-
- -k word
- --keyword=word
- Keywords to look for in addition to the default set, which are:
- %(DEFAULTKEYWORDS)s
-
- You can have multiple -k flags on the command line.
-
- -K
- --no-default-keywords
- Disable the default set of keywords (see above). Any keywords
- explicitly added with the -k/--keyword option are still recognized.
-
- --no-location
- Do not write filename/lineno location comments.
-
- -n
- --add-location
- Write filename/lineno location comments indicating where each
- extracted string is found in the source. These lines appear before
- each msgid. The style of comments is controlled by the -S/--style
- option. This is the default.
-
- -o filename
- --output=filename
- Rename the default output file from messages.pot to filename. If
- filename is `-' then the output is sent to standard out.
-
- -p dir
- --output-dir=dir
- Output files will be placed in directory dir.
-
- -S stylename
- --style stylename
- Specify which style to use for location comments. Two styles are
- supported:
-
- Solaris # File: filename, line: line-number
- GNU #: filename:line
-
- The style name is case insensitive. GNU style is the default.
-
- -v
- --verbose
- Print the names of the files being processed.
-
- -V
- --version
- Print the version of pygettext and exit.
-
- -w columns
- --width=columns
- Set width of output to columns.
-
- -x filename
- --exclude-file=filename
- Specify a file that contains a list of strings that are not be
- extracted from the input files. Each string to be excluded must
- appear on a line by itself in the file.
-
- -X filename
- --no-docstrings=filename
- Specify a file that contains a list of files (one per line) that
- should not have their docstrings extracted. This is only useful in
- conjunction with the -D option above.
-
-If `inputfile' is -, standard input is read.
-"""
-
-import os
-import sys
-import time
-import getopt
-import tokenize
-import operator
-
-# for selftesting
-try:
- import fintl
- _ = fintl.gettext
-except ImportError:
- def _(s): return s
-
-__version__ = '1.4'
-
-default_keywords = ['_']
-DEFAULTKEYWORDS = ', '.join(default_keywords)
-
-EMPTYSTRING = ''
-
-
-
-# The normal pot-file header. msgmerge and Emacs's po-mode work better if it's
-# there.
-pot_header = _('''\
-# SOME DESCRIPTIVE TITLE.
-# Copyright (C) YEAR ORGANIZATION
-# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
-#
-msgid ""
-msgstr ""
-"Project-Id-Version: PACKAGE VERSION\\n"
-"POT-Creation-Date: %(time)s\\n"
-"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n"
-"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n"
-"Language-Team: LANGUAGE <LL@li.org>\\n"
-"MIME-Version: 1.0\\n"
-"Content-Type: text/plain; charset=CHARSET\\n"
-"Content-Transfer-Encoding: ENCODING\\n"
-"Generated-By: pygettext.py %(version)s\\n"
-
-''')
-
-
-def usage(code, msg=''):
- if code:
- fd = sys.stderr
- else:
- fd = sys.stdout
- print >> fd, _(__doc__) % globals()
- if msg:
- print >> fd, msg
- sys.exit(code)
-
-
-
-escapes = []
-
-def make_escapes(pass_iso8859):
- global escapes
- if pass_iso8859:
- # Allow iso-8859 characters to pass through so that e.g. 'msgid
- # "H[o-umlaut]he"' would result not result in 'msgid "H\366he"'.
- # Otherwise we escape any character outside the 32..126 range.
- mod = 128
- else:
- mod = 256
- for i in range(256):
- if 32 <= (i % mod) <= 126:
- escapes.append(chr(i))
- else:
- escapes.append("\\%03o" % i)
- escapes[ord('\\')] = '\\\\'
- escapes[ord('\t')] = '\\t'
- escapes[ord('\r')] = '\\r'
- escapes[ord('\n')] = '\\n'
- escapes[ord('\"')] = '\\"'
-
-
-def escape(s):
- global escapes
- s = list(s)
- for i in range(len(s)):
- s[i] = escapes[ord(s[i])]
- return EMPTYSTRING.join(s)
-
-
-def safe_eval(s):
- # unwrap quotes, safely
- return eval(s, {'__builtins__':{}}, {})
-
-
-def normalize(s):
- # This converts the various Python string types into a format that is
- # appropriate for .po files, namely much closer to C style.
- lines = s.split('\n')
- if len(lines) == 1:
- s = '"' + escape(s) + '"'
- else:
- if not lines[-1]:
- del lines[-1]
- lines[-1] = lines[-1] + '\n'
- for i in range(len(lines)):
- lines[i] = escape(lines[i])
- lineterm = '\\n"\n"'
- s = '""\n"' + lineterm.join(lines) + '"'
- return s
-
-
-
-class TokenEater:
- def __init__(self, options):
- self.__options = options
- self.__messages = {}
- self.__state = self.__waiting
- self.__data = []
- self.__lineno = -1
- self.__freshmodule = 1
- self.__curfile = None
-
- def __call__(self, ttype, tstring, stup, etup, line):
- # dispatch
-## import token
-## print >> sys.stderr, 'ttype:', token.tok_name[ttype], \
-## 'tstring:', tstring
- self.__state(ttype, tstring, stup[0])
-
- def __waiting(self, ttype, tstring, lineno):
- opts = self.__options
- # Do docstring extractions, if enabled
- if opts.docstrings and not opts.nodocstrings.get(self.__curfile):
- # module docstring?
- if self.__freshmodule:
- if ttype == tokenize.STRING:
- self.__addentry(safe_eval(tstring), lineno, isdocstring=1)
- self.__freshmodule = 0
- elif ttype not in (tokenize.COMMENT, tokenize.NL):
- self.__freshmodule = 0
- return
- # class docstring?
- if ttype == tokenize.NAME and tstring in ('class', 'def'):
- self.__state = self.__suiteseen
- return
- if ttype == tokenize.NAME and tstring in opts.keywords:
- self.__state = self.__keywordseen
-
- def __suiteseen(self, ttype, tstring, lineno):
- # ignore anything until we see the colon
- if ttype == tokenize.OP and tstring == ':':
- self.__state = self.__suitedocstring
-
- def __suitedocstring(self, ttype, tstring, lineno):
- # ignore any intervening noise
- if ttype == tokenize.STRING:
- self.__addentry(safe_eval(tstring), lineno, isdocstring=1)
- self.__state = self.__waiting
- elif ttype not in (tokenize.NEWLINE, tokenize.INDENT,
- tokenize.COMMENT):
- # there was no class docstring
- self.__state = self.__waiting
-
- def __keywordseen(self, ttype, tstring, lineno):
- if ttype == tokenize.OP and tstring == '(':
- self.__data = []
- self.__lineno = lineno
- self.__state = self.__openseen
- else:
- self.__state = self.__waiting
-
- def __openseen(self, ttype, tstring, lineno):
- if ttype == tokenize.OP and tstring == ')':
- # We've seen the last of the translatable strings. Record the
- # line number of the first line of the strings and update the list
- # of messages seen. Reset state for the next batch. If there
- # were no strings inside _(), then just ignore this entry.
- if self.__data:
- self.__addentry(EMPTYSTRING.join(self.__data))
- self.__state = self.__waiting
- elif ttype == tokenize.STRING:
- self.__data.append(safe_eval(tstring))
- # TBD: should we warn if we seen anything else?
-
- def __addentry(self, msg, lineno=None, isdocstring=0):
- if lineno is None:
- lineno = self.__lineno
- if not msg in self.__options.toexclude:
- entry = (self.__curfile, lineno)
- self.__messages.setdefault(msg, {})[entry] = isdocstring
-
- def set_filename(self, filename):
- self.__curfile = filename
- self.__freshmodule = 1
-
- def write(self, fp):
- options = self.__options
- timestamp = time.ctime(time.time())
- # The time stamp in the header doesn't have the same format as that
- # generated by xgettext...
- print >> fp, pot_header % {'time': timestamp, 'version': __version__}
- # Sort the entries. First sort each particular entry's keys, then
- # sort all the entries by their first item.
- reverse = {}
- for k, v in self.__messages.items():
- keys = v.keys()
- keys.sort()
- reverse.setdefault(tuple(keys), []).append((k, v))
- rkeys = reverse.keys()
- rkeys.sort()
- for rkey in rkeys:
- rentries = reverse[rkey]
- rentries.sort()
- for k, v in rentries:
- isdocstring = 0
- # If the entry was gleaned out of a docstring, then add a
- # comment stating so. This is to aid translators who may wish
- # to skip translating some unimportant docstrings.
- if reduce(operator.__add__, v.values()):
- isdocstring = 1
- # k is the message string, v is a dictionary-set of (filename,
- # lineno) tuples. We want to sort the entries in v first by
- # file name and then by line number.
- v = v.keys()
- v.sort()
- if not options.writelocations:
- pass
- # location comments are different b/w Solaris and GNU:
- elif options.locationstyle == options.SOLARIS:
- for filename, lineno in v:
- d = {'filename': filename, 'lineno': lineno}
- print >>fp, _(
- '# File: %(filename)s, line: %(lineno)d') % d
- elif options.locationstyle == options.GNU:
- # fit as many locations on one line, as long as the
- # resulting line length doesn't exceeds 'options.width'
- locline = '#:'
- for filename, lineno in v:
- d = {'filename': filename, 'lineno': lineno}
- s = _(' %(filename)s:%(lineno)d') % d
- if len(locline) + len(s) <= options.width:
- locline = locline + s
- else:
- print >> fp, locline
- locline = "#:" + s
- if len(locline) > 2:
- print >> fp, locline
- if isdocstring:
- print >> fp, '#, docstring'
- print >> fp, 'msgid', normalize(k)
- print >> fp, 'msgstr ""\n'
-
-
-
-def main():
- global default_keywords
- try:
- opts, args = getopt.getopt(
- sys.argv[1:],
- 'ad:DEhk:Kno:p:S:Vvw:x:X:',
- ['extract-all', 'default-domain=', 'escape', 'help',
- 'keyword=', 'no-default-keywords',
- 'add-location', 'no-location', 'output=', 'output-dir=',
- 'style=', 'verbose', 'version', 'width=', 'exclude-file=',
- 'docstrings', 'no-docstrings',
- ])
- except getopt.error, msg:
- usage(1, msg)
-
- # for holding option values
- class Options:
- # constants
- GNU = 1
- SOLARIS = 2
- # defaults
- extractall = 0 # FIXME: currently this option has no effect at all.
- escape = 0
- keywords = []
- outpath = ''
- outfile = 'messages.pot'
- writelocations = 1
- locationstyle = GNU
- verbose = 0
- width = 78
- excludefilename = ''
- docstrings = 0
- nodocstrings = {}
-
- options = Options()
- locations = {'gnu' : options.GNU,
- 'solaris' : options.SOLARIS,
- }
-
- # parse options
- for opt, arg in opts:
- if opt in ('-h', '--help'):
- usage(0)
- elif opt in ('-a', '--extract-all'):
- options.extractall = 1
- elif opt in ('-d', '--default-domain'):
- options.outfile = arg + '.pot'
- elif opt in ('-E', '--escape'):
- options.escape = 1
- elif opt in ('-D', '--docstrings'):
- options.docstrings = 1
- elif opt in ('-k', '--keyword'):
- options.keywords.append(arg)
- elif opt in ('-K', '--no-default-keywords'):
- default_keywords = []
- elif opt in ('-n', '--add-location'):
- options.writelocations = 1
- elif opt in ('--no-location',):
- options.writelocations = 0
- elif opt in ('-S', '--style'):
- options.locationstyle = locations.get(arg.lower())
- if options.locationstyle is None:
- usage(1, _('Invalid value for --style: %s') % arg)
- elif opt in ('-o', '--output'):
- options.outfile = arg
- elif opt in ('-p', '--output-dir'):
- options.outpath = arg
- elif opt in ('-v', '--verbose'):
- options.verbose = 1
- elif opt in ('-V', '--version'):
- print _('pygettext.py (xgettext for Python) %s') % __version__
- sys.exit(0)
- elif opt in ('-w', '--width'):
- try:
- options.width = int(arg)
- except ValueError:
- usage(1, _('--width argument must be an integer: %s') % arg)
- elif opt in ('-x', '--exclude-file'):
- options.excludefilename = arg
- elif opt in ('-X', '--no-docstrings'):
- fp = open(arg)
- try:
- while 1:
- line = fp.readline()
- if not line:
- break
- options.nodocstrings[line[:-1]] = 1
- finally:
- fp.close()
-
- # calculate escapes
- make_escapes(options.escape)
-
- # calculate all keywords
- options.keywords.extend(default_keywords)
-
- # initialize list of strings to exclude
- if options.excludefilename:
- try:
- fp = open(options.excludefilename)
- options.toexclude = fp.readlines()
- fp.close()
- except IOError:
- print >> sys.stderr, _(
- "Can't read --exclude-file: %s") % options.excludefilename
- sys.exit(1)
- else:
- options.toexclude = []
-
- # slurp through all the files
- eater = TokenEater(options)
- for filename in args:
- if filename == '-':
- if options.verbose:
- print _('Reading standard input')
- fp = sys.stdin
- closep = 0
- else:
- if options.verbose:
- print _('Working on %s') % filename
- fp = open(filename)
- closep = 1
- try:
- eater.set_filename(filename)
- try:
- tokenize.tokenize(fp.readline, eater)
- except tokenize.TokenError, e:
- print >> sys.stderr, '%s: %s, line %d, column %d' % (
- e[0], filename, e[1][0], e[1][1])
- finally:
- if closep:
- fp.close()
-
- # write the output
- if options.outfile == '-':
- fp = sys.stdout
- closep = 0
- else:
- if options.outpath:
- options.outfile = os.path.join(options.outpath, options.outfile)
- fp = open(options.outfile, 'w')
- closep = 1
- try:
- eater.write(fp)
- finally:
- if closep:
- fp.close()
-
-
-if __name__ == '__main__':
- main()
- # some more test strings
- _(u'a unicode string')
diff --git a/mailman/attic/bin/remove_members b/mailman/attic/bin/remove_members
deleted file mode 100755
index a7b4ebb47..000000000
--- a/mailman/attic/bin/remove_members
+++ /dev/null
@@ -1,186 +0,0 @@
-#! @PYTHON@
-#
-# Copyright (C) 1998-2005 by the Free Software Foundation, Inc.
-#
-# 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
-# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
-# USA.
-
-"""Remove members from a list.
-
-Usage:
- remove_members [options] [listname] [addr1 ...]
-
-Options:
-
- --file=file
- -f file
- Remove member addresses found in the given file. If file is
- `-', read stdin.
-
- --all
- -a
- Remove all members of the mailing list.
- (mutually exclusive with --fromall)
-
- --fromall
- Removes the given addresses from all the lists on this system
- regardless of virtual domains if you have any. This option cannot be
- used -a/--all. Also, you should not specify a listname when using
- this option.
-
- --nouserack
- -n
- Don't send the user acknowledgements. If not specified, the list
- default value is used.
-
- --noadminack
- -N
- Don't send the admin acknowledgements. If not specified, the list
- default value is used.
-
- --help
- -h
- Print this help message and exit.
-
- listname is the name of the mailing list to use.
-
- addr1 ... are additional addresses to remove.
-"""
-
-import sys
-import getopt
-
-import paths
-from Mailman import MailList
-from Mailman import Utils
-from Mailman import Errors
-from Mailman.i18n import _
-
-try:
- True, False
-except NameError:
- True = 1
- False = 0
-
-
-
-def usage(code, msg=''):
- if code:
- fd = sys.stderr
- else:
- fd = sys.stdout
- print >> fd, _(__doc__)
- if msg:
- print >> fd, msg
- sys.exit(code)
-
-
-def ReadFile(filename):
- lines = []
- if filename == "-":
- fp = sys.stdin
- closep = False
- else:
- fp = open(filename)
- closep = True
- lines = filter(None, [line.strip() for line in fp.readlines()])
- if closep:
- fp.close()
- return lines
-
-
-
-def main():
- try:
- opts, args = getopt.getopt(
- sys.argv[1:], 'naf:hN',
- ['all', 'fromall', 'file=', 'help', 'nouserack', 'noadminack'])
- except getopt.error, msg:
- usage(1, msg)
-
- filename = None
- all = False
- alllists = False
- # None means use list default
- userack = None
- admin_notif = None
-
- for opt, arg in opts:
- if opt in ('-h', '--help'):
- usage(0)
- elif opt in ('-f', '--file'):
- filename = arg
- elif opt in ('-a', '--all'):
- all = True
- elif opt == '--fromall':
- alllists = True
- elif opt in ('-n', '--nouserack'):
- userack = False
- elif opt in ('-N', '--noadminack'):
- admin_notif = False
-
- if len(args) < 1 and not (filename and alllists):
- usage(1)
-
- # You probably don't want to delete all the users of all the lists -- Marc
- if all and alllists:
- usage(1)
-
- if alllists:
- addresses = args
- else:
- listname = args[0].lower().strip()
- addresses = args[1:]
-
- if alllists:
- listnames = Utils.list_names()
- else:
- listnames = [listname]
-
- if filename:
- try:
- addresses = addresses + ReadFile(filename)
- except IOError:
- print _('Could not open file for reading: %(filename)s.')
-
- for listname in listnames:
- try:
- # open locked
- mlist = MailList.MailList(listname)
- except Errors.MMListError:
- print _('Error opening list %(listname)s... skipping.')
- continue
-
- if all:
- addresses = mlist.getMembers()
-
- try:
- for addr in addresses:
- if not mlist.isMember(addr):
- if not alllists:
- print _('No such member: %(addr)s')
- continue
- mlist.ApprovedDeleteMember(addr, 'bin/remove_members',
- admin_notif, userack)
- if alllists:
- print _("User `%(addr)s' removed from list: %(listname)s.")
- mlist.Save()
- finally:
- mlist.Unlock()
-
-
-
-if __name__ == '__main__':
- main()
diff --git a/mailman/attic/bin/reset_pw.py b/mailman/attic/bin/reset_pw.py
deleted file mode 100644
index 453c8b849..000000000
--- a/mailman/attic/bin/reset_pw.py
+++ /dev/null
@@ -1,83 +0,0 @@
-#! @PYTHON@
-#
-# Copyright (C) 2004-2009 by the Free Software Foundation, Inc.
-#
-# 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
-# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
-# Inspired by Florian Weimer.
-
-"""Reset the passwords for members of a mailing list.
-
-This script resets all the passwords of a mailing list's members. It can also
-be used to reset the lists of all members of all mailing lists, but it is your
-responsibility to let the users know that their passwords have been changed.
-
-This script is intended to be run as a bin/withlist script, i.e.
-
-% bin/withlist -l -r reset_pw listname [options]
-
-Options:
- -v / --verbose
- Print what the script is doing.
-"""
-
-import sys
-import getopt
-
-import paths
-from Mailman import Utils
-from Mailman.i18n import _
-
-
-
-def usage(code, msg=''):
- if code:
- fd = sys.stderr
- else:
- fd = sys.stdout
- print >> fd, _(__doc__.replace('%', '%%'))
- if msg:
- print >> fd, msg
- sys.exit(code)
-
-
-
-def reset_pw(mlist, *args):
- try:
- opts, args = getopt.getopt(args, 'v', ['verbose'])
- except getopt.error, msg:
- usage(1, msg)
-
- verbose = False
- for opt, args in opts:
- if opt in ('-v', '--verbose'):
- verbose = True
-
- listname = mlist.internal_name()
- if verbose:
- print _('Changing passwords for list: %(listname)s')
-
- for member in mlist.getMembers():
- randompw = Utils.MakeRandomPassword()
- mlist.setMemberPassword(member, randompw)
- if verbose:
- print _('New password for member %(member)40s: %(randompw)s')
-
- mlist.Save()
-
-
-
-if __name__ == '__main__':
- usage(0)
diff --git a/mailman/attic/bin/sync_members b/mailman/attic/bin/sync_members
deleted file mode 100755
index 4a21624c1..000000000
--- a/mailman/attic/bin/sync_members
+++ /dev/null
@@ -1,286 +0,0 @@
-#! @PYTHON@
-#
-# Copyright (C) 1998-2003 by the Free Software Foundation, Inc.
-#
-# 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
-# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
-"""Synchronize a mailing list's membership with a flat file.
-
-This script is useful if you have a Mailman mailing list and a sendmail
-:include: style list of addresses (also as is used in Majordomo). For every
-address in the file that does not appear in the mailing list, the address is
-added. For every address in the mailing list that does not appear in the
-file, the address is removed. Other options control what happens when an
-address is added or removed.
-
-Usage: %(PROGRAM)s [options] -f file listname
-
-Where `options' are:
-
- --no-change
- -n
- Don't actually make the changes. Instead, print out what would be
- done to the list.
-
- --welcome-msg[=<yes|no>]
- -w[=<yes|no>]
- Sets whether or not to send the newly added members a welcome
- message, overriding whatever the list's `send_welcome_msg' setting
- is. With -w=yes or -w, the welcome message is sent. With -w=no, no
- message is sent.
-
- --goodbye-msg[=<yes|no>]
- -g[=<yes|no>]
- Sets whether or not to send the goodbye message to removed members,
- overriding whatever the list's `send_goodbye_msg' setting is. With
- -g=yes or -g, the goodbye message is sent. With -g=no, no message is
- sent.
-
- --digest[=<yes|no>]
- -d[=<yes|no>]
- Selects whether to make newly added members receive messages in
- digests. With -d=yes or -d, they become digest members. With -d=no
- (or if no -d option given) they are added as regular members.
-
- --notifyadmin[=<yes|no>]
- -a[=<yes|no>]
- Specifies whether the admin should be notified for each subscription
- or unsubscription. If you're adding a lot of addresses, you
- definitely want to turn this off! With -a=yes or -a, the admin is
- notified. With -a=no, the admin is not notified. With no -a option,
- the default for the list is used.
-
- --file <filename | ->
- -f <filename | ->
- This option is required. It specifies the flat file to synchronize
- against. Email addresses must appear one per line. If filename is
- `-' then stdin is used.
-
- --help
- -h
- Print this message.
-
- listname
- Required. This specifies the list to synchronize.
-"""
-
-import sys
-
-import paths
-# Import this /after/ paths so that the sys.path is properly hacked
-import email.Utils
-
-from Mailman import MailList
-from Mailman import Errors
-from Mailman import Utils
-from Mailman.UserDesc import UserDesc
-from Mailman.i18n import _
-
-
-
-PROGRAM = sys.argv[0]
-
-def usage(code, msg=''):
- if code:
- fd = sys.stderr
- else:
- fd = sys.stdout
- print >> fd, _(__doc__)
- if msg:
- print >> fd, msg
- sys.exit(code)
-
-
-
-def yesno(opt):
- i = opt.find('=')
- yesno = opt[i+1:].lower()
- if yesno in ('y', 'yes'):
- return 1
- elif yesno in ('n', 'no'):
- return 0
- else:
- usage(1, _('Bad choice: %(yesno)s'))
- # no return
-
-
-def main():
- dryrun = 0
- digest = 0
- welcome = None
- goodbye = None
- filename = None
- listname = None
- notifyadmin = None
-
- # TBD: can't use getopt with this command line syntax, which is broken and
- # should be changed to be getopt compatible.
- i = 1
- while i < len(sys.argv):
- opt = sys.argv[i]
- if opt in ('-h', '--help'):
- usage(0)
- elif opt in ('-n', '--no-change'):
- dryrun = 1
- i += 1
- print _('Dry run mode')
- elif opt in ('-d', '--digest'):
- digest = 1
- i += 1
- elif opt.startswith('-d=') or opt.startswith('--digest='):
- digest = yesno(opt)
- i += 1
- elif opt in ('-w', '--welcome-msg'):
- welcome = 1
- i += 1
- elif opt.startswith('-w=') or opt.startswith('--welcome-msg='):
- welcome = yesno(opt)
- i += 1
- elif opt in ('-g', '--goodbye-msg'):
- goodbye = 1
- i += 1
- elif opt.startswith('-g=') or opt.startswith('--goodbye-msg='):
- goodbye = yesno(opt)
- i += 1
- elif opt in ('-f', '--file'):
- if filename is not None:
- usage(1, _('Only one -f switch allowed'))
- try:
- filename = sys.argv[i+1]
- except IndexError:
- usage(1, _('No argument to -f given'))
- i += 2
- elif opt in ('-a', '--notifyadmin'):
- notifyadmin = 1
- i += 1
- elif opt.startswith('-a=') or opt.startswith('--notifyadmin='):
- notifyadmin = yesno(opt)
- i += 1
- elif opt[0] == '-':
- usage(1, _('Illegal option: %(opt)s'))
- else:
- try:
- listname = sys.argv[i].lower()
- i += 1
- except IndexError:
- usage(1, _('No listname given'))
- break
-
- if listname is None or filename is None:
- usage(1, _('Must have a listname and a filename'))
-
- # read the list of addresses to sync to from the file
- if filename == '-':
- filemembers = sys.stdin.readlines()
- else:
- try:
- fp = open(filename)
- except IOError, (code, msg):
- usage(1, _('Cannot read address file: %(filename)s: %(msg)s'))
- try:
- filemembers = fp.readlines()
- finally:
- fp.close()
-
- # strip out lines we don't care about, they are comments (# in first
- # non-whitespace) or are blank
- for i in range(len(filemembers)-1, -1, -1):
- addr = filemembers[i].strip()
- if addr == '' or addr[:1] == '#':
- del filemembers[i]
- print _('Ignore : %(addr)30s')
-
- # first filter out any invalid addresses
- filemembers = email.Utils.getaddresses(filemembers)
- invalid = 0
- for name, addr in filemembers:
- try:
- Utils.ValidateEmail(addr)
- except Errors.EmailAddressError:
- print _('Invalid : %(addr)30s')
- invalid = 1
- if invalid:
- print _('You must fix the preceding invalid addresses first.')
- sys.exit(1)
-
- # get the locked list object
- try:
- mlist = MailList.MailList(listname)
- except Errors.MMListError, e:
- print _('No such list: %(listname)s')
- sys.exit(1)
-
- try:
- # Get the list of addresses currently subscribed
- addrs = {}
- needsadding = {}
- matches = {}
- for addr in mlist.getMemberCPAddresses(mlist.getMembers()):
- addrs[addr.lower()] = addr
-
- for name, addr in filemembers:
- # Any address found in the file that is also in the list can be
- # ignored. If not found in the list, it must be added later.
- laddr = addr.lower()
- if addrs.has_key(laddr):
- del addrs[laddr]
- matches[laddr] = 1
- elif not matches.has_key(laddr):
- needsadding[laddr] = (name, addr)
-
- if not needsadding and not addrs:
- print _('Nothing to do.')
- sys.exit(0)
-
- enc = sys.getdefaultencoding()
- # addrs contains now all the addresses that need removing
- for laddr, (name, addr) in needsadding.items():
- pw = Utils.MakeRandomPassword()
- # should not already be subscribed, otherwise our test above is
- # broken. Bogosity is if the address is listed in the file more
- # than once. Second and subsequent ones trigger an
- # MMAlreadyAMember error. Just catch it and go on.
- userdesc = UserDesc(addr, name, pw, digest)
- try:
- if not dryrun:
- mlist.ApprovedAddMember(userdesc, welcome, notifyadmin)
- s = email.Utils.formataddr((name, addr)).encode(enc, 'replace')
- print _('Added : %(s)s')
- except Errors.MMAlreadyAMember:
- pass
-
- for laddr, addr in addrs.items():
- # Should be a member, otherwise our test above is broken
- name = mlist.getMemberName(laddr) or ''
- if not dryrun:
- try:
- mlist.ApprovedDeleteMember(addr, admin_notif=notifyadmin,
- userack=goodbye)
- except Errors.NotAMemberError:
- # This can happen if the address is illegal (i.e. can't be
- # parsed by email.Utils.parseaddr()) but for legacy
- # reasons is in the database. Use a lower level remove to
- # get rid of this member's entry
- mlist.removeMember(addr)
- s = email.Utils.formataddr((name, addr)).encode(enc, 'replace')
- print _('Removed: %(s)s')
-
- mlist.Save()
- finally:
- mlist.Unlock()
-
-
-if __name__ == '__main__':
- main()
diff --git a/mailman/attic/bin/templ2pot.py b/mailman/attic/bin/templ2pot.py
deleted file mode 100644
index 0253cc2cd..000000000
--- a/mailman/attic/bin/templ2pot.py
+++ /dev/null
@@ -1,120 +0,0 @@
-#! @PYTHON@
-# Code stolen from pygettext.py
-# by Tokio Kikuchi <tkikuchi@is.kochi-u.ac.jp>
-
-"""templ2pot.py -- convert mailman template (en) to pot format.
-
-Usage: templ2pot.py inputfile ...
-
-Options:
-
- -h, --help
-
-Inputfiles are english templates. Outputs are written to stdout.
-"""
-
-import sys
-import getopt
-
-
-
-try:
- import paths
- from Mailman.i18n import _
-except ImportError:
- def _(s): return s
-
-EMPTYSTRING = ''
-
-
-
-def usage(code, msg=''):
- if code:
- fd = sys.stderr
- else:
- fd = sys.stdout
- print >> fd, _(__doc__) % globals()
- if msg:
- print >> fd, msg
- sys.exit(code)
-
-
-
-escapes = []
-
-def make_escapes(pass_iso8859):
- global escapes
- if pass_iso8859:
- # Allow iso-8859 characters to pass through so that e.g. 'msgid
- # "H[o-umlaut]he"' would result not result in 'msgid "H\366he"'.
- # Otherwise we escape any character outside the 32..126 range.
- mod = 128
- else:
- mod = 256
- for i in range(256):
- if 32 <= (i % mod) <= 126:
- escapes.append(chr(i))
- else:
- escapes.append("\\%03o" % i)
- escapes[ord('\\')] = '\\\\'
- escapes[ord('\t')] = '\\t'
- escapes[ord('\r')] = '\\r'
- escapes[ord('\n')] = '\\n'
- escapes[ord('\"')] = '\\"'
-
-
-def escape(s):
- global escapes
- s = list(s)
- for i in range(len(s)):
- s[i] = escapes[ord(s[i])]
- return EMPTYSTRING.join(s)
-
-
-def normalize(s):
- # This converts the various Python string types into a format that is
- # appropriate for .po files, namely much closer to C style.
- lines = s.splitlines()
- if len(lines) == 1:
- s = '"' + escape(s) + '"'
- else:
- if not lines[-1]:
- del lines[-1]
- lines[-1] = lines[-1] + '\n'
- for i in range(len(lines)):
- lines[i] = escape(lines[i])
- lineterm = '\\n"\n"'
- s = '""\n"' + lineterm.join(lines) + '"'
- return s
-
-
-
-def main():
- try:
- opts, args = getopt.getopt(
- sys.argv[1:],
- 'h',
- ['help',]
- )
- except getopt.error, msg:
- usage(1, msg)
-
- # parse options
- for opt, arg in opts:
- if opt in ('-h', '--help'):
- usage(0)
-
- # calculate escapes
- make_escapes(0)
-
- for filename in args:
- print '#: %s:1' % filename
- s = file(filename).read()
- print '#, template'
- print 'msgid', normalize(s)
- print 'msgstr ""\n'
-
-
-
-if __name__ == '__main__':
- main()
diff --git a/mailman/attic/bin/transcheck b/mailman/attic/bin/transcheck
deleted file mode 100755
index 73910e771..000000000
--- a/mailman/attic/bin/transcheck
+++ /dev/null
@@ -1,412 +0,0 @@
-#! @PYTHON@
-#
-# transcheck - (c) 2002 by Simone Piunno <pioppo@ferrara.linux.it>
-#
-# This program is free software; you can redistribute it and/or modify it
-# under the terms of the version 2.0 of the GNU General Public License as
-# published by the Free Software Foundation.
-#
-# 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.,
-# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
-"""
-Check a given Mailman translation, making sure that variables and
-tags referenced in translation are the same variables and tags in
-the original templates and catalog.
-
-Usage:
-
-cd $MAILMAN_DIR
-%(program)s [-q] <lang>
-
-Where <lang> is your country code (e.g. 'it' for Italy) and -q is
-to ask for a brief summary.
-"""
-
-import sys
-import re
-import os
-import getopt
-
-import paths
-from Mailman.i18n import _
-
-program = sys.argv[0]
-
-
-
-def usage(code, msg=''):
- if code:
- fd = sys.stderr
- else:
- fd = sys.stdout
- print >> fd, _(__doc__)
- if msg:
- print >> fd, msg
- sys.exit(code)
-
-
-
-class TransChecker:
- "check a translation comparing with the original string"
- def __init__(self, regexp, escaped=None):
- self.dict = {}
- self.errs = []
- self.regexp = re.compile(regexp)
- self.escaped = None
- if escaped:
- self.escaped = re.compile(escaped)
-
- def checkin(self, string):
- "scan a string from the original file"
- for key in self.regexp.findall(string):
- if self.escaped and self.escaped.match(key):
- continue
- if self.dict.has_key(key):
- self.dict[key] += 1
- else:
- self.dict[key] = 1
-
- def checkout(self, string):
- "scan a translated string"
- for key in self.regexp.findall(string):
- if self.escaped and self.escaped.match(key):
- continue
- if self.dict.has_key(key):
- self.dict[key] -= 1
- else:
- self.errs.append(
- "%(key)s was not found" %
- { 'key' : key }
- )
-
- def computeErrors(self):
- "check for differences between checked in and checked out"
- for key in self.dict.keys():
- if self.dict[key] < 0:
- self.errs.append(
- "Too much %(key)s" %
- { 'key' : key }
- )
- if self.dict[key] > 0:
- self.errs.append(
- "Too few %(key)s" %
- { 'key' : key }
- )
- return self.errs
-
- def status(self):
- if self.errs:
- return "FAILED"
- else:
- return "OK"
-
- def errorsAsString(self):
- msg = ""
- for err in self.errs:
- msg += " - %(err)s" % { 'err': err }
- return msg
-
- def reset(self):
- self.dict = {}
- self.errs = []
-
-
-
-class POParser:
- "parse a .po file extracting msgids and msgstrs"
- def __init__(self, filename=""):
- self.status = 0
- self.files = []
- self.msgid = ""
- self.msgstr = ""
- self.line = 1
- self.f = None
- self.esc = { "n": "\n", "r": "\r", "t": "\t" }
- if filename:
- self.f = open(filename)
-
- def open(self, filename):
- self.f = open(filename)
-
- def close(self):
- self.f.close()
-
- def parse(self):
- """States table for the finite-states-machine parser:
- 0 idle
- 1 filename-or-comment
- 2 msgid
- 3 msgstr
- 4 end
- """
- # each time we can safely re-initialize those vars
- self.files = []
- self.msgid = ""
- self.msgstr = ""
-
-
- # can't continue if status == 4, this is a dead status
- if self.status == 4:
- return 0
-
- while 1:
- # continue scanning, char-by-char
- c = self.f.read(1)
- if not c:
- # EOF -> maybe we have a msgstr to save?
- self.status = 4
- if self.msgstr:
- return 1
- else:
- return 0
-
- # keep the line count up-to-date
- if c == "\n":
- self.line += 1
-
- # a pound was detected the previous char...
- if self.status == 1:
- if c == ":":
- # was a line of filenames
- row = self.f.readline()
- self.files += row.split()
- self.line += 1
- elif c == "\n":
- # was a single pount on the line
- pass
- else:
- # was a comment... discard
- self.f.readline()
- self.line += 1
- # in every case, we switch to idle status
- self.status = 0;
- continue
-
- # in idle status we search for a '#' or for a 'm'
- if self.status == 0:
- if c == "#":
- # this could be a comment or a filename
- self.status = 1;
- continue
- elif c == "m":
- # this should be a msgid start...
- s = self.f.read(4)
- assert s == "sgid"
- # so now we search for a '"'
- self.status = 2
- continue
- # in idle only those other chars are possibile
- assert c in [ "\n", " ", "\t" ]
-
- # searching for the msgid string
- if self.status == 2:
- if c == "\n":
- # a double LF is not possible here
- c = self.f.read(1)
- assert c != "\n"
- if c == "\"":
- # ok, this is the start of the string,
- # now search for the end
- while 1:
- c = self.f.read(1)
- if not c:
- # EOF, bailout
- self.status = 4
- return 0
- if c == "\\":
- # a quoted char...
- c = self.f.read(1)
- if self.esc.has_key(c):
- self.msgid += self.esc[c]
- else:
- self.msgid += c
- continue
- if c == "\"":
- # end of string found
- break
- # a normal char, add it
- self.msgid += c
- if c == "m":
- # this should be a msgstr identifier
- s = self.f.read(5)
- assert s == "sgstr"
- # ok, now search for the msgstr string
- self.status = 3
-
- # searching for the msgstr string
- if self.status == 3:
- if c == "\n":
- # a double LF is the end of the msgstr!
- c = self.f.read(1)
- if c == "\n":
- # ok, time to go idle and return
- self.status = 0
- self.line += 1
- return 1
- if c == "\"":
- # start of string found
- while 1:
- c = self.f.read(1)
- if not c:
- # EOF, bail out
- self.status = 4
- return 1
- if c == "\\":
- # a quoted char...
- c = self.f.read(1)
- if self.esc.has_key(c):
- self.msgid += self.esc[c]
- else:
- self.msgid += c
- continue
- if c == "\"":
- # end of string
- break
- # a normal char, add it
- self.msgstr += c
-
-
-
-
-def check_file(translatedFile, originalFile, html=0, quiet=0):
- """check a translated template against the original one
- search also <MM-*> tags if html is not zero"""
-
- if html:
- c = TransChecker("(%%|%\([^)]+\)[0-9]*[sd]|</?MM-[^>]+>)", "^%%$")
- else:
- c = TransChecker("(%%|%\([^)]+\)[0-9]*[sd])", "^%%$")
-
- try:
- f = open(originalFile)
- except IOError:
- if not quiet:
- print " - Can'open original file " + originalFile
- return 1
-
- while 1:
- line = f.readline()
- if not line: break
- c.checkin(line)
-
- f.close()
-
- try:
- f = open(translatedFile)
- except IOError:
- if not quiet:
- print " - Can'open translated file " + translatedFile
- return 1
-
- while 1:
- line = f.readline()
- if not line: break
- c.checkout(line)
-
- f.close()
-
- n = 0
- msg = ""
- for desc in c.computeErrors():
- n +=1
- if not quiet:
- print " - %(desc)s" % { 'desc': desc }
- return n
-
-
-
-def check_po(file, quiet=0):
- "scan the po file comparing msgids with msgstrs"
- n = 0
- p = POParser(file)
- c = TransChecker("(%%|%\([^)]+\)[0-9]*[sdu]|%[0-9]*[sdu])", "^%%$")
- while p.parse():
- if p.msgstr:
- c.reset()
- c.checkin(p.msgid)
- c.checkout(p.msgstr)
- for desc in c.computeErrors():
- n += 1
- if not quiet:
- print " - near line %(line)d %(file)s: %(desc)s" % {
- 'line': p.line,
- 'file': p.files,
- 'desc': desc
- }
- p.close()
- return n
-
-
-def main():
- try:
- opts, args = getopt.getopt(sys.argv[1:], 'qh', ['quiet', 'help'])
- except getopt.error, msg:
- usage(1, msg)
-
- quiet = 0
- for opt, arg in opts:
- if opt in ('-h', '--help'):
- usage(0)
- elif opt in ('-q', '--quiet'):
- quiet = 1
-
- if len(args) <> 1:
- usage(1)
-
- lang = args[0]
-
- isHtml = re.compile("\.html$");
- isTxt = re.compile("\.txt$");
-
- numerrors = 0
- numfiles = 0
- try:
- files = os.listdir("templates/" + lang + "/")
- except:
- print "can't open templates/%s/" % lang
- for file in files:
- fileEN = "templates/en/" + file
- fileIT = "templates/" + lang + "/" + file
- errlist = []
- if isHtml.search(file):
- if not quiet:
- print "HTML checking " + fileIT + "... "
- n = check_file(fileIT, fileEN, html=1, quiet=quiet)
- if n:
- numerrors += n
- numfiles += 1
- elif isTxt.search(file):
- if not quiet:
- print "TXT checking " + fileIT + "... "
- n = check_file(fileIT, fileEN, html=0, quiet=quiet)
- if n:
- numerrors += n
- numfiles += 1
-
- else:
- continue
-
- file = "messages/" + lang + "/LC_MESSAGES/mailman.po"
- if not quiet:
- print "PO checking " + file + "... "
- n = check_po(file, quiet=quiet)
- if n:
- numerrors += n
- numfiles += 1
-
- if quiet:
- print "%(errs)u warnings in %(files)u files" % {
- 'errs': numerrors,
- 'files': numfiles
- }
-
-
-if __name__ == '__main__':
- main()