diff options
-rw-r--r-- | Mailman/Cgi/subscribe.py | 2 | ||||
-rw-r--r-- | Mailman/Commands/cmd_confirm.py | 2 | ||||
-rw-r--r-- | Mailman/Handlers/ToDigest.py | 39 | ||||
-rw-r--r-- | Mailman/Queue/CommandRunner.py | 25 | ||||
-rw-r--r-- | Mailman/Utils.py | 90 | ||||
-rw-r--r-- | README-I18N.en | 86 | ||||
-rw-r--r-- | README.POSTFIX | 3 | ||||
-rw-r--r-- | bin/arch | 2 | ||||
-rw-r--r-- | messages/es/LC_MESSAGES/mailman.mo | bin | 318303 -> 318304 bytes | |||
-rw-r--r-- | messages/es/LC_MESSAGES/mailman.po | 2 |
10 files changed, 175 insertions, 76 deletions
diff --git a/Mailman/Cgi/subscribe.py b/Mailman/Cgi/subscribe.py index d0a477d7..8ae9564f 100644 --- a/Mailman/Cgi/subscribe.py +++ b/Mailman/Cgi/subscribe.py @@ -117,12 +117,10 @@ def process_form(mlist, doc, cgidata, lang): remote = os.environ.get('REMOTE_HOST', os.environ.get('REMOTE_ADDR', 'unidentified origin')) - # Was an attempt made to subscribe the list to itself? if email == mlist.GetListEmail(): syslog('mischief', 'Attempt to self subscribe %s: %s', email, remote) results.append(_('You may not subscribe a list to itself!')) - # If the user did not supply a password, generate one for him password = cgidata.getvalue('pw') confirmed = cgidata.getvalue('pw-conf') diff --git a/Mailman/Commands/cmd_confirm.py b/Mailman/Commands/cmd_confirm.py index f93e7b9b..e66c52b5 100644 --- a/Mailman/Commands/cmd_confirm.py +++ b/Mailman/Commands/cmd_confirm.py @@ -61,7 +61,7 @@ Your request has been forwarded to the list moderator for approval.""")) except Errors.NotAMemberError: # They've already been unsubscribed res.results.append(_("""\ -You are not current a member. Have you already unsubscribed or changed +You are not currently a member. Have you already unsubscribed or changed your email address?""")) except Errors.HostileSubscriptionError: res.results.append(_("""\ diff --git a/Mailman/Handlers/ToDigest.py b/Mailman/Handlers/ToDigest.py index 79090051..3506beaa 100644 --- a/Mailman/Handlers/ToDigest.py +++ b/Mailman/Handlers/ToDigest.py @@ -55,6 +55,12 @@ _ = i18n._ UEMPTYSTRING = u'' EMPTYSTRING = '' +try: + True, False +except NameError: + True = 1 + False = 0 + def process(mlist, msg, msgdata): @@ -68,7 +74,7 @@ def process(mlist, msg, msgdata): finally: os.umask(omask) g = Generator(mboxfp) - g.flatten(msg, unixfrom=1) + g.flatten(msg, unixfrom=True) # Calculate the current size of the accumulation file. This will not tell # us exactly how big the MIME, rfc1153, or any other generated digest # message will be, but it's the most easily available metric to decide @@ -88,30 +94,30 @@ def process(mlist, msg, msgdata): def send_digests(mlist, mboxfp): # Set the digest volume and time if mlist.digest_last_sent_at: - bump = 0 + bump = False # See if we should bump the digest volume number timetup = time.localtime(mlist.digest_last_sent_at) now = time.localtime(time.time()) freq = mlist.digest_volume_frequency if freq == 0 and timetup[0] < now[0]: # Yearly - bump = 1 + bump = True elif freq == 1 and timetup[1] <> now[1]: # Monthly, but we take a cheap way to calculate this. We assume # that the clock isn't going to be reset backwards. - bump = 1 + bump = True elif freq == 2 and (timetup[1] % 4 <> now[1] % 4): # Quarterly, same caveat - bump = 1 + bump = True elif freq == 3: # Once again, take a cheap way of calculating this weeknum_last = int(time.strftime('%W', timetup)) weeknum_now = int(time.strftime('%W', now)) if weeknum_now > weeknum_last or timetup[0] > now[0]: - bump = 1 + bump = True elif freq == 4 and timetup[7] <> now[7]: # Daily - bump = 1 + bump = True if bump: mlist.bump_digest_volume() mlist.digest_last_sent_at = time.time() @@ -230,11 +236,11 @@ def send_i18n_digests(mlist, mboxfp): else: slines[-1] += username # Add this subject to the accumulating topics - first = 1 + first = True for line in slines: if first: print >> toc, ' ', line - first = 0 + first = False else: print >> toc, ' ', line.lstrip() # We do not want all the headers of the original message to leak @@ -247,7 +253,7 @@ def send_i18n_digests(mlist, mboxfp): all_keepers = {} for header in (mm_cfg.MIME_DIGEST_KEEP_HEADERS + mm_cfg.PLAIN_DIGEST_KEEP_HEADERS): - all_keepers[header] = 1 + all_keepers[header] = True all_keepers = all_keepers.keys() for keep in all_keepers: keeper[keep] = msg.get_all(keep, []) @@ -281,13 +287,13 @@ def send_i18n_digests(mlist, mboxfp): # Now go through and add each message mimedigest = MIMEBase('multipart', 'digest') mimemsg.attach(mimedigest) - first = 1 + first = True for msg in messages: # MIME mimedigest.attach(MIMEMessage(msg)) # rfc1153 if first: - first = 0 + first = False else: print >> plainmsg, separator30 print >> plainmsg @@ -300,7 +306,10 @@ def send_i18n_digests(mlist, mboxfp): uh = '\n\t'.join(uh.split('\n')) print >> plainmsg, uh print >> plainmsg - print >> plainmsg, msg.get_payload(decode=1) + payload = msg.get_payload(decode=True) + print >> plainmsg, payload + if not payload.endswith('\n'): + print >> plainmsg # Now add the footer if mlist.digest_footer: footertxt = decorate(mlist, mlist.digest_footer, _('digest footer')) @@ -356,13 +365,13 @@ def send_i18n_digests(mlist, mboxfp): virginq.enqueue(mimemsg, recips=mimerecips, listname=mlist.internal_name(), - isdigest=1) + isdigest=True) # RFC 1153 rfc1153msg.set_payload(plainmsg.getvalue(), lcset) virginq.enqueue(rfc1153msg, recips=plainrecips, listname=mlist.internal_name(), - isdigest=1) + isdigest=True) diff --git a/Mailman/Queue/CommandRunner.py b/Mailman/Queue/CommandRunner.py index 5bc1599b..524ea575 100644 --- a/Mailman/Queue/CommandRunner.py +++ b/Mailman/Queue/CommandRunner.py @@ -26,8 +26,8 @@ # BAW: get rid of this when we Python 2.2 is a minimum requirement. from __future__ import nested_scopes -import sys import re +import sys from types import StringType, UnicodeType from Mailman import mm_cfg @@ -39,12 +39,19 @@ from Mailman.Queue.Runner import Runner from Mailman.Logging.Syslog import syslog from Mailman import LockFile +from email.Header import decode_header, make_header, Header from email.MIMEText import MIMEText from email.MIMEMessage import MIMEMessage from email.Iterators import typed_subpart_iterator NL = '\n' +try: + True, False +except NameError: + True = 1 + False = 0 + class Results: @@ -61,9 +68,13 @@ class Results: self.ignored = [] self.lineno = 0 self.subjcmdretried = 0 - self.respond = 1 + self.respond = True + # Extract the subject header and do RFC 2047 decoding. Note that + # Python 2.1's unicode() builtin doesn't call obj.__unicode__(). + subj = msg.get('subject', '') + subj = make_header(decode_header(subj)).__unicode__() # Always process the Subject: header first - self.commands.append(msg.get('subject', '')) + self.commands.append(subj) # Find the first text/plain part part = None for part in typed_subpart_iterator(msg, 'text', 'plain'): @@ -86,7 +97,7 @@ class Results: def process(self): # Now, process each line until we find an error. The first # non-command line found stops processing. - stop = 0 + stop = False for line in self.commands: if line and line.strip(): args = line.split() @@ -195,14 +206,14 @@ class CommandRunner(Runner): if ack <> 'yes' and precedence in ('bulk', 'junk', 'list'): syslog('vette', 'Precedence: %s message discarded by: %s', precedence, mlist.GetRequestEmail()) - return 0 + return False # Do replybot for commands mlist.Load() Replybot.process(mlist, msg, msgdata) if mlist.autorespond_requests == 1: syslog('vette', 'replied and discard') # w/discard - return 0 + return False # Now craft the response res = Results(mlist, msg, msgdata) # BAW: Not all the functions of this qrunner require the list to be @@ -212,7 +223,7 @@ class CommandRunner(Runner): mlist.Lock(timeout=mm_cfg.LIST_LOCK_TIMEOUT) except LockFile.TimeOutError: # Oh well, try again later - return 1 + return True # This message will have been delivered to one of mylist-request, # mylist-join, or mylist-leave, and the message metadata will contain # a key to which one was used. diff --git a/Mailman/Utils.py b/Mailman/Utils.py index 57c87c36..ceb63f66 100644 --- a/Mailman/Utils.py +++ b/Mailman/Utils.py @@ -50,6 +50,12 @@ from Mailman import Errors from Mailman import Site from Mailman.SafeDict import SafeDict +try: + True, False +except NameError: + True = 1 + False = 0 + EMPTYSTRING = '' NL = '\n' DOT = '.' @@ -74,8 +80,8 @@ def list_exists(listname): for ext in ('.pck', '.pck.last', '.db', '.db.last'): dbfile = os.path.join(basepath, 'config' + ext) if os.path.exists(dbfile): - return 1 - return 0 + return True + return False def list_names(): @@ -86,7 +92,7 @@ def list_names(): # a much more naive implementation than say, Emacs's fill-paragraph! -def wrap(text, column=70, honor_leading_ws=1): +def wrap(text, column=70, honor_leading_ws=True): """Wrap and fill the text to the specified column. Wrapping is always in effect, although if it is not possible to wrap a @@ -103,15 +109,15 @@ def wrap(text, column=70, honor_leading_ws=1): for para in paras: # fill lines = [] - fillprev = 0 + fillprev = False for line in para.split(NL): if not line: lines.append(line) continue if honor_leading_ws and line[0] in whitespace: - fillthis = 0 + fillthis = False else: - fillthis = 1 + fillthis = True if fillprev and fillthis: # if the previous line should be filled, then just append a # single space, and the rest of the current line @@ -130,33 +136,33 @@ def wrap(text, column=70, honor_leading_ws=1): bol = column # find the last whitespace character while bol > 0 and text[bol] not in whitespace: - bol = bol - 1 + bol -= 1 # now find the last non-whitespace character eol = bol while eol > 0 and text[eol] in whitespace: - eol = eol - 1 + eol -= 1 # watch out for text that's longer than the column width if eol == 0: # break on whitespace after column eol = column while eol < len(text) and \ text[eol] not in whitespace: - eol = eol + 1 + eol += 1 bol = eol while bol < len(text) and \ text[bol] in whitespace: - bol = bol + 1 - bol = bol - 1 + bol += 1 + bol -= 1 line = text[:eol+1] + '\n' # find the next non-whitespace character - bol = bol + 1 + bol += 1 while bol < len(text) and text[bol] in whitespace: - bol = bol + 1 + bol += 1 text = text[bol:] - wrapped = wrapped + line - wrapped = wrapped + '\n' + wrapped += line + wrapped += '\n' # end while text - wrapped = wrapped + '\n' + wrapped += '\n' # end for text in lines # the last two newlines are bogus return wrapped[:-2] @@ -218,7 +224,7 @@ def GetPathPieces(envar='PATH_INFO'): -def ScriptURL(target, web_page_url=None, absolute=0): +def ScriptURL(target, web_page_url=None, absolute=False): """target - scriptname only, nothing extra web_page_url - the list's configvar of the same name absolute - a flag which if set, generates an absolute url @@ -267,15 +273,15 @@ def GetPossibleMatchingAddrs(name): -def List2Dict(list, foldcase=0): +def List2Dict(L, foldcase=False): """Return a dict keyed by the entries in the list passed to it.""" d = {} if foldcase: - for i in list: - d[i.lower()] = 1 + for i in L: + d[i.lower()] = True else: - for i in list: - d[i] = 1 + for i in L: + d[i] = True return d @@ -293,7 +299,7 @@ del c, v def MakeRandomPassword(length=6): syls = [] - while len(syls)*2 < length: + while len(syls) * 2 < length: syls.append(random.choice(_syllables)) return EMPTYSTRING.join(syls)[:length] @@ -302,20 +308,22 @@ def GetRandomSeed(): chr2 = int(random.random() * 52) def mkletter(c): if 0 <= c < 26: - c = c + 65 + c += 65 if 26 <= c < 52: - c = c - 26 + 97 + #c = c - 26 + 97 + c += 71 return c return "%c%c" % tuple(map(mkletter, (chr1, chr2))) -def set_global_password(pw, siteadmin=1): +def set_global_password(pw, siteadmin=True): if siteadmin: filename = mm_cfg.SITE_PW_FILE else: filename = mm_cfg.LISTCREATOR_PW_FILE - omask = os.umask(026) # rw-r----- + # rw-r----- + omask = os.umask(026) try: fp = open(filename, 'w') fp.write(sha.new(pw).hexdigest() + '\n') @@ -324,7 +332,7 @@ def set_global_password(pw, siteadmin=1): os.umask(omask) -def get_global_password(siteadmin=1): +def get_global_password(siteadmin=True): if siteadmin: filename = mm_cfg.SITE_PW_FILE else: @@ -340,7 +348,7 @@ def get_global_password(siteadmin=1): return challenge -def check_global_password(response, siteadmin=1): +def check_global_password(response, siteadmin=True): challenge = get_global_password(siteadmin) if challenge is None: return None @@ -355,7 +363,7 @@ def websafe(s): # Just changing these two functions should be enough to control the way # that email address obscuring is handled. -def ObscureEmail(addr, for_text=0): +def ObscureEmail(addr, for_text=False): """Make email address unrecognizable to web spiders, but invertable. When for_text option is set (not default), make a sentence fragment @@ -373,7 +381,7 @@ def UnobscureEmail(addr): -def maketext(templatefile, dict=None, raw=0, lang=None, mlist=None): +def maketext(templatefile, dict=None, raw=False, lang=None, mlist=None): # Make some text from a template file. The order of searches depends on # whether mlist and lang are provided. Once the templatefile is found, # string substitution is performed by interpolation in `dict'. If `raw' @@ -508,12 +516,12 @@ def is_administrivia(msg): if line.strip(): linecnt += 1 if linecnt > mm_cfg.DEFAULT_MAIL_COMMANDS_MAX_LINES: - return 0 + return False lines.append(line) bodytext = NL.join(lines) # See if the body text has only one word, and that word is administrivia if ADMINDATA.has_key(bodytext.strip().lower()): - return 1 + return True # Look at the first N lines and see if there is any administrivia on the # line. BAW: N is currently hardcoded to 5. str-ify the Subject: header # because it may be an email.Header.Header instance rather than a string. @@ -532,12 +540,12 @@ def is_administrivia(msg): # here. if words[0] == 'set' and words[2] not in ('on', 'off'): continue - return 1 - return 0 + return True + return False -def GetRequestURI(fallback=None, escape=1): +def GetRequestURI(fallback=None, escape=True): """Return the full virtual path this CGI script was invoked with. Newer web servers seems to supply this info in the REQUEST_URI @@ -563,7 +571,7 @@ def GetRequestURI(fallback=None, escape=1): # Wait on a dictionary of child pids -def reap(kids, func=None, once=0): +def reap(kids, func=None, once=False): while kids: if func: func() @@ -685,7 +693,7 @@ def dollar_identifiers(s): """Return the set (dictionary) of identifiers found in a $-string.""" d = {} for name in filter(None, [b or c or None for a, b, c in dre.findall(s)]): - d[name] = 1 + d[name] = True return d @@ -693,7 +701,7 @@ def percent_identifiers(s): """Return the set (dictionary) of identifiers found in a %-string.""" d = {} for name in cre.findall(s): - d[name] = 1 + d[name] = True return d @@ -708,7 +716,7 @@ def canonstr(s, lang=None): newparts.append(chr(i)) else: newparts.append(unichr(i)) - while 1: + while True: newparts.append(parts.pop(0)) if not parts: break @@ -732,7 +740,7 @@ def canonstr(s, lang=None): # English (us-ascii). This seems like a practical compromise so that # non-ASCII characters in names can be used in English lists w/o having to # change the global charset for English from us-ascii (which I - # superstitiously think my have unintended consequences). + # superstitiously think may have unintended consequences). if lang is None: charset = 'iso-8859-1' else: diff --git a/README-I18N.en b/README-I18N.en index 59b20965..b3efcd64 100644 --- a/README-I18N.en +++ b/README-I18N.en @@ -1,5 +1,5 @@ Mailman - The GNU Mailing List Management System -Copyright (C) 2001,2002 by the Free Software Foundation, Inc. +Copyright (C) 2001-2003 by the Free Software Foundation, Inc. 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA @@ -29,11 +29,13 @@ ADDING NEW TRANSLATIONS translation for the mythical language "Fredonia" which has the official language code of "xx". - You should also see + You should see - http://www.list.org/MM21/i18n.html + http://www.list.org/i18n.html - for more information on internationalizing Mailman. + for more information on internationalizing Mailman. Also, Simone + Piunno -- who is the Italian translation champion -- has written + up some nice instructions, which are provided below. In general you need to do two things to add translations for a language in Mailman. You need to translate the message catalog @@ -134,7 +136,7 @@ CURRENT LIST OF LANGUAGE SUPPORTED OUT-OF-THE BOX following languages out of the box: - Czech - - Chinese (Simplified and Traditional) + - Chinese (Simplified and Traditional, but may have problems) - Dutch - English - Estonian @@ -146,11 +148,11 @@ CURRENT LIST OF LANGUAGE SUPPORTED OUT-OF-THE BOX - Japanese - Korean - Lithuanian - - Spanish - - Swedish - Norwegian - Portuguese (Brazil) - Russian + - Spanish + - Swedish We've also had volunteers for these languages, although they aren't yet integrated into the code base: @@ -159,6 +161,76 @@ CURRENT LIST OF LANGUAGE SUPPORTED OUT-OF-THE BOX - Polish +MORE INSTRUCTIONS + + Here is the recipe that Simone Piunno used for the Italian + translations: + + "You can start without much technical knowledge, but if you want + to keep your translation up-to-date (while the development branch + evolves into the next stable release) you'd better learn how to + use cvs and diff. + + Here is my recipe. + + Basically, you'll start by copying templates/en/* to your sandbox dir + and then translating each file. Keep in mind that %(foo)s is a + variable reference (much like %s in C) and must be left untouched. + Also, you must be able to recognize a markup tag (eg, <foo>) because + they must be left untouched too, and you should know how to escape + non-ASCII characters, e.g. "è" -> "è", but only in html files. + Remember that if you need a literal % sign, it must be doubled: %% + + Next, you copy messages/mailman.pot, renaming it to serbian.po. + You can open this file with kbabel (a tool included in KDE SDK) and + translate each string (original on the higher half of the window, your + translation on the bottom half). + + If you are a masochist, you can even use emacs PO mode ;) + Keep attention to the same markers and escaping as above, with the added + complexity that here it's harder to say when a string is html (e.g. used + for web UI) or pure text (e.g used for email interface) + + Then you try to compile you .po file: + + msgfmt -v -o serbian.mo serbian.po + + No error messages should appear. + + Next, copy your files on an installed mailman tree, and run + bin/transcheck XX, where XX is your coutry code. + + No warning should appear (but maybe some warning is ok, if you really + know what you're doing). + + Now, try to run your translation (add an "add_language" line to + Mailman/Defaults.py) and check the many scattered pieces blend + together well. Sometimes you'll need some adjustment. + + When you're satistied, pack up a tar.gz with the following structure: + + messages/XX/LC_MESSAGES/mailman.po + messages/XX/LC_MESSAGES/mailman.mo + templates/XX/admindbdetails.html + templates/XX/admindbpreamble.html + . + . + templates/XX/userpass.txt + templates/XX/verify.txt + + (XX is your country code) and send it to Barry Warsaw. + + By that time, your translation could be somewhat obsolete, because + templates and mailman.pot could have been evolved meanwhile. + + Don't panic. + + You'll need to check diffs to find what changed and how, so that + you can easily update your files. + + Save everything everytime, you'll need it. + + Local Variables: mode: text diff --git a/README.POSTFIX b/README.POSTFIX index 00d66c34..f018f824 100644 --- a/README.POSTFIX +++ b/README.POSTFIX @@ -67,7 +67,8 @@ INTEGRATING POSTFIX AND MAILMAN - Look at the Defaults.py file for the variables POSTFIX_ALIAS_CMD and POSTFIX_MAP_CMD command. Make sure these point to your - postalias and postmap programs respectively. + postalias and postmap programs respectively. Remember that if + you need to make changes, do it in mm_cfg.py. - Run the genaliases script to initialize your aliases file. @@ -94,7 +94,7 @@ def main(): try: opts, args = getopt.getopt( sys.argv[1:], 'hs:e:q', - ['help', 'start', 'end', 'quiet', 'wipe']) + ['help', 'start=', 'end=', 'quiet', 'wipe']) except getopt.error, msg: usage(1, msg) diff --git a/messages/es/LC_MESSAGES/mailman.mo b/messages/es/LC_MESSAGES/mailman.mo Binary files differindex e6136917..5b3c7bca 100644 --- a/messages/es/LC_MESSAGES/mailman.mo +++ b/messages/es/LC_MESSAGES/mailman.mo diff --git a/messages/es/LC_MESSAGES/mailman.po b/messages/es/LC_MESSAGES/mailman.po index c4459e94..3c64575a 100644 --- a/messages/es/LC_MESSAGES/mailman.po +++ b/messages/es/LC_MESSAGES/mailman.po @@ -2195,7 +2195,7 @@ msgid "" " to find the management interface for your list.\n" " <p>Send questions or comments to " msgstr "" -"para acceder al interfaz de gestión de su lista.\n" +" para acceder al interfaz de gestión de su lista.\n" " <p>Envíe sus preguntas o comentarios a " #: Mailman/Cgi/listinfo.py:189 |